public async Task <MemberGuildSettings> GetMemberGuildSettings(PKMember member, ulong guild) { using var conn = await _conn.Obtain(); return(await conn.QuerySingleOrDefaultAsync <MemberGuildSettings>( "select * from member_guild where member = @Member and guild = @Guild", new { Member = member.Id, Guild = guild }) ?? new MemberGuildSettings { Guild = guild, Member = member.Id }); }
public async Task SetMemberGuildSettings(PKMember member, ulong guild, MemberGuildSettings settings) { using var conn = await _conn.Obtain(); await conn.ExecuteAsync( "insert into member_guild (member, guild, display_name, avatar_url) values (@Member, @Guild, @DisplayName, @AvatarUrl) on conflict (member, guild) do update set display_name = @DisplayName, avatar_url = @AvatarUrl", settings); _logger.Information("Updated member guild settings {@MemberGuildSettings}", settings); await _cache.InvalidateSystem(member.System); }
private PKMember ConvertMember(PKSystem system, DataFileMember fileMember) { var newMember = new PKMember { Hid = fileMember.Id, System = system.Id, Name = fileMember.Name, DisplayName = fileMember.DisplayName, Description = fileMember.Description, Color = fileMember.Color, Pronouns = fileMember.Pronouns, AvatarUrl = fileMember.AvatarUrl, KeepProxy = fileMember.KeepProxy, }; if (fileMember.Prefix != null || fileMember.Suffix != null) { newMember.ProxyTags = new List <ProxyTag> { new ProxyTag(fileMember.Prefix, fileMember.Suffix) } } ; else { // Ignore proxy tags where both prefix and suffix are set to null (would be invalid anyway) newMember.ProxyTags = (fileMember.ProxyTags ?? new ProxyTag[] { }).Where(tag => !tag.IsEmpty).ToList(); } if (fileMember.Birthday != null) { var birthdayParse = DateTimeFormats.DateExportFormat.Parse(fileMember.Birthday); newMember.Birthday = birthdayParse.Success ? (LocalDate?)birthdayParse.Value : null; } return(newMember); }
public async Task AddMessage(ulong senderId, ulong messageId, ulong guildId, ulong channelId, ulong originalMessage, PKMember member) { using (var conn = await _conn.Obtain()) await conn.ExecuteAsync("insert into messages(mid, guild, channel, member, sender, original_mid) values(@MessageId, @GuildId, @ChannelId, @MemberId, @SenderId, @OriginalMid)", new { MessageId = messageId, GuildId = guildId, ChannelId = channelId, MemberId = member.Id, SenderId = senderId, OriginalMid = originalMessage }); _logger.Information("Stored message {Message} in channel {Channel}", messageId, channelId); }
public async Task <ulong> GetMemberMessageCount(PKMember member) { using (var conn = await _conn.Obtain()) return(await conn.QuerySingleAsync <ulong>("select count(*) from messages where member = @Id", member)); }
public static string NameFor(this PKMember member, LookupContext ctx) => member.NamePrivacy.Get(ctx, member.Name, member.DisplayName ?? member.Name);
public static int MessageCountFor(this PKMember member, LookupContext ctx) => member.MetadataPrivacy.Get(ctx, member.MessageCount);
public static Instant?CreatedFor(this PKMember member, LookupContext ctx) => member.MetadataPrivacy.Get(ctx, (Instant?)member.Created);
public static string PronounsFor(this PKMember member, LookupContext ctx) => member.PronounPrivacy.Get(ctx, member.Pronouns);
public static LocalDate?BirthdayFor(this PKMember member, LookupContext ctx) => member.BirthdayPrivacy.Get(ctx, member.Birthday);
public static string DescriptionFor(this PKMember member, LookupContext ctx) => member.DescriptionPrivacy.Get(ctx, member.Description);
public static string AvatarFor(this PKMember member, LookupContext ctx) => member.AvatarPrivacy.Get(ctx, member.AvatarUrl);
public async Task <ImportResult> ImportSystem(DataFileSystem data, PKSystem system, ulong accountId) { // TODO: make atomic, somehow - we'd need to obtain one IDbConnection and reuse it // which probably means refactoring SystemStore.Save and friends etc var result = new ImportResult { AddedNames = new List <string>(), ModifiedNames = new List <string>(), Success = true // Assume success unless indicated otherwise }; var dataFileToMemberMapping = new Dictionary <string, PKMember>(); var unmappedMembers = new List <DataFileMember>(); // If we don't already have a system to save to, create one if (system == null) { system = await _data.CreateSystem(data.Name); } result.System = system; // Apply system info system.Name = data.Name; if (data.Description != null) { system.Description = data.Description; } if (data.Tag != null) { system.Tag = data.Tag; } if (data.AvatarUrl != null) { system.AvatarUrl = data.AvatarUrl; } if (data.TimeZone != null) { system.UiTz = data.TimeZone ?? "UTC"; } await _data.SaveSystem(system); // Make sure to link the sender account, too await _data.AddAccount(system, accountId); // Determine which members already exist and which ones need to be created var membersByHid = new Dictionary <string, PKMember>(); var membersByName = new Dictionary <string, PKMember>(); await foreach (var member in _data.GetSystemMembers(system)) { membersByHid[member.Hid] = member; membersByName[member.Name] = member; } foreach (var d in data.Members) { PKMember match = null; if (membersByHid.TryGetValue(d.Id, out var matchByHid)) { match = matchByHid; // Try to look up the member with the given ID } else if (membersByName.TryGetValue(d.Name, out var matchByName)) { match = matchByName; // Try with the name instead } if (match != null) { dataFileToMemberMapping.Add(d.Id, match); // Relate the data file ID to the PKMember for importing switches result.ModifiedNames.Add(d.Name); } else { unmappedMembers.Add(d); // Track members that weren't found so we can create them all result.AddedNames.Add(d.Name); } } // If creating the unmatched members would put us over the member limit, abort before creating any members // new total: # in the system + (# in the file - # in the file that already exist) if (data.Members.Count - dataFileToMemberMapping.Count + membersByHid.Count > Limits.MaxMemberCount) { result.Success = false; result.Message = $"Import would exceed the maximum number of members ({Limits.MaxMemberCount})."; result.AddedNames.Clear(); result.ModifiedNames.Clear(); return(result); } // Create all unmapped members in one transaction // These consist of members from another PluralKit system or another framework (e.g. Tupperbox) var membersToCreate = new Dictionary <string, string>(); unmappedMembers.ForEach(x => membersToCreate.Add(x.Id, x.Name)); var newMembers = await _data.CreateMembersBulk(system, membersToCreate); foreach (var member in newMembers) { dataFileToMemberMapping.Add(member.Key, member.Value); } // Update members with data file properties // TODO: parallelize? foreach (var dataMember in data.Members) { dataFileToMemberMapping.TryGetValue(dataMember.Id, out PKMember member); if (member == null) { continue; } // Apply member info member.Name = dataMember.Name; if (dataMember.DisplayName != null) { member.DisplayName = dataMember.DisplayName; } if (dataMember.Description != null) { member.Description = dataMember.Description; } if (dataMember.Color != null) { member.Color = dataMember.Color.ToLower(); } if (dataMember.AvatarUrl != null) { member.AvatarUrl = dataMember.AvatarUrl; } if (dataMember.Prefix != null || dataMember.Suffix != null) { member.ProxyTags = new List <ProxyTag> { new ProxyTag(dataMember.Prefix, dataMember.Suffix) }; } else { // Ignore proxy tags where both prefix and suffix are set to null (would be invalid anyway) member.ProxyTags = (dataMember.ProxyTags ?? new ProxyTag[] { }).Where(tag => !tag.IsEmpty).ToList(); } member.KeepProxy = dataMember.KeepProxy; if (dataMember.Birthday != null) { var birthdayParse = DateTimeFormats.DateExportFormat.Parse(dataMember.Birthday); member.Birthday = birthdayParse.Success ? (LocalDate?)birthdayParse.Value : null; } await _data.SaveMember(member); } // Re-map the switch members in the likely case IDs have changed var mappedSwitches = new List <ImportedSwitch>(); foreach (var sw in data.Switches) { var timestamp = InstantPattern.ExtendedIso.Parse(sw.Timestamp).Value; var swMembers = new List <PKMember>(); swMembers.AddRange(sw.Members.Select(x => dataFileToMemberMapping.FirstOrDefault(y => y.Key.Equals(x)).Value)); mappedSwitches.Add(new ImportedSwitch { Timestamp = timestamp, Members = swMembers }); } // Import switches if (mappedSwitches.Any()) { await _data.AddSwitchesBulk(system, mappedSwitches); } _logger.Information("Imported system {System}", system.Hid); return(result); }