Esempio n. 1
0
        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.");
            }
        }
Esempio n. 2
0
        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))));
        }
Esempio n. 3
0
    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)));
    }
Esempio n. 4
0
        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.");
            }
        }