Move system updates to the same patch system as members
This commit is contained in:
		| @@ -26,18 +26,20 @@ namespace PluralKit.API | |||||||
|             return o; |             return o; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public static void ApplyJson(this PKSystem system, JObject o) |         public static SystemPatch ToSystemPatch(JObject o) | ||||||
|         { |         { | ||||||
|             if (o.ContainsKey("name")) system.Name = o.Value<string>("name").NullIfEmpty().BoundsCheckField(Limits.MaxSystemNameLength, "System name"); |             var patch = new SystemPatch(); | ||||||
|             if (o.ContainsKey("description")) system.Description = o.Value<string>("description").NullIfEmpty().BoundsCheckField(Limits.MaxDescriptionLength, "System description"); |             if (o.ContainsKey("name")) patch.Name = o.Value<string>("name").NullIfEmpty().BoundsCheckField(Limits.MaxSystemNameLength, "System name"); | ||||||
|             if (o.ContainsKey("tag")) system.Tag = o.Value<string>("tag").NullIfEmpty().BoundsCheckField(Limits.MaxSystemTagLength, "System tag"); |             if (o.ContainsKey("description")) patch.Description = o.Value<string>("description").NullIfEmpty().BoundsCheckField(Limits.MaxDescriptionLength, "System description"); | ||||||
|             if (o.ContainsKey("avatar_url")) system.AvatarUrl = o.Value<string>("avatar_url").NullIfEmpty().BoundsCheckField(Limits.MaxUriLength, "System avatar URL"); |             if (o.ContainsKey("tag")) patch.Tag = o.Value<string>("tag").NullIfEmpty().BoundsCheckField(Limits.MaxSystemTagLength, "System tag"); | ||||||
|             if (o.ContainsKey("tz")) system.UiTz = o.Value<string>("tz") ?? "UTC"; |             if (o.ContainsKey("avatar_url")) patch.AvatarUrl = o.Value<string>("avatar_url").NullIfEmpty().BoundsCheckField(Limits.MaxUriLength, "System avatar URL"); | ||||||
|  |             if (o.ContainsKey("tz")) patch.UiTz = o.Value<string>("tz") ?? "UTC"; | ||||||
|              |              | ||||||
|             if (o.ContainsKey("description_privacy")) system.DescriptionPrivacy = o.Value<string>("description_privacy").ParsePrivacy("description"); |             if (o.ContainsKey("description_privacy")) patch.DescriptionPrivacy = o.Value<string>("description_privacy").ParsePrivacy("description"); | ||||||
|             if (o.ContainsKey("member_list_privacy")) system.MemberListPrivacy = o.Value<string>("member_list_privacy").ParsePrivacy("member list"); |             if (o.ContainsKey("member_list_privacy")) patch.MemberListPrivacy = o.Value<string>("member_list_privacy").ParsePrivacy("member list"); | ||||||
|             if (o.ContainsKey("front_privacy")) system.FrontPrivacy = o.Value<string>("front_privacy").ParsePrivacy("front"); |             if (o.ContainsKey("front_privacy")) patch.FrontPrivacy = o.Value<string>("front_privacy").ParsePrivacy("front"); | ||||||
|             if (o.ContainsKey("front_history_privacy")) system.FrontHistoryPrivacy = o.Value<string>("front_history_privacy").ParsePrivacy("front history"); |             if (o.ContainsKey("front_history_privacy")) patch.FrontHistoryPrivacy = o.Value<string>("front_history_privacy").ParsePrivacy("front history"); | ||||||
|  |             return patch; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         public static JObject ToJson(this PKMember member, LookupContext ctx) |         public static JObject ToJson(this PKMember member, LookupContext ctx) | ||||||
|   | |||||||
| @@ -41,13 +41,13 @@ namespace PluralKit.API | |||||||
|     public class SystemController : ControllerBase |     public class SystemController : ControllerBase | ||||||
|     { |     { | ||||||
|         private IDataStore _data; |         private IDataStore _data; | ||||||
|         private IDatabase _conn; |         private IDatabase _db; | ||||||
|         private IAuthorizationService _auth; |         private IAuthorizationService _auth; | ||||||
|  |  | ||||||
|         public SystemController(IDataStore data, IDatabase conn, IAuthorizationService auth) |         public SystemController(IDataStore data, IDatabase db, IAuthorizationService auth) | ||||||
|         { |         { | ||||||
|             _data = data; |             _data = data; | ||||||
|             _conn = conn; |             _db = db; | ||||||
|             _auth = auth; |             _auth = auth; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -55,7 +55,7 @@ namespace PluralKit.API | |||||||
|         [Authorize] |         [Authorize] | ||||||
|         public async Task<ActionResult<JObject>> GetOwnSystem() |         public async Task<ActionResult<JObject>> GetOwnSystem() | ||||||
|         { |         { | ||||||
|             var system = await _conn.Execute(c => c.QuerySystem(User.CurrentSystem())); |             var system = await _db.Execute(c => c.QuerySystem(User.CurrentSystem())); | ||||||
|             return system.ToJson(User.ContextFor(system)); |             return system.ToJson(User.ContextFor(system)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -94,7 +94,7 @@ namespace PluralKit.API | |||||||
|             var auth = await _auth.AuthorizeAsync(User, system, "ViewFrontHistory"); |             var auth = await _auth.AuthorizeAsync(User, system, "ViewFrontHistory"); | ||||||
|             if (!auth.Succeeded) return StatusCode(StatusCodes.Status403Forbidden, "Unauthorized to view front history."); |             if (!auth.Succeeded) return StatusCode(StatusCodes.Status403Forbidden, "Unauthorized to view front history."); | ||||||
|  |  | ||||||
|             using (var conn = await _conn.Obtain()) |             using (var conn = await _db.Obtain()) | ||||||
|             { |             { | ||||||
|                 var res = await conn.QueryAsync<SwitchesReturn>( |                 var res = await conn.QueryAsync<SwitchesReturn>( | ||||||
|                     @"select *, array( |                     @"select *, array( | ||||||
| @@ -132,17 +132,19 @@ namespace PluralKit.API | |||||||
|         [Authorize] |         [Authorize] | ||||||
|         public async Task<ActionResult<JObject>> EditSystem([FromBody] JObject changes) |         public async Task<ActionResult<JObject>> EditSystem([FromBody] JObject changes) | ||||||
|         { |         { | ||||||
|             var system = await _conn.Execute(c => c.QuerySystem(User.CurrentSystem())); |             var system = await _db.Execute(c => c.QuerySystem(User.CurrentSystem())); | ||||||
|  |  | ||||||
|  |             SystemPatch patch; | ||||||
|             try |             try | ||||||
|             { |             { | ||||||
|                 system.ApplyJson(changes); |                 patch = JsonModelExt.ToSystemPatch(changes);  | ||||||
|             } |             } | ||||||
|             catch (JsonModelParseError e) |             catch (JsonModelParseError e) | ||||||
|             { |             { | ||||||
|                 return BadRequest(e.Message); |                 return BadRequest(e.Message); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             await _data.SaveSystem(system); |             await _db.Execute(conn => conn.UpdateSystem(system.Id, patch)); | ||||||
|             return Ok(system.ToJson(User.ContextFor(system))); |             return Ok(system.ToJson(User.ContextFor(system))); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -166,7 +168,7 @@ namespace PluralKit.API | |||||||
|  |  | ||||||
|             // Resolve member objects for all given IDs |             // Resolve member objects for all given IDs | ||||||
|             IEnumerable<PKMember> membersList; |             IEnumerable<PKMember> membersList; | ||||||
|             using (var conn = await _conn.Obtain()) |             using (var conn = await _db.Obtain()) | ||||||
|                 membersList = (await conn.QueryAsync<PKMember>("select * from members where hid = any(@Hids)", new {Hids = param.Members})).ToList(); |                 membersList = (await conn.QueryAsync<PKMember>("select * from members where hid = any(@Hids)", new {Hids = param.Members})).ToList(); | ||||||
|              |              | ||||||
|             foreach (var member in membersList) |             foreach (var member in membersList) | ||||||
|   | |||||||
| @@ -34,8 +34,9 @@ namespace PluralKit.Bot | |||||||
|  |  | ||||||
|             if (ctx.MatchFlag("c", "clear") || ctx.Match("clear")) |             if (ctx.MatchFlag("c", "clear") || ctx.Match("clear")) | ||||||
|             { |             { | ||||||
|                 ctx.System.Name = null; |                 var clearPatch = new SystemPatch {Name = null}; | ||||||
|                 await _data.SaveSystem(ctx.System); |                 await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, clearPatch)); | ||||||
|  |  | ||||||
|                 await ctx.Reply($"{Emojis.Success} System name cleared."); |                 await ctx.Reply($"{Emojis.Success} System name cleared."); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| @@ -50,9 +51,12 @@ namespace PluralKit.Bot | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             if (newSystemName != null && newSystemName.Length > Limits.MaxSystemNameLength) throw Errors.SystemNameTooLongError(newSystemName.Length); |             if (newSystemName != null && newSystemName.Length > Limits.MaxSystemNameLength) | ||||||
|             ctx.System.Name = newSystemName; |                 throw Errors.SystemNameTooLongError(newSystemName.Length); | ||||||
|             await _data.SaveSystem(ctx.System); |              | ||||||
|  |             var patch = new SystemPatch {Name = newSystemName}; | ||||||
|  |             await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |              | ||||||
|             await ctx.Reply($"{Emojis.Success} System name changed."); |             await ctx.Reply($"{Emojis.Success} System name changed."); | ||||||
|         } |         } | ||||||
|          |          | ||||||
| @@ -61,8 +65,9 @@ namespace PluralKit.Bot | |||||||
|  |  | ||||||
|             if (ctx.MatchFlag("c", "clear") || ctx.Match("clear")) |             if (ctx.MatchFlag("c", "clear") || ctx.Match("clear")) | ||||||
|             { |             { | ||||||
|                 ctx.System.Description = null; |                 var patch = new SystemPatch {Description = null}; | ||||||
|                 await _data.SaveSystem(ctx.System); |                 await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |                  | ||||||
|                 await ctx.Reply($"{Emojis.Success} System description cleared."); |                 await ctx.Reply($"{Emojis.Success} System description cleared."); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| @@ -84,8 +89,10 @@ namespace PluralKit.Bot | |||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 if (newDescription.Length > Limits.MaxDescriptionLength) throw Errors.DescriptionTooLongError(newDescription.Length); |                 if (newDescription.Length > Limits.MaxDescriptionLength) throw Errors.DescriptionTooLongError(newDescription.Length); | ||||||
|                 ctx.System.Description = newDescription; |                  | ||||||
|                 await _data.SaveSystem(ctx.System); |                 var patch = new SystemPatch {Description = newDescription}; | ||||||
|  |                 await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |                  | ||||||
|                 await ctx.Reply($"{Emojis.Success} System description changed."); |                 await ctx.Reply($"{Emojis.Success} System description changed."); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -96,8 +103,9 @@ namespace PluralKit.Bot | |||||||
|  |  | ||||||
|             if (ctx.MatchFlag("c", "clear") || ctx.Match("clear")) |             if (ctx.MatchFlag("c", "clear") || ctx.Match("clear")) | ||||||
|             { |             { | ||||||
|                 ctx.System.Tag = null; |                 var patch = new SystemPatch {Tag = null}; | ||||||
|                 await _data.SaveSystem(ctx.System); |                 await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |                  | ||||||
|                 await ctx.Reply($"{Emojis.Success} System tag cleared."); |                 await ctx.Reply($"{Emojis.Success} System tag cleared."); | ||||||
|             } else if (!ctx.HasNext(skipFlags: false)) |             } else if (!ctx.HasNext(skipFlags: false)) | ||||||
|             { |             { | ||||||
| @@ -112,8 +120,10 @@ namespace PluralKit.Bot | |||||||
|                 if (newTag != null) |                 if (newTag != null) | ||||||
|                     if (newTag.Length > Limits.MaxSystemTagLength) |                     if (newTag.Length > Limits.MaxSystemTagLength) | ||||||
|                         throw Errors.SystemNameTooLongError(newTag.Length); |                         throw Errors.SystemNameTooLongError(newTag.Length); | ||||||
|                 ctx.System.Tag = newTag; |                  | ||||||
|                 await _data.SaveSystem(ctx.System); |                 var patch = new SystemPatch {Tag = newTag}; | ||||||
|  |                 await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |                  | ||||||
|                 await ctx.Reply($"{Emojis.Success} System tag changed. Member names will now end with `{newTag}` when proxied."); |                 await ctx.Reply($"{Emojis.Success} System tag changed. Member names will now end with `{newTag}` when proxied."); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -124,8 +134,9 @@ namespace PluralKit.Bot | |||||||
|              |              | ||||||
|             if (ctx.Match("clear") || ctx.MatchFlag("c", "clear")) |             if (ctx.Match("clear") || ctx.MatchFlag("c", "clear")) | ||||||
|             { |             { | ||||||
|                 ctx.System.AvatarUrl = null; |                 var patch = new SystemPatch {AvatarUrl = null}; | ||||||
|                 await _data.SaveSystem(ctx.System); |                 await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |                  | ||||||
|                 await ctx.Reply($"{Emojis.Success} System avatar cleared."); |                 await ctx.Reply($"{Emojis.Success} System avatar cleared."); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| @@ -149,10 +160,12 @@ namespace PluralKit.Bot | |||||||
|             if (member != null) |             if (member != null) | ||||||
|             { |             { | ||||||
|                 if (member.AvatarHash == null) throw Errors.UserHasNoAvatar; |                 if (member.AvatarHash == null) throw Errors.UserHasNoAvatar; | ||||||
|                 ctx.System.AvatarUrl = member.GetAvatarUrl(ImageFormat.Png, size: 256); |  | ||||||
|                 await _data.SaveSystem(ctx.System); |  | ||||||
|  |  | ||||||
|                 var embed = new DiscordEmbedBuilder().WithImageUrl(ctx.System.AvatarUrl).Build(); |                 var newUrl = member.GetAvatarUrl(ImageFormat.Png, size: 256); | ||||||
|  |                 var patch = new SystemPatch {AvatarUrl = newUrl}; | ||||||
|  |                 await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |                  | ||||||
|  |                 var embed = new DiscordEmbedBuilder().WithImageUrl(newUrl).Build(); | ||||||
|                 await ctx.Reply( |                 await ctx.Reply( | ||||||
|                     $"{Emojis.Success} System avatar changed to {member.Username}'s avatar! {Emojis.Warn} Please note that if {member.Username} changes their avatar, the system's avatar will need to be re-set.", embed: embed); |                     $"{Emojis.Success} System avatar changed to {member.Username}'s avatar! {Emojis.Warn} Please note that if {member.Username} changes their avatar, the system's avatar will need to be re-set.", embed: embed); | ||||||
|             } |             } | ||||||
| @@ -163,8 +176,8 @@ namespace PluralKit.Bot | |||||||
|                 if (url?.Length > Limits.MaxUriLength) throw Errors.InvalidUrl(url); |                 if (url?.Length > Limits.MaxUriLength) throw Errors.InvalidUrl(url); | ||||||
|                 await ctx.BusyIndicator(() => AvatarUtils.VerifyAvatarOrThrow(url)); |                 await ctx.BusyIndicator(() => AvatarUtils.VerifyAvatarOrThrow(url)); | ||||||
|  |  | ||||||
|                 ctx.System.AvatarUrl = url; |                 var patch = new SystemPatch {AvatarUrl = url}; | ||||||
|                 await _data.SaveSystem(ctx.System); |                 await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |  | ||||||
|                 var embed = url != null ? new DiscordEmbedBuilder().WithImageUrl(url).Build() : null; |                 var embed = url != null ? new DiscordEmbedBuilder().WithImageUrl(url).Build() : null; | ||||||
|                 await ctx.Reply($"{Emojis.Success} System avatar changed.", embed: embed); |                 await ctx.Reply($"{Emojis.Success} System avatar changed.", embed: embed); | ||||||
| @@ -178,7 +191,8 @@ namespace PluralKit.Bot | |||||||
|             if (!await ctx.ConfirmWithReply(ctx.System.Hid)) |             if (!await ctx.ConfirmWithReply(ctx.System.Hid)) | ||||||
|                 throw new PKError($"System deletion cancelled. Note that you must reply with your system ID (`{ctx.System.Hid}`) *verbatim*."); |                 throw new PKError($"System deletion cancelled. Note that you must reply with your system ID (`{ctx.System.Hid}`) *verbatim*."); | ||||||
|  |  | ||||||
|             await _data.DeleteSystem(ctx.System); |             await _db.Execute(conn => conn.DeleteSystem(ctx.System.Id)); | ||||||
|  |              | ||||||
|             await ctx.Reply($"{Emojis.Success} System deleted."); |             await ctx.Reply($"{Emojis.Success} System deleted."); | ||||||
|         } |         } | ||||||
|          |          | ||||||
| @@ -216,8 +230,9 @@ namespace PluralKit.Bot | |||||||
|  |  | ||||||
|             if (ctx.MatchFlag("c", "clear") || ctx.Match("clear")) |             if (ctx.MatchFlag("c", "clear") || ctx.Match("clear")) | ||||||
|             { |             { | ||||||
|                 ctx.System.UiTz = "UTC"; |                 var clearPatch = new SystemPatch {UiTz = "UTC"}; | ||||||
|                 await _data.SaveSystem(ctx.System); |                 await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, clearPatch)); | ||||||
|  |  | ||||||
|                 await ctx.Reply($"{Emojis.Success} System time zone cleared (set to UTC)."); |                 await ctx.Reply($"{Emojis.Success} System time zone cleared (set to UTC)."); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| @@ -237,8 +252,9 @@ namespace PluralKit.Bot | |||||||
|             var msg = await ctx.Reply( |             var msg = await ctx.Reply( | ||||||
|                 $"This will change the system time zone to **{zone.Id}**. The current time is **{currentTime.FormatZoned()}**. Is this correct?"); |                 $"This will change the system time zone to **{zone.Id}**. The current time is **{currentTime.FormatZoned()}**. Is this correct?"); | ||||||
|             if (!await ctx.PromptYesNo(msg)) throw Errors.TimezoneChangeCancelled; |             if (!await ctx.PromptYesNo(msg)) throw Errors.TimezoneChangeCancelled; | ||||||
|             ctx.System.UiTz = zone.Id; |              | ||||||
|             await _data.SaveSystem(ctx.System); |             var patch = new SystemPatch {UiTz = zone.Id}; | ||||||
|  |             await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |  | ||||||
|             await ctx.Reply($"System time zone changed to **{zone.Id}**."); |             await ctx.Reply($"System time zone changed to **{zone.Id}**."); | ||||||
|         } |         } | ||||||
| @@ -290,39 +306,41 @@ namespace PluralKit.Bot | |||||||
|  |  | ||||||
|             string levelStr, levelExplanation, subjectStr; |             string levelStr, levelExplanation, subjectStr; | ||||||
|             var subjectList = "`description`, `members`, `front`, `fronthistory`, or `all`"; |             var subjectList = "`description`, `members`, `front`, `fronthistory`, or `all`"; | ||||||
|  |              | ||||||
|  |             SystemPatch patch = new SystemPatch(); | ||||||
|             if (ctx.Match("description", "desc", "text", "info")) |             if (ctx.Match("description", "desc", "text", "info")) | ||||||
|             { |             { | ||||||
|                 subjectStr = "description"; |                 subjectStr = "description"; | ||||||
|                 ctx.System.DescriptionPrivacy = PopPrivacyLevel("description", out levelStr, out levelExplanation); |                 patch.DescriptionPrivacy = PopPrivacyLevel("description", out levelStr, out levelExplanation); | ||||||
|             }  |             }  | ||||||
|             else if (ctx.Match("members", "memberlist", "list", "mlist")) |             else if (ctx.Match("members", "memberlist", "list", "mlist")) | ||||||
|             { |             { | ||||||
|                 subjectStr = "member list"; |                 subjectStr = "member list"; | ||||||
|                 ctx.System.MemberListPrivacy = PopPrivacyLevel("members", out levelStr, out levelExplanation); |                 patch.MemberListPrivacy = PopPrivacyLevel("members", out levelStr, out levelExplanation); | ||||||
|             } |             } | ||||||
|             else if (ctx.Match("front", "fronter")) |             else if (ctx.Match("front", "fronter")) | ||||||
|             { |             { | ||||||
|                 subjectStr = "fronter(s)"; |                 subjectStr = "fronter(s)"; | ||||||
|                 ctx.System.FrontPrivacy = PopPrivacyLevel("front", out levelStr, out levelExplanation); |                 patch.FrontPrivacy = PopPrivacyLevel("front", out levelStr, out levelExplanation); | ||||||
|             }  |             }  | ||||||
|             else if (ctx.Match("switch", "switches", "fronthistory", "fh")) |             else if (ctx.Match("switch", "switches", "fronthistory", "fh")) | ||||||
|             { |             { | ||||||
|                 subjectStr = "front history"; |                 subjectStr = "front history"; | ||||||
|                 ctx.System.FrontHistoryPrivacy = PopPrivacyLevel("fronthistory", out levelStr, out levelExplanation); |                 patch.FrontHistoryPrivacy = PopPrivacyLevel("fronthistory", out levelStr, out levelExplanation); | ||||||
|             } |             } | ||||||
|             else if (ctx.Match("all")){ |             else if (ctx.Match("all")){ | ||||||
|                 subjectStr = "all"; |                 subjectStr = "all"; | ||||||
|                 PrivacyLevel level = PopPrivacyLevel("all", out levelStr, out levelExplanation); |                 PrivacyLevel level = PopPrivacyLevel("all", out levelStr, out levelExplanation); | ||||||
|                 ctx.System.DescriptionPrivacy = level; |                 patch.DescriptionPrivacy = level; | ||||||
|                 ctx.System.MemberListPrivacy = level; |                 patch.MemberListPrivacy = level; | ||||||
|                 ctx.System.FrontPrivacy = level; |                 patch.FrontPrivacy = level; | ||||||
|                 ctx.System.FrontHistoryPrivacy = level; |                 patch.FrontHistoryPrivacy = level; | ||||||
|  |  | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|                 throw new PKSyntaxError($"Invalid privacy subject `{ctx.PopArgument()}` (must be {subjectList})."); |                 throw new PKSyntaxError($"Invalid privacy subject `{ctx.PopArgument()}` (must be {subjectList})."); | ||||||
|  |  | ||||||
|             await _data.SaveSystem(ctx.System); |             await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|             if(subjectStr == "all"){ |             if(subjectStr == "all"){ | ||||||
|                 if(levelStr == "private") |                 if(levelStr == "private") | ||||||
|                     await ctx.Reply($"All of your systems privacy settings have been set to **{levelStr}**. Other accounts will now see nothing on the member card."); |                     await ctx.Reply($"All of your systems privacy settings have been set to **{levelStr}**. Other accounts will now see nothing on the member card."); | ||||||
| @@ -331,7 +349,7 @@ namespace PluralKit.Bot | |||||||
|             }  |             }  | ||||||
|             //Handle other subjects |             //Handle other subjects | ||||||
|             else |             else | ||||||
|             await ctx.Reply($"System {subjectStr} privacy has been set to **{levelStr}**. Other accounts will now {levelExplanation} your system {subjectStr}."); |                 await ctx.Reply($"System {subjectStr} privacy has been set to **{levelStr}**. Other accounts will now {levelExplanation} your system {subjectStr}."); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public async Task SystemPing(Context ctx)  |         public async Task SystemPing(Context ctx)  | ||||||
| @@ -345,13 +363,15 @@ namespace PluralKit.Bot | |||||||
| 	        } | 	        } | ||||||
|             else { |             else { | ||||||
|                 if (ctx.Match("on", "enable")) { |                 if (ctx.Match("on", "enable")) { | ||||||
|                     ctx.System.PingsEnabled = true; |                     var patch = new SystemPatch {PingsEnabled = true}; | ||||||
|                     await _data.SaveSystem(ctx.System); |                     await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |                      | ||||||
|                     await ctx.Reply("Reaction pings have now been enabled."); |                     await ctx.Reply("Reaction pings have now been enabled."); | ||||||
|                 } |                 } | ||||||
|                 if (ctx.Match("off", "disable")) { |                 if (ctx.Match("off", "disable")) { | ||||||
|                     ctx.System.PingsEnabled = false; |                     var patch = new SystemPatch {PingsEnabled = false}; | ||||||
|                     await _data.SaveSystem(ctx.System); |                     await _db.Execute(conn => conn.UpdateSystem(ctx.System.Id, patch)); | ||||||
|  |                      | ||||||
|                     await ctx.Reply("Reaction pings have now been disabled."); |                     await ctx.Reply("Reaction pings have now been disabled."); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -8,10 +8,10 @@ namespace PluralKit.Bot | |||||||
| { | { | ||||||
|     public class Token |     public class Token | ||||||
|     { |     { | ||||||
|         private IDataStore _data; |         private readonly IDatabase _db; | ||||||
|         public Token(IDataStore data) |         public Token(IDatabase db) | ||||||
|         { |         { | ||||||
|             _data = data; |             _db = db; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public async Task GetToken(Context ctx) |         public async Task GetToken(Context ctx) | ||||||
| @@ -35,8 +35,9 @@ namespace PluralKit.Bot | |||||||
|  |  | ||||||
|         private async Task<string> MakeAndSetNewToken(PKSystem system) |         private async Task<string> MakeAndSetNewToken(PKSystem system) | ||||||
|         { |         { | ||||||
|             system.Token = Core.StringUtils.GenerateToken(); |             var patch = new SystemPatch {Token = StringUtils.GenerateToken()}; | ||||||
|             await _data.SaveSystem(system); |             await _db.Execute(conn => conn.UpdateSystem(system.Id, patch)); | ||||||
|  |              | ||||||
|             return system.Token; |             return system.Token; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|   | |||||||
| @@ -28,16 +28,5 @@ namespace PluralKit.Core | |||||||
|             conn.QueryFirstAsync<MemberGuildSettings>( |             conn.QueryFirstAsync<MemberGuildSettings>( | ||||||
|                 "insert into member_guild (guild, member) values (@guild, @member) on conflict (guild, member) do update set guild = @guild, member = @member returning *", |                 "insert into member_guild (guild, member) values (@guild, @member) on conflict (guild, member) do update set guild = @guild, member = @member returning *", | ||||||
|                 new {guild, member}); |                 new {guild, member}); | ||||||
|  |  | ||||||
|         public static Task<PKMember> UpdateMember(this IPKConnection conn, MemberId id, MemberPatch patch) |  | ||||||
|         { |  | ||||||
|             var (query, pms) = patch.Apply(new UpdateQueryBuilder("members", "id = @id")) |  | ||||||
|                 .WithConstant("id", id) |  | ||||||
|                 .Build("returning *"); |  | ||||||
|             return conn.QueryFirstAsync<PKMember>(query, pms); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public static Task DeleteMember(this IPKConnection conn, MemberId id) => |  | ||||||
|             conn.ExecuteAsync("delete from members where id = @Id", new {Id = id}); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -10,18 +10,18 @@ namespace PluralKit.Core { | |||||||
|         // Additions here should be mirrored in SystemStore::Save |         // Additions here should be mirrored in SystemStore::Save | ||||||
|         [Key] public SystemId Id { get; } |         [Key] public SystemId Id { get; } | ||||||
|         public string Hid { get; } |         public string Hid { get; } | ||||||
|         public string Name { get; set; } |         public string Name { get; } | ||||||
|         public string Description { get; set; } |         public string Description { get; } | ||||||
|         public string Tag { get; set; } |         public string Tag { get; } | ||||||
|         public string AvatarUrl { get; set; } |         public string AvatarUrl { get; } | ||||||
|         public string Token { get; set; } |         public string Token { get; } | ||||||
|         public Instant Created { get; } |         public Instant Created { get; } | ||||||
|         public string UiTz { get; set; } |         public string UiTz { get; set; } | ||||||
|         public bool PingsEnabled { get; set; } |         public bool PingsEnabled { get; } | ||||||
| 	    public PrivacyLevel DescriptionPrivacy { get; set; } | 	    public PrivacyLevel DescriptionPrivacy { get; } | ||||||
|         public PrivacyLevel MemberListPrivacy { get; set; } |         public PrivacyLevel MemberListPrivacy { get;} | ||||||
|         public PrivacyLevel FrontPrivacy { get; set; } |         public PrivacyLevel FrontPrivacy { get; } | ||||||
|         public PrivacyLevel FrontHistoryPrivacy { get; set; } |         public PrivacyLevel FrontHistoryPrivacy { get; } | ||||||
|          |          | ||||||
|         [JsonIgnore] public DateTimeZone Zone => DateTimeZoneProviders.Tzdb.GetZoneOrNull(UiTz); |         [JsonIgnore] public DateTimeZone Zone => DateTimeZoneProviders.Tzdb.GetZoneOrNull(UiTz); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ using NodaTime; | |||||||
|  |  | ||||||
| namespace PluralKit.Core | namespace PluralKit.Core | ||||||
| { | { | ||||||
|     public class MemberPatch: PatchObject<MemberId, PKMember> |     public class MemberPatch: PatchObject | ||||||
|     { |     { | ||||||
|         public Partial<string> Name { get; set; } |         public Partial<string> Name { get; set; } | ||||||
|         public Partial<string?> DisplayName { get; set; } |         public Partial<string?> DisplayName { get; set; } | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								PluralKit.Core/Models/Patch/ModelPatchExt.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								PluralKit.Core/Models/Patch/ModelPatchExt.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | using System.Threading.Tasks; | ||||||
|  |  | ||||||
|  | using Dapper; | ||||||
|  |  | ||||||
|  | namespace PluralKit.Core | ||||||
|  | { | ||||||
|  |     public static class ModelPatchExt | ||||||
|  |     { | ||||||
|  |         public static Task<PKSystem> UpdateSystem(this IPKConnection conn, SystemId id, SystemPatch patch) | ||||||
|  |         { | ||||||
|  |             var (query, pms) = patch.Apply(new UpdateQueryBuilder("systems", "id = @id")) | ||||||
|  |                 .WithConstant("id", id) | ||||||
|  |                 .Build("returning *"); | ||||||
|  |             return conn.QueryFirstAsync<PKSystem>(query, pms); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static Task DeleteSystem(this IPKConnection conn, SystemId id) => | ||||||
|  |             conn.ExecuteAsync("delete from systems where id = @Id", new {Id = id}); | ||||||
|  |          | ||||||
|  |         public static Task<PKMember> UpdateMember(this IPKConnection conn, MemberId id, MemberPatch patch) | ||||||
|  |         { | ||||||
|  |             var (query, pms) = patch.Apply(new UpdateQueryBuilder("members", "id = @id")) | ||||||
|  |                 .WithConstant("id", id) | ||||||
|  |                 .Build("returning *"); | ||||||
|  |             return conn.QueryFirstAsync<PKMember>(query, pms); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         public static Task DeleteMember(this IPKConnection conn, MemberId id) => | ||||||
|  |             conn.ExecuteAsync("delete from members where id = @Id", new {Id = id}); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,8 +1,6 @@ | |||||||
| using PluralKit.Core; | namespace PluralKit.Core | ||||||
|  |  | ||||||
| namespace PluralKit.Core |  | ||||||
| { | { | ||||||
|     public abstract class PatchObject<TKey, TObj> |     public abstract class PatchObject | ||||||
|     { |     { | ||||||
|         public abstract UpdateQueryBuilder Apply(UpdateQueryBuilder b); |         public abstract UpdateQueryBuilder Apply(UpdateQueryBuilder b); | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								PluralKit.Core/Models/Patch/SystemPatch.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								PluralKit.Core/Models/Patch/SystemPatch.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | #nullable enable | ||||||
|  | namespace PluralKit.Core | ||||||
|  | { | ||||||
|  |     public class SystemPatch: PatchObject | ||||||
|  |     { | ||||||
|  |         public Partial<string?> Name { get; set; } | ||||||
|  |         public Partial<string?> Description { get; set; } | ||||||
|  |         public Partial<string?> Tag { get; set; } | ||||||
|  |         public Partial<string?> AvatarUrl { get; set; } | ||||||
|  |         public Partial<string?> Token { get; set; } | ||||||
|  |         public Partial<string> UiTz { get; set; } | ||||||
|  |         public Partial<PrivacyLevel> DescriptionPrivacy { get; set; } | ||||||
|  |         public Partial<PrivacyLevel> MemberListPrivacy { get; set; } | ||||||
|  |         public Partial<PrivacyLevel> FrontPrivacy { get; set; } | ||||||
|  |         public Partial<PrivacyLevel> FrontHistoryPrivacy { get; set; } | ||||||
|  |         public Partial<bool> PingsEnabled { get; set; } | ||||||
|  |  | ||||||
|  |         public override UpdateQueryBuilder Apply(UpdateQueryBuilder b) => b | ||||||
|  |             .With("name", Name) | ||||||
|  |             .With("description", Description) | ||||||
|  |             .With("tag", Tag) | ||||||
|  |             .With("avatar_url", AvatarUrl) | ||||||
|  |             .With("token", Token) | ||||||
|  |             .With("ui_tz", UiTz) | ||||||
|  |             .With("description_privacy", DescriptionPrivacy) | ||||||
|  |             .With("member_list_privacy", MemberListPrivacy) | ||||||
|  |             .With("front_privacy", FrontPrivacy) | ||||||
|  |             .With("front_history_privacy", FrontHistoryPrivacy) | ||||||
|  |             .With("pings_enabled", PingsEnabled); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -116,16 +116,17 @@ namespace PluralKit.Core | |||||||
|                 await _data.AddAccount(system, accountId); |                 await _data.AddAccount(system, accountId); | ||||||
|             } |             } | ||||||
|              |              | ||||||
|  |             await using var conn = await _db.Obtain(); | ||||||
|  |  | ||||||
|             // Apply system info |             // Apply system info | ||||||
|             system.Name = data.Name; |             var patch = new SystemPatch {Name = data.Name}; | ||||||
|             if (data.Description != null) system.Description = data.Description; |             if (data.Description != null) patch.Description = data.Description; | ||||||
|             if (data.Tag != null) system.Tag = data.Tag; |             if (data.Tag != null) patch.Tag = data.Tag; | ||||||
|             if (data.AvatarUrl != null) system.AvatarUrl = data.AvatarUrl; |             if (data.AvatarUrl != null) patch.AvatarUrl = data.AvatarUrl; | ||||||
|             if (data.TimeZone != null) system.UiTz = data.TimeZone ?? "UTC"; |             if (data.TimeZone != null) patch.UiTz = data.TimeZone ?? "UTC"; | ||||||
|             await _data.SaveSystem(system); |             await conn.UpdateSystem(system.Id, patch); | ||||||
|              |              | ||||||
|             // -- Member/switch import -- |             // -- Member/switch import -- | ||||||
|             await using var conn = await _db.Obtain(); |  | ||||||
|             await using (var imp = await BulkImporter.Begin(system, conn)) |             await using (var imp = await BulkImporter.Begin(system, conn)) | ||||||
|             { |             { | ||||||
|                 // Tally up the members that didn't exist before, and check member count on import |                 // Tally up the members that didn't exist before, and check member count on import | ||||||
|   | |||||||
| @@ -103,20 +103,6 @@ namespace PluralKit.Core { | |||||||
|         /// <exception>Throws an exception (TODO: which?) if the given account is not linked to the given system.</exception> |         /// <exception>Throws an exception (TODO: which?) if the given account is not linked to the given system.</exception> | ||||||
|         Task RemoveAccount(PKSystem system, ulong accountToRemove); |         Task RemoveAccount(PKSystem system, ulong accountToRemove); | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Saves the information within the given <see cref="PKSystem"/> struct to the data store. |  | ||||||
|         /// </summary> |  | ||||||
|         Task SaveSystem(PKSystem system); |  | ||||||
|          |  | ||||||
|         /// <summary> |  | ||||||
|         /// Deletes the given system from the database. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <para> |  | ||||||
|         /// This will also delete all the system's members, all system switches, and every message that has been proxied |  | ||||||
|         /// by members in the system. |  | ||||||
|         /// </para> |  | ||||||
|         Task DeleteSystem(PKSystem system); |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Gets a member by its user-facing human ID. |         /// Gets a member by its user-facing human ID. | ||||||
|         /// </summary> |         /// </summary> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user