feat: config setting to automatically set members/groups to private when creating
This commit is contained in:
parent
7c37726afb
commit
1ff6bb76cd
@ -23,6 +23,8 @@ public partial class CommandTree
|
|||||||
public static Command ConfigPing = new Command("config ping", "config ping <enable|disable>", "Changes your system's ping preferences");
|
public static Command ConfigPing = new Command("config ping", "config ping <enable|disable>", "Changes your system's ping preferences");
|
||||||
public static Command ConfigAutoproxyAccount = new Command("config autoproxy account", "autoproxy account [on|off]", "Toggles autoproxy globally for the current account");
|
public static Command ConfigAutoproxyAccount = new Command("config autoproxy account", "autoproxy account [on|off]", "Toggles autoproxy globally for the current account");
|
||||||
public static Command ConfigAutoproxyTimeout = new Command("config autoproxy timeout", "autoproxy timeout [<duration>|off|reset]", "Sets the latch timeout duration for your system");
|
public static Command ConfigAutoproxyTimeout = new Command("config autoproxy timeout", "autoproxy timeout [<duration>|off|reset]", "Sets the latch timeout duration for your system");
|
||||||
|
public static Command ConfigMemberDefaultPrivacy = new("config member private", "config member private [on|off]", "Sets whether member privacy is automatically set to private when creating a new member");
|
||||||
|
public static Command ConfigGroupDefaultPrivacy = new("config group private", "config group private [on|off]", "Sets whether group privacy is automatically set to private when creating a new group");
|
||||||
public static Command AutoproxySet = new Command("autoproxy", "autoproxy [off|front|latch|member]", "Sets your system's autoproxy mode for the current server");
|
public static Command AutoproxySet = new Command("autoproxy", "autoproxy [off|front|latch|member]", "Sets your system's autoproxy mode for the current server");
|
||||||
public static Command MemberInfo = new Command("member", "member <member>", "Looks up information about a member");
|
public static Command MemberInfo = new Command("member", "member <member>", "Looks up information about a member");
|
||||||
public static Command MemberNew = new Command("member new", "member new <name>", "Creates a new member");
|
public static Command MemberNew = new Command("member new", "member new <name>", "Creates a new member");
|
||||||
@ -125,7 +127,8 @@ public partial class CommandTree
|
|||||||
|
|
||||||
public static Command[] ConfigCommands =
|
public static Command[] ConfigCommands =
|
||||||
{
|
{
|
||||||
ConfigTimezone, ConfigPing, ConfigAutoproxyAccount, ConfigAutoproxyTimeout
|
ConfigTimezone, ConfigPing, ConfigAutoproxyAccount, ConfigAutoproxyTimeout,
|
||||||
|
ConfigMemberDefaultPrivacy, ConfigGroupDefaultPrivacy
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Command[] LogCommands = { LogChannel, LogChannelClear, LogEnable, LogDisable };
|
public static Command[] LogCommands = { LogChannel, LogChannelClear, LogEnable, LogDisable };
|
||||||
|
@ -481,6 +481,10 @@ public partial class CommandTree
|
|||||||
return ctx.Execute<Config>(null, m => m.SystemTimezone(ctx));
|
return ctx.Execute<Config>(null, m => m.SystemTimezone(ctx));
|
||||||
if (ctx.Match("ping"))
|
if (ctx.Match("ping"))
|
||||||
return ctx.Execute<Config>(null, m => m.SystemPing(ctx));
|
return ctx.Execute<Config>(null, m => m.SystemPing(ctx));
|
||||||
|
if (ctx.MatchMultiple(new[] { "private member" }) || ctx.Match("mp"))
|
||||||
|
return ctx.Execute<Config>(null, m => m.MemberDefaultPrivacy(ctx));
|
||||||
|
if (ctx.MatchMultiple(new[] { "private group" }) || ctx.Match("gp"))
|
||||||
|
return ctx.Execute<Config>(null, m => m.GroupDefaultPrivacy(ctx));
|
||||||
|
|
||||||
// todo: maybe add the list of configuration keys here?
|
// todo: maybe add the list of configuration keys here?
|
||||||
return ctx.Reply($"{Emojis.Error} Could not find a setting with that name. Please see `pk;commands config` for the list of possible config settings.");
|
return ctx.Reply($"{Emojis.Error} Could not find a setting with that name. Please see `pk;commands config` for the list of possible config settings.");
|
||||||
@ -492,7 +496,6 @@ public partial class CommandTree
|
|||||||
await ctx.Reply(
|
await ctx.Reply(
|
||||||
$"{Emojis.Error} Unknown command `pk;{ctx.FullCommand().Truncate(100)}`. Perhaps you meant to use one of the following commands?\n{commandListStr}\n\nFor a full list of possible commands, see <https://pluralkit.me/commands>.");
|
$"{Emojis.Error} Unknown command `pk;{ctx.FullCommand().Truncate(100)}`. Perhaps you meant to use one of the following commands?\n{commandListStr}\n\nFor a full list of possible commands, see <https://pluralkit.me/commands>.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PrintCommandExpectedError(Context ctx, params Command[] potentialCommands)
|
private async Task PrintCommandExpectedError(Context ctx, params Command[] potentialCommands)
|
||||||
{
|
{
|
||||||
var commandListStr = CreatePotentialCommandList(potentialCommands);
|
var commandListStr = CreatePotentialCommandList(potentialCommands);
|
||||||
|
@ -58,6 +58,20 @@ public class Config
|
|||||||
"enabled"
|
"enabled"
|
||||||
));
|
));
|
||||||
|
|
||||||
|
items.Add(new(
|
||||||
|
"private member",
|
||||||
|
"Whether member privacy is automatically set to private for new members",
|
||||||
|
EnabledDisabled(ctx.Config.MemberDefaultPrivate),
|
||||||
|
"disabled"
|
||||||
|
));
|
||||||
|
|
||||||
|
items.Add(new(
|
||||||
|
"private group",
|
||||||
|
"Whether group privacy is automatically set to private for new groups",
|
||||||
|
EnabledDisabled(ctx.Config.GroupDefaultPrivate),
|
||||||
|
"disabled"
|
||||||
|
));
|
||||||
|
|
||||||
items.Add(new(
|
items.Add(new(
|
||||||
"Member limit",
|
"Member limit",
|
||||||
"The maximum number of registered members for your system",
|
"The maximum number of registered members for your system",
|
||||||
@ -298,4 +312,56 @@ public class Config
|
|||||||
return $"**{z.Id}**";
|
return $"**{z.Id}**";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task MemberDefaultPrivacy(Context ctx)
|
||||||
|
{
|
||||||
|
ctx.CheckSystem();
|
||||||
|
|
||||||
|
if (!ctx.HasNext())
|
||||||
|
{
|
||||||
|
if (ctx.Config.MemberDefaultPrivate) { await ctx.Reply("Newly created members will currently have their privacy settings set to private. To change this, type `pk;config private member off`"); }
|
||||||
|
else { await ctx.Reply("Newly created members will currently have their privacy settings set to public. To automatically set new members' privacy settings to private, type `pk;config private member on`"); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ctx.Match("on", "enable"))
|
||||||
|
{
|
||||||
|
await _repo.UpdateSystemConfig(ctx.System.Id, new() { MemberDefaultPrivate = true });
|
||||||
|
|
||||||
|
await ctx.Reply("Newly created members will now have their privacy settings set to private.");
|
||||||
|
}
|
||||||
|
if (ctx.Match("off", "disable"))
|
||||||
|
{
|
||||||
|
await _repo.UpdateSystemConfig(ctx.System.Id, new() { MemberDefaultPrivate = false });
|
||||||
|
|
||||||
|
await ctx.Reply("Newly created members will now have their privacy settings set to public.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task GroupDefaultPrivacy(Context ctx)
|
||||||
|
{
|
||||||
|
ctx.CheckSystem();
|
||||||
|
|
||||||
|
if (!ctx.HasNext())
|
||||||
|
{
|
||||||
|
if (ctx.Config.MemberDefaultPrivate) { await ctx.Reply("Newly created groups will currently have their privacy settings set to private. To change this, type `pk;config private group off`"); }
|
||||||
|
else { await ctx.Reply("Newly created groups will currently have their privacy settings set to public. To automatically set new groups' privacy settings to private, type `pk;config private group on`"); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ctx.Match("on", "enable"))
|
||||||
|
{
|
||||||
|
await _repo.UpdateSystemConfig(ctx.System.Id, new() { GroupDefaultPrivate = true });
|
||||||
|
|
||||||
|
await ctx.Reply("Newly created groups will now have their privacy settings set to private.");
|
||||||
|
}
|
||||||
|
if (ctx.Match("off", "disable"))
|
||||||
|
{
|
||||||
|
await _repo.UpdateSystemConfig(ctx.System.Id, new() { GroupDefaultPrivate = false });
|
||||||
|
|
||||||
|
await ctx.Reply("Newly created groups will now have their privacy settings set to public.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -64,14 +64,24 @@ public class Groups
|
|||||||
throw new PKError("Group creation cancelled.");
|
throw new PKError("Group creation cancelled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using var conn = await _db.Obtain();
|
||||||
var newGroup = await _repo.CreateGroup(ctx.System.Id, groupName);
|
var newGroup = await _repo.CreateGroup(ctx.System.Id, groupName);
|
||||||
|
|
||||||
_ = _dispatch.Dispatch(newGroup.Id,
|
var dispatchData = new JObject();
|
||||||
new UpdateDispatchData
|
dispatchData.Add("name", groupName);
|
||||||
{
|
|
||||||
Event = DispatchEvent.CREATE_GROUP,
|
if (ctx.Config.GroupDefaultPrivate)
|
||||||
EventData = JObject.FromObject(new { name = groupName })
|
{
|
||||||
});
|
var patch = new GroupPatch().WithAllPrivacy(PrivacyLevel.Private);
|
||||||
|
await _repo.UpdateGroup(newGroup.Id, patch, conn);
|
||||||
|
dispatchData.Merge(patch.ToJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = _dispatch.Dispatch(newGroup.Id, new UpdateDispatchData
|
||||||
|
{
|
||||||
|
Event = DispatchEvent.CREATE_GROUP,
|
||||||
|
EventData = dispatchData
|
||||||
|
});
|
||||||
|
|
||||||
var eb = new EmbedBuilder()
|
var eb = new EmbedBuilder()
|
||||||
.Description(
|
.Description(
|
||||||
|
@ -55,13 +55,22 @@ public class Member
|
|||||||
throw Errors.MemberLimitReachedError(memberLimit);
|
throw Errors.MemberLimitReachedError(memberLimit);
|
||||||
|
|
||||||
// Create the member
|
// Create the member
|
||||||
var member = await _repo.CreateMember(ctx.System.Id, memberName);
|
var member = await _repo.CreateMember(ctx.System.Id, memberName, conn);
|
||||||
memberCount++;
|
memberCount++;
|
||||||
|
|
||||||
|
JObject dispatchData = new JObject();
|
||||||
|
dispatchData.Add("name", memberName);
|
||||||
|
|
||||||
|
if (ctx.Config.MemberDefaultPrivate)
|
||||||
|
{
|
||||||
|
var patch = new MemberPatch().WithAllPrivacy(PrivacyLevel.Private);
|
||||||
|
await _repo.UpdateMember(member.Id, patch, conn);
|
||||||
|
dispatchData.Merge(patch.ToJson());
|
||||||
|
}
|
||||||
|
|
||||||
// Try to match an image attached to the message
|
// Try to match an image attached to the message
|
||||||
var avatarArg = ctx.Message.Attachments.FirstOrDefault();
|
var avatarArg = ctx.Message.Attachments.FirstOrDefault();
|
||||||
Exception imageMatchError = null;
|
Exception imageMatchError = null;
|
||||||
var sentDispatch = false;
|
|
||||||
if (avatarArg != null)
|
if (avatarArg != null)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -69,31 +78,25 @@ public class Member
|
|||||||
await _db.Execute(conn =>
|
await _db.Execute(conn =>
|
||||||
_repo.UpdateMember(member.Id, new MemberPatch { AvatarUrl = avatarArg.Url }, conn));
|
_repo.UpdateMember(member.Id, new MemberPatch { AvatarUrl = avatarArg.Url }, conn));
|
||||||
|
|
||||||
_ = _dispatch.Dispatch(member.Id, new UpdateDispatchData
|
dispatchData.Add("avatar_url", avatarArg.Url);
|
||||||
{
|
|
||||||
Event = DispatchEvent.CREATE_MEMBER,
|
|
||||||
EventData = JObject.FromObject(new { name = memberName, avatar_url = avatarArg.Url }),
|
|
||||||
});
|
|
||||||
sentDispatch = true;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
imageMatchError = e;
|
imageMatchError = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sentDispatch)
|
_ = _dispatch.Dispatch(member.Id, new UpdateDispatchData
|
||||||
_ = _dispatch.Dispatch(member.Id, new UpdateDispatchData
|
{
|
||||||
{
|
Event = DispatchEvent.CREATE_MEMBER,
|
||||||
Event = DispatchEvent.CREATE_MEMBER,
|
EventData = dispatchData,
|
||||||
EventData = JObject.FromObject(new { name = memberName }),
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Send confirmation and space hint
|
// Send confirmation and space hint
|
||||||
await ctx.Reply(
|
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");
|
$"{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
|
// todo: move this to ModelRepository
|
||||||
if (await _db.Execute(conn => conn.QuerySingleAsync<bool>("select has_private_members(@System)",
|
if (await _db.Execute(conn => conn.QuerySingleAsync<bool>("select has_private_members(@System)",
|
||||||
new { System = ctx.System.Id }))) //if has private members
|
new { System = ctx.System.Id })) && !ctx.Config.MemberDefaultPrivate) //if has private members
|
||||||
await ctx.Reply(
|
await ctx.Reply(
|
||||||
$"{Emojis.Warn} This member is currently **public**. To change this, use `pk;member {member.Hid} private`.");
|
$"{Emojis.Warn} This member is currently **public**. To change this, use `pk;member {member.Hid} private`.");
|
||||||
if (avatarArg != null)
|
if (avatarArg != null)
|
||||||
|
7
PluralKit.Core/Database/Migrations/22.sql
Normal file
7
PluralKit.Core/Database/Migrations/22.sql
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
-- schema version 22
|
||||||
|
-- automatically set members/groups as private when creating
|
||||||
|
|
||||||
|
alter table system_config add column member_default_private bool not null default false;
|
||||||
|
alter table system_config add column group_default_private bool not null default false;
|
||||||
|
|
||||||
|
update info set schema_version = 22;
|
@ -9,7 +9,7 @@ namespace PluralKit.Core;
|
|||||||
internal class DatabaseMigrator
|
internal class DatabaseMigrator
|
||||||
{
|
{
|
||||||
private const string RootPath = "PluralKit.Core.Database"; // "resource path" root for SQL files
|
private const string RootPath = "PluralKit.Core.Database"; // "resource path" root for SQL files
|
||||||
private const int TargetSchemaVersion = 21;
|
private const int TargetSchemaVersion = 22;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public DatabaseMigrator(ILogger logger)
|
public DatabaseMigrator(ILogger logger)
|
||||||
|
@ -11,6 +11,8 @@ public class SystemConfigPatch: PatchObject
|
|||||||
public Partial<string> UiTz { get; set; }
|
public Partial<string> UiTz { get; set; }
|
||||||
public Partial<bool> PingsEnabled { get; set; }
|
public Partial<bool> PingsEnabled { get; set; }
|
||||||
public Partial<int?> LatchTimeout { get; set; }
|
public Partial<int?> LatchTimeout { get; set; }
|
||||||
|
public Partial<bool> MemberDefaultPrivate { get; set; }
|
||||||
|
public Partial<bool> GroupDefaultPrivate { get; set; }
|
||||||
public Partial<int?> MemberLimitOverride { get; set; }
|
public Partial<int?> MemberLimitOverride { get; set; }
|
||||||
public Partial<int?> GroupLimitOverride { get; set; }
|
public Partial<int?> GroupLimitOverride { get; set; }
|
||||||
|
|
||||||
@ -18,6 +20,8 @@ public class SystemConfigPatch: PatchObject
|
|||||||
.With("ui_tz", UiTz)
|
.With("ui_tz", UiTz)
|
||||||
.With("pings_enabled", PingsEnabled)
|
.With("pings_enabled", PingsEnabled)
|
||||||
.With("latch_timeout", LatchTimeout)
|
.With("latch_timeout", LatchTimeout)
|
||||||
|
.With("member_default_private", MemberDefaultPrivate)
|
||||||
|
.With("group_default_private", GroupDefaultPrivate)
|
||||||
.With("member_limit_override", MemberLimitOverride)
|
.With("member_limit_override", MemberLimitOverride)
|
||||||
.With("group_limit_override", GroupLimitOverride)
|
.With("group_limit_override", GroupLimitOverride)
|
||||||
);
|
);
|
||||||
@ -41,6 +45,12 @@ public class SystemConfigPatch: PatchObject
|
|||||||
if (LatchTimeout.IsPresent)
|
if (LatchTimeout.IsPresent)
|
||||||
o.Add("latch_timeout", LatchTimeout.Value);
|
o.Add("latch_timeout", LatchTimeout.Value);
|
||||||
|
|
||||||
|
if (MemberDefaultPrivate.IsPresent)
|
||||||
|
o.Add("member_default_private", MemberDefaultPrivate.Value);
|
||||||
|
|
||||||
|
if (GroupDefaultPrivate.IsPresent)
|
||||||
|
o.Add("group_default_private", GroupDefaultPrivate.Value);
|
||||||
|
|
||||||
if (MemberLimitOverride.IsPresent)
|
if (MemberLimitOverride.IsPresent)
|
||||||
o.Add("member_limit", MemberLimitOverride.Value);
|
o.Add("member_limit", MemberLimitOverride.Value);
|
||||||
|
|
||||||
@ -63,6 +73,12 @@ public class SystemConfigPatch: PatchObject
|
|||||||
if (o.ContainsKey("latch_timeout"))
|
if (o.ContainsKey("latch_timeout"))
|
||||||
patch.LatchTimeout = o.Value<int>("latch_timeout");
|
patch.LatchTimeout = o.Value<int>("latch_timeout");
|
||||||
|
|
||||||
|
if (o.ContainsKey("member_default_private"))
|
||||||
|
patch.MemberDefaultPrivate = o.Value<bool>("member_default_private");
|
||||||
|
|
||||||
|
if (o.ContainsKey("group_default_private"))
|
||||||
|
patch.GroupDefaultPrivate = o.Value<bool>("group_default_private");
|
||||||
|
|
||||||
return patch;
|
return patch;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,6 +10,8 @@ public class SystemConfig
|
|||||||
public string UiTz { get; set; }
|
public string UiTz { get; set; }
|
||||||
public bool PingsEnabled { get; }
|
public bool PingsEnabled { get; }
|
||||||
public int? LatchTimeout { get; }
|
public int? LatchTimeout { get; }
|
||||||
|
public bool MemberDefaultPrivate { get; }
|
||||||
|
public bool GroupDefaultPrivate { get; }
|
||||||
public int? MemberLimitOverride { get; }
|
public int? MemberLimitOverride { get; }
|
||||||
public int? GroupLimitOverride { get; }
|
public int? GroupLimitOverride { get; }
|
||||||
|
|
||||||
@ -25,6 +27,8 @@ public static class SystemConfigExt
|
|||||||
o.Add("timezone", cfg.UiTz);
|
o.Add("timezone", cfg.UiTz);
|
||||||
o.Add("pings_enabled", cfg.PingsEnabled);
|
o.Add("pings_enabled", cfg.PingsEnabled);
|
||||||
o.Add("latch_timeout", cfg.LatchTimeout);
|
o.Add("latch_timeout", cfg.LatchTimeout);
|
||||||
|
o.Add("member_default_private", cfg.MemberDefaultPrivate);
|
||||||
|
o.Add("group_default_private", cfg.GroupDefaultPrivate);
|
||||||
o.Add("member_limit", cfg.MemberLimitOverride ?? Limits.MaxMemberCount);
|
o.Add("member_limit", cfg.MemberLimitOverride ?? Limits.MaxMemberCount);
|
||||||
o.Add("group_limit", cfg.GroupLimitOverride ?? Limits.MaxGroupCount);
|
o.Add("group_limit", cfg.GroupLimitOverride ?? Limits.MaxGroupCount);
|
||||||
|
|
||||||
|
@ -106,9 +106,13 @@ Every PluralKit entity has two IDs: a short (5-character) ID and a longer UUID.
|
|||||||
|timezone|string|defaults to `UTC`|
|
|timezone|string|defaults to `UTC`|
|
||||||
|pings_enabled|boolean|
|
|pings_enabled|boolean|
|
||||||
|latch_timeout|int?|
|
|latch_timeout|int?|
|
||||||
|
|member_default_private*|bool|whether members created through the bot have privacy settings set to private by default|
|
||||||
|
|group_default_private*|bool|whether groups created through the bot have privacy settings set to private by default|
|
||||||
|member_limit|int|read-only, defaults to 1000|
|
|member_limit|int|read-only, defaults to 1000|
|
||||||
|group_limit|int|read-only, defaults to 250|
|
|group_limit|int|read-only, defaults to 250|
|
||||||
|
|
||||||
|
\* this *does not* affect members/groups created through the API - please specify privacy keys in the JSON payload instead
|
||||||
|
|
||||||
### System guild settings model
|
### System guild settings model
|
||||||
|
|
||||||
|key|type|notes|
|
|key|type|notes|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user