Add support for multiple proxy tags

Tangentially closes #103.
This commit is contained in:
Ske
2019-10-28 20:15:27 +01:00
committed by Astrid
parent 96b03495a4
commit 393ee16c1b
16 changed files with 190 additions and 69 deletions

View File

@@ -37,8 +37,7 @@ namespace PluralKit.Bot
Pronouns = m.Pronouns,
Color = m.Color,
AvatarUrl = m.AvatarUrl,
Prefix = m.Prefix,
Suffix = m.Suffix,
ProxyTags = m.ProxyTags,
Created = Formats.TimestampExportFormat.Format(m.Created),
MessageCount = messageCounts.Where(x => x.Member == m.Id).Select(x => x.MessageCount).FirstOrDefault()
}));
@@ -150,8 +149,7 @@ namespace PluralKit.Bot
if (dataMember.AvatarUrl != null) member.AvatarUrl = dataMember.AvatarUrl;
if (dataMember.Prefix != null || dataMember.Suffix != null)
{
member.Prefix = dataMember.Prefix;
member.Suffix = dataMember.Suffix;
member.ProxyTags = new List<ProxyTag> { new ProxyTag(dataMember.Prefix, dataMember.Suffix) };
}
if (dataMember.Birthday != null)
@@ -223,8 +221,14 @@ namespace PluralKit.Bot
[JsonProperty("pronouns")] public string Pronouns;
[JsonProperty("color")] public string Color;
[JsonProperty("avatar_url")] public string AvatarUrl;
[JsonProperty("prefix")] public string Prefix;
[JsonProperty("suffix")] public string Suffix;
// For legacy single-tag imports
[JsonProperty("prefix")] [JsonIgnore] public string Prefix;
[JsonProperty("suffix")] [JsonIgnore] public string Suffix;
// ^ is superseded by v
[JsonProperty("proxy_tags")] public ICollection<ProxyTag> ProxyTags;
[JsonProperty("message_count")] public int MessageCount;
[JsonProperty("created")] public string Created;

View File

@@ -1,12 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Dapper.Contrib.Extensions;
using Newtonsoft.Json;
using NodaTime;
using NodaTime.Text;
using PluralKit.Core;
namespace PluralKit
{
public struct ProxyTag
{
public ProxyTag(string prefix, string suffix)
{
// Normalize empty strings to null for DB
Prefix = prefix.Length == 0 ? null : prefix;
Suffix = suffix.Length == 0 ? null : suffix;
}
[JsonProperty("prefix")] public string Prefix { get; set; }
[JsonProperty("suffix")] public string Suffix { get; set; }
[JsonIgnore] public string ProxyString => $"{Prefix ?? ""}text{Suffix ?? ""}";
public bool Equals(ProxyTag other) => Prefix == other.Prefix && Suffix == other.Suffix;
public override bool Equals(object obj) => obj is ProxyTag other && Equals(other);
public override int GetHashCode()
{
unchecked
{
return ((Prefix != null ? Prefix.GetHashCode() : 0) * 397) ^
(Suffix != null ? Suffix.GetHashCode() : 0);
}
}
}
public class PKSystem
{
// Additions here should be mirrored in SystemStore::Save
@@ -35,9 +65,22 @@ namespace PluralKit
[JsonProperty("birthday")] public LocalDate? Birthday { get; set; }
[JsonProperty("pronouns")] public string Pronouns { get; set; }
[JsonProperty("description")] public string Description { get; set; }
[JsonProperty("prefix")] public string Prefix { get; set; }
[JsonProperty("suffix")] public string Suffix { get; set; }
[JsonProperty("proxy_tags")] public ICollection<ProxyTag> ProxyTags { get; set; }
[JsonProperty("created")] public Instant Created { get; set; }
// These are deprecated as fuck, and are kinda hacky
// Don't use, unless you're the API's serialization library
[JsonProperty("prefix")] [Obsolete("Use PKMember.ProxyTags")] public string Prefix
{
get => ProxyTags.FirstOrDefault().Prefix;
set => ProxyTags = new[] {new ProxyTag(Prefix, value)};
}
[JsonProperty("suffix")] [Obsolete("Use PKMember.ProxyTags")] public string Suffix
{
get => ProxyTags.FirstOrDefault().Prefix;
set => ProxyTags = new[] {new ProxyTag(Prefix, value)};
}
/// Returns a formatted string representing the member's birthday, taking into account that a year of "0001" is hidden
[JsonIgnore] public string BirthdayString
@@ -52,9 +95,7 @@ namespace PluralKit
}
}
[JsonIgnore] public bool HasProxyTags => Prefix != null || Suffix != null;
[JsonIgnore] public string ProxyString => $"{Prefix ?? ""}text{Suffix ?? ""}";
[JsonIgnore] public bool HasProxyTags => ProxyTags.Count > 0;
public string ProxyName(string systemTag)
{
if (systemTag == null) return DisplayName ?? Name;

View File

@@ -495,7 +495,7 @@ namespace PluralKit {
public async Task SaveMember(PKMember member) {
using (var conn = await _conn.Obtain())
await conn.ExecuteAsync("update members set name = @Name, display_name = @DisplayName, description = @Description, color = @Color, avatar_url = @AvatarUrl, birthday = @Birthday, pronouns = @Pronouns, prefix = @Prefix, suffix = @Suffix where id = @Id", member);
await conn.ExecuteAsync("update members set name = @Name, display_name = @DisplayName, description = @Description, color = @Color, avatar_url = @AvatarUrl, birthday = @Birthday, pronouns = @Pronouns, proxy_tags = @ProxyTags where id = @Id", member);
_logger.Information("Updated member {@Member}", member);
}

View File

@@ -310,6 +310,9 @@ namespace PluralKit
// So we add a custom type handler that literally just passes the type through to Npgsql
SqlMapper.AddTypeHandler(new PassthroughTypeHandler<Instant>());
SqlMapper.AddTypeHandler(new PassthroughTypeHandler<LocalDate>());
// Add global type mapper for ProxyTag compound type in Postgres
NpgsqlConnection.GlobalTypeMapper.MapComposite<ProxyTag>("proxy_tag");
}
public static ILogger InitLogger(CoreConfig config, string component)

View File

@@ -1,3 +1,12 @@
-- Create proxy_tag compound type if it doesn't exist
do $$ begin
create type proxy_tag as (
prefix text,
suffix text
);
exception when duplicate_object then null;
end $$;
create table if not exists systems
(
id serial primary key,
@@ -23,8 +32,7 @@ create table if not exists members
birthday date,
pronouns text,
description text,
prefix text,
suffix text,
proxy_tags proxy_tag[] not null default array[], -- Rationale on making this an array rather than a separate table - we never need to query them individually, only access them as part of a selected Member struct
created timestamp not null default (current_timestamp at time zone 'utc')
);