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 there's already a member by this name var existingMember = await _db.Execute(c => _repo.GetMemberByName(c, ctx.System.Id, memberName)); if (existingMember != null) { var msg = $"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.NameFor(ctx)}\" (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."); } } await using var conn = await _db.Obtain(); // Enforce per-system member limit var memberCount = await _repo.GetSystemMemberCount(conn, ctx.System.Id); var memberLimit = ctx.System.MemberLimitOverride ?? Limits.MaxMemberCount; if (memberCount >= memberLimit) { throw Errors.MemberLimitReachedError(memberLimit); } // Create the member var member = await _repo.CreateMember(conn, ctx.System.Id, memberName); memberCount++; // Send confirmation and space hint await ctx.Reply($"{Emojis.Success} Member \"{memberName}\" (`{member.Hid}`) registered! Check out the getting started page for how to get a member up and running: https://pluralkit.me/start#members"); 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."); } }
public async Task <ActionResult <JObject> > PostMember([FromBody] JObject properties) { if (!properties.ContainsKey("name")) { return(BadRequest("Member name must be specified.")); } var systemId = User.CurrentSystem(); await using var conn = await _db.Obtain(); var systemData = await _repo.GetSystem(conn, systemId); // Enforce per-system member limit var memberCount = await conn.QuerySingleAsync <int>("select count(*) from members where system = @System", new { System = systemId }); var memberLimit = systemData?.MemberLimitOverride ?? Limits.MaxMemberCount; if (memberCount >= memberLimit) { return(BadRequest($"Member limit reached ({memberCount} / {memberLimit}).")); } await using var tx = await conn.BeginTransactionAsync(); var member = await _repo.CreateMember(conn, systemId, properties.Value <string>("name"), transaction : tx); MemberPatch patch; try { patch = JsonModelExt.ToMemberPatch(properties); patch.CheckIsValid(); } catch (JsonModelParseError e) { await tx.RollbackAsync(); return(BadRequest(e.Message)); } catch (InvalidPatchException e) { await tx.RollbackAsync(); return(BadRequest($"Request field '{e.Message}' is invalid.")); } member = await _repo.UpdateMember(conn, member.Id, patch, transaction : tx); await tx.CommitAsync(); return(Ok(member.ToJson(User.ContextFor(member)))); }
public async Task <ActionResult <JObject> > PostMember([FromBody] JObject properties) { if (!properties.ContainsKey("name")) { return(BadRequest("Member name must be specified.")); } var systemId = User.CurrentSystem(); var config = await _repo.GetSystemConfig(systemId); await using var conn = await _db.Obtain(); // Enforce per-system member limit var memberCount = await conn.QuerySingleAsync <int>("select count(*) from members where system = @System", new { System = systemId }); var memberLimit = config.MemberLimitOverride ?? Limits.MaxMemberCount; if (memberCount >= memberLimit) { return(BadRequest($"Member limit reached ({memberCount} / {memberLimit}).")); } await using var tx = await conn.BeginTransactionAsync(); var member = await _repo.CreateMember(systemId, properties.Value <string>("name"), conn); var patch = MemberPatch.FromJSON(properties); patch.AssertIsValid(); if (patch.Errors.Count > 0) { await tx.RollbackAsync(); var err = patch.Errors[0]; if (err is FieldTooLongError) { return(BadRequest($"Field {err.Key} is too long " + $"({(err as FieldTooLongError).ActualLength} > {(err as FieldTooLongError).MaxLength}).")); } if (err.Text != null) { return(BadRequest(err.Text)); } return(BadRequest($"Field {err.Key} is invalid.")); } member = await _repo.UpdateMember(member.Id, patch, conn); await tx.CommitAsync(); return(Ok(member.ToJson(User.ContextFor(member), true))); }
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 there's already a member by this name var existingMember = await _db.Execute(c => _repo.GetMemberByName(c, ctx.System.Id, memberName)); if (existingMember != null) { var msg = $"{Emojis.Warn} You already have a member in your system with the name \"{existingMember.NameFor(ctx)}\" (with ID `{existingMember.Hid}`). Do you want to create another member with the same name?"; if (!await ctx.PromptYesNo(msg, "Create")) { throw new PKError("Member creation cancelled."); } } await using var conn = await _db.Obtain(); // Enforce per-system member limit var memberCount = await _repo.GetSystemMemberCount(conn, ctx.System.Id); var memberLimit = ctx.System.MemberLimitOverride ?? Limits.MaxMemberCount; if (memberCount >= memberLimit) { throw Errors.MemberLimitReachedError(memberLimit); } // Create the member var member = await _repo.CreateMember(conn, ctx.System.Id, memberName); memberCount++; // Try to match an image attached to the message var avatarArg = ctx.Message.Attachments.FirstOrDefault(); Exception imageMatchError = null; if (avatarArg != null) { try { await AvatarUtils.VerifyAvatarOrThrow(avatarArg.Url); await _db.Execute(conn => _repo.UpdateMember(conn, member.Id, new MemberPatch { AvatarUrl = avatarArg.Url })); } catch (Exception e) { imageMatchError = e; } } // Send confirmation and space hint await ctx.Reply($"{Emojis.Success} Member \"{memberName}\" (`{member.Hid}`) registered! Check out the getting started page for how to get a member up and running: https://pluralkit.me/start#create-a-member"); if (await _db.Execute(conn => conn.QuerySingleAsync <bool>("select has_private_members(@System)", new { System = ctx.System.Id }))) //if has private members { await ctx.Reply($"{Emojis.Warn} This member is currently **public**. To change this, use `pk;member {member.Hid} private`."); } if (avatarArg != null) { if (imageMatchError == null) { await ctx.Reply($"{Emojis.Success} Member avatar set to attached image.\n{Emojis.Warn} If you delete the message containing the attachment, the avatar will stop working."); } else { await ctx.Reply($"{Emojis.Error} Couldn't set avatar: {imageMatchError.Message}"); } } 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 >= memberLimit) { await ctx.Reply($"{Emojis.Warn} You have reached the per-system member limit ({memberLimit}). You will be unable to create additional members until existing members are deleted."); } else if (memberCount >= Limits.MaxMembersWarnThreshold(memberLimit)) { await ctx.Reply($"{Emojis.Warn} You are approaching the per-system member limit ({memberCount} / {memberLimit} members). Please review your member list for unused or duplicate members."); } }