feat(backend): limit total members per user

This commit is contained in:
sam 2024-09-30 21:44:41 +02:00
parent 80ac16694c
commit 4002893323
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
3 changed files with 21 additions and 4 deletions

View file

@ -41,6 +41,8 @@ public class MembersController(
return Ok(memberRenderer.RenderMember(member, CurrentToken)); return Ok(memberRenderer.RenderMember(member, CurrentToken));
} }
public const int MaxMemberCount = 500;
[HttpPost("/api/v2/users/@me/members")] [HttpPost("/api/v2/users/@me/members")]
[ProducesResponseType<MemberRendererService.MemberResponse>(StatusCodes.Status200OK)] [ProducesResponseType<MemberRendererService.MemberResponse>(StatusCodes.Status200OK)]
[Authorize("member.create")] [Authorize("member.create")]
@ -58,6 +60,10 @@ public class MembersController(
.. ValidationUtils.ValidateLinks(req.Links) .. ValidationUtils.ValidateLinks(req.Links)
]); ]);
var memberCount = await db.Members.CountAsync(m => m.UserId == CurrentUser.Id, ct);
if (memberCount >= MaxMemberCount)
throw new ApiError.BadRequest("Maximum number of members reached");
var member = new Member var member = new Member
{ {
Id = snowflakeGenerator.GenerateSnowflake(), Id = snowflakeGenerator.GenerateSnowflake(),

View file

@ -1,3 +1,4 @@
using Foxnouns.Backend.Utils;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Foxnouns.Backend.Controllers; namespace Foxnouns.Backend.Controllers;
@ -18,14 +19,22 @@ public class MetaController : ApiControllerBase
(int)FoxnounsMetrics.UsersActiveMonthCount.Value, (int)FoxnounsMetrics.UsersActiveMonthCount.Value,
(int)FoxnounsMetrics.UsersActiveWeekCount.Value, (int)FoxnounsMetrics.UsersActiveWeekCount.Value,
(int)FoxnounsMetrics.UsersActiveDayCount.Value (int)FoxnounsMetrics.UsersActiveDayCount.Value
)) ),
new Limits(
MemberCount: MembersController.MaxMemberCount,
BioLength: ValidationUtils.MaxBioLength))
); );
} }
[HttpGet("/api/v2/coffee")] [HttpGet("/api/v2/coffee")]
public IActionResult BrewCoffee() => Problem("Sorry, I'm a teapot!", statusCode: StatusCodes.Status418ImATeapot); public IActionResult BrewCoffee() => Problem("Sorry, I'm a teapot!", statusCode: StatusCodes.Status418ImATeapot);
private record MetaResponse(string Repository, string Version, string Hash, int Members, UserInfo Users); private record MetaResponse(string Repository, string Version, string Hash, int Members, UserInfo Users, Limits Limits);
private record UserInfo(int Total, int ActiveMonth, int ActiveWeek, int ActiveDay); private record UserInfo(int Total, int ActiveMonth, int ActiveWeek, int ActiveDay);
// All limits that the frontend should know about (for UI purposes)
private record Limits(
int MemberCount,
int BioLength);
} }

View file

@ -127,12 +127,14 @@ public static class ValidationUtils
return errors; return errors;
} }
public const int MaxBioLength = 1024;
public static ValidationError? ValidateBio(string? bio) public static ValidationError? ValidateBio(string? bio)
{ {
return bio?.Length switch return bio?.Length switch
{ {
0 => ValidationError.LengthError("Bio is too short", 1, 1024, bio.Length), 0 => ValidationError.LengthError("Bio is too short", 1, MaxBioLength, bio.Length),
> 1024 => ValidationError.LengthError("Bio is too long", 1, 1024, bio.Length), > MaxBioLength => ValidationError.LengthError("Bio is too long", 1, MaxBioLength, bio.Length),
_ => null _ => null
}; };
} }