#nullable enable using Newtonsoft.Json.Linq; using NodaTime; using SqlKata; namespace PluralKit.Core; public class MemberPatch: PatchObject { public Partial Name { get; set; } public Partial Hid { get; set; } public Partial DisplayName { get; set; } public Partial AvatarUrl { get; set; } public Partial BannerImage { get; set; } public Partial Color { get; set; } public Partial Birthday { get; set; } public Partial Pronouns { get; set; } public Partial Description { get; set; } public Partial ProxyTags { get; set; } public Partial KeepProxy { get; set; } public Partial MessageCount { get; set; } public Partial AllowAutoproxy { get; set; } public Partial Visibility { get; set; } public Partial NamePrivacy { get; set; } public Partial DescriptionPrivacy { get; set; } public Partial PronounPrivacy { get; set; } public Partial BirthdayPrivacy { get; set; } public Partial AvatarPrivacy { get; set; } public Partial MetadataPrivacy { get; set; } public override Query Apply(Query q) => q.ApplyPatch(wrapper => wrapper .With("name", Name) .With("hid", Hid) .With("display_name", DisplayName) .With("avatar_url", AvatarUrl) .With("banner_image", BannerImage) .With("color", Color) .With("birthday", Birthday) .With("pronouns", Pronouns) .With("description", Description) .With("proxy_tags", ProxyTags) .With("keep_proxy", KeepProxy) .With("message_count", MessageCount) .With("allow_autoproxy", AllowAutoproxy) .With("member_visibility", Visibility) .With("name_privacy", NamePrivacy) .With("description_privacy", DescriptionPrivacy) .With("pronoun_privacy", PronounPrivacy) .With("birthday_privacy", BirthdayPrivacy) .With("avatar_privacy", AvatarPrivacy) .With("metadata_privacy", MetadataPrivacy) ); public new void AssertIsValid() { if (Name.Value != null) AssertValid(Name.Value, "name", Limits.MaxMemberNameLength); if (DisplayName.Value != null) AssertValid(DisplayName.Value, "display_name", Limits.MaxMemberNameLength); if (AvatarUrl.Value != null) AssertValid(AvatarUrl.Value, "avatar_url", Limits.MaxUriLength, s => MiscUtils.TryMatchUri(s, out var avatarUri)); if (BannerImage.Value != null) AssertValid(BannerImage.Value, "banner", Limits.MaxUriLength, s => MiscUtils.TryMatchUri(s, out var bannerUri)); if (Color.Value != null) AssertValid(Color.Value, "color", "^[0-9a-fA-F]{6}$"); if (Pronouns.Value != null) AssertValid(Pronouns.Value, "pronouns", Limits.MaxPronounsLength); if (Description.Value != null) AssertValid(Description.Value, "description", Limits.MaxDescriptionLength); if (ProxyTags.IsPresent && (ProxyTags.Value.Length > 100 || ProxyTags.Value.Any(tag => tag.ProxyString.IsLongerThan(100)))) // todo: have a better error for this Errors.Add(new ValidationError("proxy_tags")); } #nullable disable public static MemberPatch FromJSON(JObject o, bool isImport = false) { var patch = new MemberPatch(); if (o.ContainsKey("name")) { patch.Name = o.Value("name").NullIfEmpty(); if (patch.Name.Value == null) patch.Errors.Add(new ValidationError("name", "Member name can not be set to null.")); } if (o.ContainsKey("name")) patch.Name = o.Value("name"); if (o.ContainsKey("color")) patch.Color = o.Value("color").NullIfEmpty()?.ToLower(); if (o.ContainsKey("display_name")) patch.DisplayName = o.Value("display_name").NullIfEmpty(); if (o.ContainsKey("avatar_url")) patch.AvatarUrl = o.Value("avatar_url").NullIfEmpty(); if (o.ContainsKey("banner")) patch.BannerImage = o.Value("banner").NullIfEmpty(); 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 patch.Errors.Add(new ValidationError("birthday")); } if (o.ContainsKey("pronouns")) patch.Pronouns = o.Value("pronouns").NullIfEmpty(); if (o.ContainsKey("description")) patch.Description = o.Value("description").NullIfEmpty(); if (o.ContainsKey("keep_proxy")) patch.KeepProxy = o.Value("keep_proxy"); if (isImport) { // legacy: used in old export files if (o.ContainsKey("prefix") || o.ContainsKey("suffix") && !o.ContainsKey("proxy_tags")) patch.ProxyTags = new[] { new ProxyTag(o.Value("prefix"), o.Value("suffix")) }; if (o.ContainsKey("visibility")) patch.Visibility = patch.ParsePrivacy(o, "visibility"); if (o.ContainsKey("name_privacy")) patch.NamePrivacy = patch.ParsePrivacy(o, "name_privacy"); if (o.ContainsKey("description_privacy")) patch.DescriptionPrivacy = patch.ParsePrivacy(o, "description_privacy"); if (o.ContainsKey("avatar_privacy")) patch.AvatarPrivacy = patch.ParsePrivacy(o, "avatar_privacy"); if (o.ContainsKey("birthday_privacy")) patch.BirthdayPrivacy = patch.ParsePrivacy(o, "birthday_privacy"); if (o.ContainsKey("pronoun_privacy")) patch.PronounPrivacy = patch.ParsePrivacy(o, "pronoun_privacy"); if (o.ContainsKey("metadata_privacy")) patch.MetadataPrivacy = patch.ParsePrivacy(o, "metadata_privacy"); } if (o.ContainsKey("proxy_tags")) patch.ProxyTags = o.Value("proxy_tags") .OfType().Select(o => new ProxyTag(o.Value("prefix"), o.Value("suffix"))) .Where(p => p.Valid) .ToArray(); if (o.ContainsKey("privacy") && o["privacy"].Type == JTokenType.Object) { var privacy = o.Value("privacy"); if (privacy.ContainsKey("visibility")) patch.Visibility = patch.ParsePrivacy(privacy, "visibility"); if (privacy.ContainsKey("name_privacy")) patch.NamePrivacy = patch.ParsePrivacy(privacy, "name_privacy"); if (privacy.ContainsKey("description_privacy")) patch.DescriptionPrivacy = patch.ParsePrivacy(privacy, "description_privacy"); if (privacy.ContainsKey("avatar_privacy")) patch.AvatarPrivacy = patch.ParsePrivacy(privacy, "avatar_privacy"); if (privacy.ContainsKey("birthday_privacy")) patch.BirthdayPrivacy = patch.ParsePrivacy(privacy, "birthday_privacy"); if (privacy.ContainsKey("pronoun_privacy")) patch.PronounPrivacy = patch.ParsePrivacy(privacy, "pronoun_privacy"); if (privacy.ContainsKey("metadata_privacy")) patch.MetadataPrivacy = patch.ParsePrivacy(privacy, "metadata_privacy"); } return patch; } public JObject ToJson() { var o = new JObject(); if (Name.IsPresent) o.Add("name", Name.Value); if (Hid.IsPresent) o.Add("id", Hid.Value); if (DisplayName.IsPresent) o.Add("display_name", DisplayName.Value); if (AvatarUrl.IsPresent) o.Add("avatar_url", AvatarUrl.Value); if (BannerImage.IsPresent) o.Add("banner", BannerImage.Value); if (Color.IsPresent) o.Add("color", Color.Value); if (Birthday.IsPresent) o.Add("birthday", Birthday.Value?.FormatExport()); if (Pronouns.IsPresent) o.Add("pronouns", Pronouns.Value); if (Description.IsPresent) o.Add("description", Description.Value); if (ProxyTags.IsPresent) { var tagArray = new JArray(); foreach (var tag in ProxyTags.Value) tagArray.Add(new JObject { { "prefix", tag.Prefix }, { "suffix", tag.Suffix } }); o.Add("proxy_tags", tagArray); } if (KeepProxy.IsPresent) o.Add("keep_proxy", KeepProxy.Value); if ( Visibility.IsPresent || NamePrivacy.IsPresent || DescriptionPrivacy.IsPresent || PronounPrivacy.IsPresent || BirthdayPrivacy.IsPresent || AvatarPrivacy.IsPresent || MetadataPrivacy.IsPresent ) { var p = new JObject(); if (Visibility.IsPresent) p.Add("visibility", Visibility.Value.ToJsonString()); if (NamePrivacy.IsPresent) p.Add("name_privacy", NamePrivacy.Value.ToJsonString()); if (DescriptionPrivacy.IsPresent) p.Add("description_privacy", DescriptionPrivacy.Value.ToJsonString()); if (PronounPrivacy.IsPresent) p.Add("pronoun_privacy", PronounPrivacy.Value.ToJsonString()); if (BirthdayPrivacy.IsPresent) p.Add("birthday_privacy", BirthdayPrivacy.Value.ToJsonString()); if (AvatarPrivacy.IsPresent) p.Add("avatar_privacy", AvatarPrivacy.Value.ToJsonString()); if (MetadataPrivacy.IsPresent) p.Add("metadata_privacy", MetadataPrivacy.Value.ToJsonString()); o.Add("privacy", p); } return o; } }