public async Task <PKMember> PeekMember() { var input = PeekArgument(); // Member references can have one or two forms, depending on // whether you're in a system or not: // - A member hid // - A textual name of a member *in your own system* // First, try member HID parsing: if (await _members.GetByHid(input) is PKMember memberByHid) { return(memberByHid); } // Then, if we have a system, try finding by member name in system if (_senderSystem != null && await _members.GetByName(_senderSystem, input) is PKMember memberByName) { return(memberByName); } // We didn't find anything, so we return null. return(null); }
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>() }; // If we don't already have a system to save to, create one if (system == null) { system = await _systems.Create(data.Name); } // 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 _systems.Save(system); // Make sure to link the sender account, too await _systems.Link(system, accountId); // Apply members // TODO: parallelize? foreach (var dataMember in data.Members) { // If member's given an ID, we try to look up the member with the given ID PKMember member = null; if (dataMember.Id != null) { member = await _members.GetByHid(dataMember.Id); // ...but if it's a different system's member, we just make a new one anyway if (member != null && member.System != system.Id) { member = null; } } // Try to look up by name, too if (member == null) { member = await _members.GetByName(system, dataMember.Name); } // And if all else fails (eg. fresh import from Tupperbox, etc) we just make a member lol if (member == null) { member = await _members.Create(system, dataMember.Name); result.AddedNames.Add(dataMember.Name); } else { result.ModifiedNames.Add(dataMember.Name); } // Apply member info member.Name = dataMember.Name; if (dataMember.Description != null) { member.Description = dataMember.Description; } if (dataMember.Color != null) { member.Color = dataMember.Color; } if (dataMember.AvatarUrl != null) { member.AvatarUrl = dataMember.AvatarUrl; } if (dataMember.Prefix != null || dataMember.Suffix != null) { member.Prefix = dataMember.Prefix; member.Suffix = dataMember.Suffix; } if (dataMember.Birthday != null) { var birthdayParse = Formats.DateExportFormat.Parse(dataMember.Birthday); member.Birthday = birthdayParse.Success ? (LocalDate?)birthdayParse.Value : null; } await _members.Save(member); } _logger.Information("Imported system {System}", system.Id); // TODO: import switches, too? result.System = system; return(result); }
public async Task NewMember(Context ctx) { if (ctx.System == null) { throw Errors.NoSystemError; } var memberName = ctx.RemainderOrNull() ?? throw new PKSyntaxError("You must pass a member name."); // Hard name length cap if (memberName.Length > Limits.MaxMemberNameLength) { throw Errors.MemberNameTooLongError(memberName.Length); } // Warn if member name will be unproxyable (with/without tag) if (memberName.Length > ctx.System.MaxMemberNameLength) { var msg = await ctx.Reply($"{Emojis.Warn} Member name too long ({memberName.Length} > {ctx.System.MaxMemberNameLength} characters), this member will be unproxyable. Do you want to create it anyway? (You can change the name later, or set a member display name)"); if (!await ctx.PromptYesNo(msg)) { throw new PKError("Member creation cancelled."); } } // Warn if there's already a member by this name var existingMember = await _members.GetByName(ctx.System, memberName); if (existingMember != null) { var msg = await ctx.Reply($"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.Name.SanitizeMentions()}\" (with ID `{existingMember.Hid}`). Do you want to create another member with the same name?"); if (!await ctx.PromptYesNo(msg)) { throw new PKError("Member creation cancelled."); } } // Enforce per-system member limit var memberCount = await _members.MemberCount(ctx.System); if (memberCount >= Limits.MaxMemberCount) { throw Errors.MemberLimitReachedError; } // Create the member var member = await _members.Create(ctx.System, memberName); memberCount++; // Send confirmation and space hint await ctx.Reply($"{Emojis.Success} Member \"{memberName.SanitizeMentions()}\" (`{member.Hid}`) registered! See the user guide for commands for editing this member: https://pluralkit.me/guide#member-management"); if (memberName.Contains(" ")) { await ctx.Reply($"{Emojis.Note} Note that this member's name contains spaces. You will need to surround it with \"double quotes\" when using commands referring to it, or just use the member's 5-character ID (which is `{member.Hid}`)."); } if (memberCount >= Limits.MaxMemberCount) { await ctx.Reply($"{Emojis.Warn} You have reached the per-system member limit ({Limits.MaxMemberCount}). You will be unable to create additional members until existing members are deleted."); } else if (memberCount >= Limits.MaxMembersWarnThreshold) { await ctx.Reply($"{Emojis.Warn} You are approaching the per-system member limit ({memberCount} / {Limits.MaxMemberCount} members). Please review your member list for unused or duplicate members."); } await _proxyCache.InvalidateResultsForSystem(ctx.System); }