From 11bd66e8d8a80c7673e2b0a360788ac3153293d6 Mon Sep 17 00:00:00 2001 From: spiral Date: Sat, 7 Aug 2021 18:13:46 -0400 Subject: [PATCH] refactor: move JsonModelExt to PluralKit.Core (in individual model/patch files) --- PluralKit.API/Controllers/v1/JsonModelExt.cs | 178 ------------------ .../Controllers/v1/MemberController.cs | 4 +- .../Controllers/v1/SystemController.cs | 2 +- PluralKit.Core/Models/PKMember.cs | 50 ++++- PluralKit.Core/Models/PKSystem.cs | 24 ++- PluralKit.Core/Models/Patch/MemberPatch.cs | 68 +++++++ PluralKit.Core/Models/Patch/SystemPatch.cs | 22 +++ PluralKit.Core/Models/Privacy/PrivacyLevel.cs | 12 ++ PluralKit.Core/Utils/JsonUtils.cs | 19 ++ 9 files changed, 193 insertions(+), 186 deletions(-) delete mode 100644 PluralKit.API/Controllers/v1/JsonModelExt.cs create mode 100644 PluralKit.Core/Utils/JsonUtils.cs diff --git a/PluralKit.API/Controllers/v1/JsonModelExt.cs b/PluralKit.API/Controllers/v1/JsonModelExt.cs deleted file mode 100644 index 28a2dc2f..00000000 --- a/PluralKit.API/Controllers/v1/JsonModelExt.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System; -using System.Linq; - -using Newtonsoft.Json.Linq; - -using PluralKit.Core; - -namespace PluralKit.API -{ - public static class JsonModelExt - { - public static JObject ToJson(this PKSystem system, LookupContext ctx) - { - var o = new JObject(); - o.Add("id", system.Hid); - o.Add("name", system.Name); - o.Add("description", system.DescriptionFor(ctx)); - o.Add("tag", system.Tag); - o.Add("avatar_url", system.AvatarUrl.TryGetCleanCdnUrl()); - o.Add("banner", system.DescriptionPrivacy.Get(ctx, system.BannerImage).TryGetCleanCdnUrl()); - o.Add("created", system.Created.FormatExport()); - o.Add("tz", system.UiTz); - o.Add("description_privacy", ctx == LookupContext.ByOwner ? system.DescriptionPrivacy.ToJsonString() : null); - o.Add("member_list_privacy", ctx == LookupContext.ByOwner ? system.MemberListPrivacy.ToJsonString() : null); - o.Add("front_privacy", ctx == LookupContext.ByOwner ? system.FrontPrivacy.ToJsonString() : null); - o.Add("front_history_privacy", ctx == LookupContext.ByOwner ? system.FrontHistoryPrivacy.ToJsonString() : null); - return o; - } - - public static SystemPatch ToSystemPatch(JObject o) - { - var patch = new SystemPatch(); - if (o.ContainsKey("name")) patch.Name = o.Value("name").NullIfEmpty().BoundsCheckField(Limits.MaxSystemNameLength, "System name"); - if (o.ContainsKey("description")) patch.Description = o.Value("description").NullIfEmpty().BoundsCheckField(Limits.MaxDescriptionLength, "System description"); - if (o.ContainsKey("tag")) patch.Tag = o.Value("tag").NullIfEmpty().BoundsCheckField(Limits.MaxSystemTagLength, "System tag"); - if (o.ContainsKey("avatar_url")) patch.AvatarUrl = o.Value("avatar_url").NullIfEmpty().BoundsCheckField(Limits.MaxUriLength, "System avatar URL"); - if (o.ContainsKey("banner")) patch.BannerImage = o.Value("banner").NullIfEmpty().BoundsCheckField(Limits.MaxUriLength, "System banner URL"); - if (o.ContainsKey("tz")) patch.UiTz = o.Value("tz") ?? "UTC"; - - if (o.ContainsKey("description_privacy")) patch.DescriptionPrivacy = o.Value("description_privacy").ParsePrivacy("description"); - if (o.ContainsKey("member_list_privacy")) patch.MemberListPrivacy = o.Value("member_list_privacy").ParsePrivacy("member list"); - if (o.ContainsKey("front_privacy")) patch.FrontPrivacy = o.Value("front_privacy").ParsePrivacy("front"); - if (o.ContainsKey("front_history_privacy")) patch.FrontHistoryPrivacy = o.Value("front_history_privacy").ParsePrivacy("front history"); - return patch; - } - - public static JObject ToJson(this PKMember member, LookupContext ctx) - { - var includePrivacy = ctx == LookupContext.ByOwner; - - var o = new JObject(); - o.Add("id", member.Hid); - o.Add("name", member.NameFor(ctx)); - // o.Add("color", member.ColorPrivacy.CanAccess(ctx) ? member.Color : null); - o.Add("color", member.Color); - o.Add("display_name", member.NamePrivacy.CanAccess(ctx) ? member.DisplayName : null); - o.Add("birthday", member.BirthdayFor(ctx)?.FormatExport()); - o.Add("pronouns", member.PronounsFor(ctx)); - o.Add("avatar_url", member.AvatarFor(ctx).TryGetCleanCdnUrl()); - o.Add("banner", member.DescriptionPrivacy.Get(ctx, member.BannerImage).TryGetCleanCdnUrl()); - o.Add("description", member.DescriptionFor(ctx)); - - var tagArray = new JArray(); - foreach (var tag in member.ProxyTags) - tagArray.Add(new JObject {{"prefix", tag.Prefix}, {"suffix", tag.Suffix}}); - o.Add("proxy_tags", tagArray); - - o.Add("keep_proxy", member.KeepProxy); - - o.Add("privacy", includePrivacy ? (member.MemberVisibility.LevelName()) : null); - - o.Add("visibility", includePrivacy ? (member.MemberVisibility.LevelName()) : null); - o.Add("name_privacy", includePrivacy ? (member.NamePrivacy.LevelName()) : null); - o.Add("description_privacy", includePrivacy ? (member.DescriptionPrivacy.LevelName()) : null); - o.Add("birthday_privacy", includePrivacy ? (member.BirthdayPrivacy.LevelName()) : null); - o.Add("pronoun_privacy", includePrivacy ? (member.PronounPrivacy.LevelName()) : null); - o.Add("avatar_privacy", includePrivacy ? (member.AvatarPrivacy.LevelName()) : null); - // o.Add("color_privacy", ctx == LookupContext.ByOwner ? (member.ColorPrivacy.LevelName()) : null); - o.Add("metadata_privacy", includePrivacy ? (member.MetadataPrivacy.LevelName()) : null); - - o.Add("created", member.CreatedFor(ctx)?.FormatExport()); - - if (member.ProxyTags.Count > 0) - { - // Legacy compatibility only, TODO: remove at some point - o.Add("prefix", member.ProxyTags?.FirstOrDefault().Prefix); - o.Add("suffix", member.ProxyTags?.FirstOrDefault().Suffix); - } - - return o; - } - - public static MemberPatch ToMemberPatch(JObject o) - { - var patch = new MemberPatch(); - - if (o.ContainsKey("name") && o["name"].Type == JTokenType.Null) - throw new JsonModelParseError("Member name can not be set to null."); - - if (o.ContainsKey("name")) patch.Name = o.Value("name").BoundsCheckField(Limits.MaxMemberNameLength, "Member name"); - if (o.ContainsKey("color")) patch.Color = o.Value("color").NullIfEmpty()?.ToLower(); - if (o.ContainsKey("display_name")) patch.DisplayName = o.Value("display_name").NullIfEmpty().BoundsCheckField(Limits.MaxMemberNameLength, "Member display name"); - if (o.ContainsKey("avatar_url")) patch.AvatarUrl = o.Value("avatar_url").NullIfEmpty().BoundsCheckField(Limits.MaxUriLength, "Member avatar URL"); - if (o.ContainsKey("banner")) patch.BannerImage = o.Value("banner").NullIfEmpty().BoundsCheckField(Limits.MaxUriLength, "Member banner URL"); - - if (o.ContainsKey("birthday")) - { - var str = o.Value("birthday").NullIfEmpty(); - var res = DateTimeFormats.DateExportFormat.Parse(str); - if (res.Success) patch.Birthday = res.Value; - else if (str == null) patch.Birthday = null; - else throw new JsonModelParseError("Could not parse member birthday."); - } - - if (o.ContainsKey("pronouns")) patch.Pronouns = o.Value("pronouns").NullIfEmpty().BoundsCheckField(Limits.MaxPronounsLength, "Member pronouns"); - if (o.ContainsKey("description")) patch.Description = o.Value("description").NullIfEmpty().BoundsCheckField(Limits.MaxDescriptionLength, "Member descriptoin"); - if (o.ContainsKey("keep_proxy")) patch.KeepProxy = o.Value("keep_proxy"); - - if (o.ContainsKey("prefix") || o.ContainsKey("suffix") && !o.ContainsKey("proxy_tags")) - patch.ProxyTags = new[] {new ProxyTag(o.Value("prefix"), o.Value("suffix"))}; - else if (o.ContainsKey("proxy_tags")) - { - patch.ProxyTags = o.Value("proxy_tags") - .OfType().Select(o => new ProxyTag(o.Value("prefix"), o.Value("suffix"))) - .ToArray(); - } - if(o.ContainsKey("privacy")) //TODO: Deprecate this completely in api v2 - { - var plevel = o.Value("privacy").ParsePrivacy("member"); - - patch.Visibility = plevel; - patch.NamePrivacy = plevel; - patch.AvatarPrivacy = plevel; - patch.DescriptionPrivacy = plevel; - patch.BirthdayPrivacy = plevel; - patch.PronounPrivacy = plevel; - // member.ColorPrivacy = plevel; - patch.MetadataPrivacy = plevel; - } - else - { - if (o.ContainsKey("visibility")) patch.Visibility = o.Value("visibility").ParsePrivacy("member"); - if (o.ContainsKey("name_privacy")) patch.NamePrivacy = o.Value("name_privacy").ParsePrivacy("member"); - if (o.ContainsKey("description_privacy")) patch.DescriptionPrivacy = o.Value("description_privacy").ParsePrivacy("member"); - if (o.ContainsKey("avatar_privacy")) patch.AvatarPrivacy = o.Value("avatar_privacy").ParsePrivacy("member"); - if (o.ContainsKey("birthday_privacy")) patch.BirthdayPrivacy = o.Value("birthday_privacy").ParsePrivacy("member"); - if (o.ContainsKey("pronoun_privacy")) patch.PronounPrivacy = o.Value("pronoun_privacy").ParsePrivacy("member"); - // if (o.ContainsKey("color_privacy")) member.ColorPrivacy = o.Value("color_privacy").ParsePrivacy("member"); - if (o.ContainsKey("metadata_privacy")) patch.MetadataPrivacy = o.Value("metadata_privacy").ParsePrivacy("member"); - } - - return patch; - } - - private static string BoundsCheckField(this string input, int maxLength, string nameInError) - { - if (input != null && input.Length > maxLength) - throw new JsonModelParseError($"{nameInError} too long ({input.Length} > {maxLength})."); - return input; - } - - private static string ToJsonString(this PrivacyLevel level) => level.LevelName(); - - private static PrivacyLevel ParsePrivacy(this string input, string errorName) - { - if (input == null) return PrivacyLevel.Public; - if (input == "") return PrivacyLevel.Private; - if (input == "private") return PrivacyLevel.Private; - if (input == "public") return PrivacyLevel.Public; - throw new JsonModelParseError($"Could not parse {errorName} privacy."); - } - } - - public class JsonModelParseError: Exception - { - public JsonModelParseError(string message): base(message) { } - } -} \ No newline at end of file diff --git a/PluralKit.API/Controllers/v1/MemberController.cs b/PluralKit.API/Controllers/v1/MemberController.cs index 56a5ae43..6c47392c 100644 --- a/PluralKit.API/Controllers/v1/MemberController.cs +++ b/PluralKit.API/Controllers/v1/MemberController.cs @@ -61,7 +61,7 @@ namespace PluralKit.API MemberPatch patch; try { - patch = JsonModelExt.ToMemberPatch(properties); + patch = MemberPatch.FromJSON(properties); patch.CheckIsValid(); } catch (JsonModelParseError e) @@ -95,7 +95,7 @@ namespace PluralKit.API MemberPatch patch; try { - patch = JsonModelExt.ToMemberPatch(changes); + patch = MemberPatch.FromJSON(changes); patch.CheckIsValid(); } catch (JsonModelParseError e) diff --git a/PluralKit.API/Controllers/v1/SystemController.cs b/PluralKit.API/Controllers/v1/SystemController.cs index b0bf7003..dd7a357b 100644 --- a/PluralKit.API/Controllers/v1/SystemController.cs +++ b/PluralKit.API/Controllers/v1/SystemController.cs @@ -140,7 +140,7 @@ namespace PluralKit.API SystemPatch patch; try { - patch = JsonModelExt.ToSystemPatch(changes); + patch = SystemPatch.FromJSON(changes); patch.CheckIsValid(); } catch (JsonModelParseError e) diff --git a/PluralKit.Core/Models/PKMember.cs b/PluralKit.Core/Models/PKMember.cs index 4a1dc6d4..287382f8 100644 --- a/PluralKit.Core/Models/PKMember.cs +++ b/PluralKit.Core/Models/PKMember.cs @@ -1,12 +1,12 @@ using System.Collections.Generic; +using System.Linq; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using NodaTime; using NodaTime.Text; - - namespace PluralKit.Core { public readonly struct MemberId: INumericId { @@ -101,5 +101,51 @@ namespace PluralKit.Core { public static int MessageCountFor(this PKMember member, LookupContext ctx) => member.MetadataPrivacy.Get(ctx, member.MessageCount); + + public static JObject ToJson(this PKMember member, LookupContext ctx) + { + var includePrivacy = ctx == LookupContext.ByOwner; + + var o = new JObject(); + o.Add("id", member.Hid); + o.Add("name", member.NameFor(ctx)); + // o.Add("color", member.ColorPrivacy.CanAccess(ctx) ? member.Color : null); + o.Add("color", member.Color); + o.Add("display_name", member.NamePrivacy.CanAccess(ctx) ? member.DisplayName : null); + o.Add("birthday", member.BirthdayFor(ctx)?.FormatExport()); + o.Add("pronouns", member.PronounsFor(ctx)); + o.Add("avatar_url", member.AvatarFor(ctx).TryGetCleanCdnUrl()); + o.Add("banner", member.DescriptionPrivacy.Get(ctx, member.BannerImage).TryGetCleanCdnUrl()); + o.Add("description", member.DescriptionFor(ctx)); + + var tagArray = new JArray(); + foreach (var tag in member.ProxyTags) + tagArray.Add(new JObject {{"prefix", tag.Prefix}, {"suffix", tag.Suffix}}); + o.Add("proxy_tags", tagArray); + + o.Add("keep_proxy", member.KeepProxy); + + o.Add("privacy", includePrivacy ? (member.MemberVisibility.LevelName()) : null); + + o.Add("visibility", includePrivacy ? (member.MemberVisibility.LevelName()) : null); + o.Add("name_privacy", includePrivacy ? (member.NamePrivacy.LevelName()) : null); + o.Add("description_privacy", includePrivacy ? (member.DescriptionPrivacy.LevelName()) : null); + o.Add("birthday_privacy", includePrivacy ? (member.BirthdayPrivacy.LevelName()) : null); + o.Add("pronoun_privacy", includePrivacy ? (member.PronounPrivacy.LevelName()) : null); + o.Add("avatar_privacy", includePrivacy ? (member.AvatarPrivacy.LevelName()) : null); + // o.Add("color_privacy", ctx == LookupContext.ByOwner ? (member.ColorPrivacy.LevelName()) : null); + o.Add("metadata_privacy", includePrivacy ? (member.MetadataPrivacy.LevelName()) : null); + + o.Add("created", member.CreatedFor(ctx)?.FormatExport()); + + if (member.ProxyTags.Count > 0) + { + // Legacy compatibility only, TODO: remove at some point + o.Add("prefix", member.ProxyTags?.FirstOrDefault().Prefix); + o.Add("suffix", member.ProxyTags?.FirstOrDefault().Suffix); + } + + return o; + } } } \ No newline at end of file diff --git a/PluralKit.Core/Models/PKSystem.cs b/PluralKit.Core/Models/PKSystem.cs index 42f9e6b8..5ce0e9e2 100644 --- a/PluralKit.Core/Models/PKSystem.cs +++ b/PluralKit.Core/Models/PKSystem.cs @@ -1,11 +1,10 @@ using Dapper.Contrib.Extensions; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using NodaTime; - - namespace PluralKit.Core { public readonly struct SystemId: INumericId @@ -34,7 +33,6 @@ namespace PluralKit.Core { public class PKSystem { - // Additions here should be mirrored in SystemStore::Save [Key] public SystemId Id { get; } public string Hid { get; } public string Name { get; } @@ -63,5 +61,25 @@ namespace PluralKit.Core { { public static string DescriptionFor(this PKSystem system, LookupContext ctx) => system.DescriptionPrivacy.Get(ctx, system.Description); + + public static JObject ToJson(this PKSystem system, LookupContext ctx) + { + var o = new JObject(); + o.Add("id", system.Hid); + o.Add("name", system.Name); + o.Add("description", system.DescriptionFor(ctx)); + o.Add("tag", system.Tag); + o.Add("avatar_url", system.AvatarUrl.TryGetCleanCdnUrl()); + o.Add("banner", system.DescriptionPrivacy.Get(ctx, system.BannerImage).TryGetCleanCdnUrl()); + o.Add("created", system.Created.FormatExport()); + // todo: change this to "timezone" + o.Add("tz", system.UiTz); + // todo: just don't include these if not ByOwner + o.Add("description_privacy", ctx == LookupContext.ByOwner ? system.DescriptionPrivacy.ToJsonString() : null); + o.Add("member_list_privacy", ctx == LookupContext.ByOwner ? system.MemberListPrivacy.ToJsonString() : null); + o.Add("front_privacy", ctx == LookupContext.ByOwner ? system.FrontPrivacy.ToJsonString() : null); + o.Add("front_history_privacy", ctx == LookupContext.ByOwner ? system.FrontHistoryPrivacy.ToJsonString() : null); + return o; + } } } diff --git a/PluralKit.Core/Models/Patch/MemberPatch.cs b/PluralKit.Core/Models/Patch/MemberPatch.cs index 8a528c38..d925be88 100644 --- a/PluralKit.Core/Models/Patch/MemberPatch.cs +++ b/PluralKit.Core/Models/Patch/MemberPatch.cs @@ -1,8 +1,11 @@ #nullable enable +using System.Linq; using System.Text.RegularExpressions; using NodaTime; +using Newtonsoft.Json.Linq; + namespace PluralKit.Core { public class MemberPatch: PatchObject @@ -60,5 +63,70 @@ namespace PluralKit.Core throw new InvalidPatchException("color"); } +#nullable disable + + public static MemberPatch FromJSON(JObject o) + { + var patch = new MemberPatch(); + + if (o.ContainsKey("name") && o["name"].Type == JTokenType.Null) + throw new JsonModelParseError("Member name can not be set to null."); + + if (o.ContainsKey("name")) patch.Name = o.Value("name").BoundsCheckField(Limits.MaxMemberNameLength, "Member name"); + if (o.ContainsKey("color")) patch.Color = o.Value("color").NullIfEmpty()?.ToLower(); + if (o.ContainsKey("display_name")) patch.DisplayName = o.Value("display_name").NullIfEmpty().BoundsCheckField(Limits.MaxMemberNameLength, "Member display name"); + if (o.ContainsKey("avatar_url")) patch.AvatarUrl = o.Value("avatar_url").NullIfEmpty().BoundsCheckField(Limits.MaxUriLength, "Member avatar URL"); + if (o.ContainsKey("banner")) patch.BannerImage = o.Value("banner").NullIfEmpty().BoundsCheckField(Limits.MaxUriLength, "Member banner URL"); + + if (o.ContainsKey("birthday")) + { + var str = o.Value("birthday").NullIfEmpty(); + var res = DateTimeFormats.DateExportFormat.Parse(str); + if (res.Success) patch.Birthday = res.Value; + else if (str == null) patch.Birthday = null; + else throw new JsonModelParseError("Could not parse member birthday."); + } + + if (o.ContainsKey("pronouns")) patch.Pronouns = o.Value("pronouns").NullIfEmpty().BoundsCheckField(Limits.MaxPronounsLength, "Member pronouns"); + if (o.ContainsKey("description")) patch.Description = o.Value("description").NullIfEmpty().BoundsCheckField(Limits.MaxDescriptionLength, "Member descriptoin"); + if (o.ContainsKey("keep_proxy")) patch.KeepProxy = o.Value("keep_proxy"); + + // legacy: used in old export files and APIv1 + // todo: should we parse `proxy_tags` first? + if (o.ContainsKey("prefix") || o.ContainsKey("suffix") && !o.ContainsKey("proxy_tags")) + patch.ProxyTags = new[] {new ProxyTag(o.Value("prefix"), o.Value("suffix"))}; + else if (o.ContainsKey("proxy_tags")) + { + patch.ProxyTags = o.Value("proxy_tags") + .OfType().Select(o => new ProxyTag(o.Value("prefix"), o.Value("suffix"))) + .ToArray(); + } + if(o.ContainsKey("privacy")) //TODO: Deprecate this completely in api v2 + { + var plevel = o.Value("privacy").ParsePrivacy("member"); + + patch.Visibility = plevel; + patch.NamePrivacy = plevel; + patch.AvatarPrivacy = plevel; + patch.DescriptionPrivacy = plevel; + patch.BirthdayPrivacy = plevel; + patch.PronounPrivacy = plevel; + // member.ColorPrivacy = plevel; + patch.MetadataPrivacy = plevel; + } + else + { + if (o.ContainsKey("visibility")) patch.Visibility = o.Value("visibility").ParsePrivacy("member"); + if (o.ContainsKey("name_privacy")) patch.NamePrivacy = o.Value("name_privacy").ParsePrivacy("member"); + if (o.ContainsKey("description_privacy")) patch.DescriptionPrivacy = o.Value("description_privacy").ParsePrivacy("member"); + if (o.ContainsKey("avatar_privacy")) patch.AvatarPrivacy = o.Value("avatar_privacy").ParsePrivacy("member"); + if (o.ContainsKey("birthday_privacy")) patch.BirthdayPrivacy = o.Value("birthday_privacy").ParsePrivacy("member"); + if (o.ContainsKey("pronoun_privacy")) patch.PronounPrivacy = o.Value("pronoun_privacy").ParsePrivacy("member"); + // if (o.ContainsKey("color_privacy")) member.ColorPrivacy = o.Value("color_privacy").ParsePrivacy("member"); + if (o.ContainsKey("metadata_privacy")) patch.MetadataPrivacy = o.Value("metadata_privacy").ParsePrivacy("member"); + } + + return patch; + } } } \ No newline at end of file diff --git a/PluralKit.Core/Models/Patch/SystemPatch.cs b/PluralKit.Core/Models/Patch/SystemPatch.cs index 9c9fdaf6..d92aef62 100644 --- a/PluralKit.Core/Models/Patch/SystemPatch.cs +++ b/PluralKit.Core/Models/Patch/SystemPatch.cs @@ -1,6 +1,8 @@ #nullable enable using System.Text.RegularExpressions; +using Newtonsoft.Json.Linq; + namespace PluralKit.Core { public class SystemPatch: PatchObject @@ -54,5 +56,25 @@ namespace PluralKit.Core throw new InvalidPatchException("color"); } + public static SystemPatch FromJSON(JObject o) + { + var patch = new SystemPatch(); + if (o.ContainsKey("name")) patch.Name = o.Value("name").NullIfEmpty().BoundsCheckField(Limits.MaxSystemNameLength, "System name"); + if (o.ContainsKey("description")) patch.Description = o.Value("description").NullIfEmpty().BoundsCheckField(Limits.MaxDescriptionLength, "System description"); + if (o.ContainsKey("tag")) patch.Tag = o.Value("tag").NullIfEmpty().BoundsCheckField(Limits.MaxSystemTagLength, "System tag"); + if (o.ContainsKey("avatar_url")) patch.AvatarUrl = o.Value("avatar_url").NullIfEmpty().BoundsCheckField(Limits.MaxUriLength, "System avatar URL"); + if (o.ContainsKey("banner")) patch.BannerImage = o.Value("banner").NullIfEmpty().BoundsCheckField(Limits.MaxUriLength, "System banner URL"); + if (o.ContainsKey("timezone")) patch.UiTz = o.Value("tz") ?? "UTC"; + + // legacy: APIv1 uses "tz" instead of "timezone" + // todo: remove in APIv2 + if (o.ContainsKey("tz")) patch.UiTz = o.Value("tz") ?? "UTC"; + + if (o.ContainsKey("description_privacy")) patch.DescriptionPrivacy = o.Value("description_privacy").ParsePrivacy("description"); + if (o.ContainsKey("member_list_privacy")) patch.MemberListPrivacy = o.Value("member_list_privacy").ParsePrivacy("member list"); + if (o.ContainsKey("front_privacy")) patch.FrontPrivacy = o.Value("front_privacy").ParsePrivacy("front"); + if (o.ContainsKey("front_history_privacy")) patch.FrontHistoryPrivacy = o.Value("front_history_privacy").ParsePrivacy("front history"); + return patch; + } } } \ No newline at end of file diff --git a/PluralKit.Core/Models/Privacy/PrivacyLevel.cs b/PluralKit.Core/Models/Privacy/PrivacyLevel.cs index 03a6ea99..a14b63bd 100644 --- a/PluralKit.Core/Models/Privacy/PrivacyLevel.cs +++ b/PluralKit.Core/Models/Privacy/PrivacyLevel.cs @@ -38,5 +38,17 @@ namespace PluralKit.Core output = input; return true; } + + public static string ToJsonString(this PrivacyLevel level) => level.LevelName(); + + public static PrivacyLevel ParsePrivacy(this string input, string errorName) + { + if (input == null) return PrivacyLevel.Public; + if (input == "") return PrivacyLevel.Private; + if (input == "private") return PrivacyLevel.Private; + if (input == "public") return PrivacyLevel.Public; + throw new JsonModelParseError($"Could not parse {errorName} privacy."); + } + } } \ No newline at end of file diff --git a/PluralKit.Core/Utils/JsonUtils.cs b/PluralKit.Core/Utils/JsonUtils.cs new file mode 100644 index 00000000..baba5c57 --- /dev/null +++ b/PluralKit.Core/Utils/JsonUtils.cs @@ -0,0 +1,19 @@ +using System; + +namespace PluralKit.Core +{ + internal static class JsonUtils + { + public static string BoundsCheckField(this string input, int maxLength, string nameInError) + { + if (input != null && input.Length > maxLength) + throw new JsonModelParseError($"{nameInError} too long ({input.Length} > {maxLength})."); + return input; + } + } + + public class JsonModelParseError: Exception + { + public JsonModelParseError(string message): base(message) { } + } +} \ No newline at end of file