397da2e1fa
A given system can now have up to 1000 members. Within 50 members of that limit, a warning will display whenever a new member is created via the bot. Once the limit is reached, a final warning will appear indicating that no additional members can be created unless members are first deleted. Attempting to create a new member at that point by any method will result in an error message indicating that the limit has been reached. Respecting this in pk;import required some restructuring to tease apart which members already exist and which ones need to be created prior to creating any members as it seems preferable to fail early and give the user the ability to intervene rather than pushing the system to the member cap and requiring manual deletion of "lower priority" members before others can be created. One consequence of the restructure is that existing members are being read in bulk which is a performance improvement of 25-70% depending on how many switches need to be imported (the more members you have, the more noticeable this is).
139 lines
6.1 KiB
C#
139 lines
6.1 KiB
C#
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using PluralKit.Core;
|
|
|
|
namespace PluralKit.API.Controllers
|
|
{
|
|
[ApiController]
|
|
[Route("m")]
|
|
[Route("v1/m")]
|
|
public class MemberController: ControllerBase
|
|
{
|
|
private MemberStore _members;
|
|
private DbConnectionFactory _conn;
|
|
private TokenAuthService _auth;
|
|
|
|
public MemberController(MemberStore members, DbConnectionFactory conn, TokenAuthService auth)
|
|
{
|
|
_members = members;
|
|
_conn = conn;
|
|
_auth = auth;
|
|
}
|
|
|
|
[HttpGet("{hid}")]
|
|
public async Task<ActionResult<PKMember>> GetMember(string hid)
|
|
{
|
|
var member = await _members.GetByHid(hid);
|
|
if (member == null) return NotFound("Member not found.");
|
|
|
|
return Ok(member);
|
|
}
|
|
|
|
[HttpPost]
|
|
[RequiresSystem]
|
|
public async Task<ActionResult<PKMember>> PostMember([FromBody] PKMember newMember)
|
|
{
|
|
var system = _auth.CurrentSystem;
|
|
|
|
if (newMember.Name == null)
|
|
return BadRequest("Member name cannot be null.");
|
|
|
|
// Enforce per-system member limit
|
|
var memberCount = await _members.MemberCount(system);
|
|
if (memberCount >= Limits.MaxMemberCount)
|
|
return BadRequest($"Member limit reached ({memberCount} / {Limits.MaxMemberCount}).");
|
|
|
|
// Explicit bounds checks
|
|
if (newMember.Name != null && newMember.Name.Length > Limits.MaxMemberNameLength)
|
|
return BadRequest($"Member name too long ({newMember.Name.Length} > {Limits.MaxMemberNameLength}.");
|
|
if (newMember.DisplayName != null && newMember.DisplayName.Length > Limits.MaxMemberNameLength)
|
|
return BadRequest($"Member display name too long ({newMember.DisplayName.Length} > {Limits.MaxMemberNameLength}.");
|
|
if (newMember.Pronouns != null && newMember.Pronouns.Length > Limits.MaxPronounsLength)
|
|
return BadRequest($"Member pronouns too long ({newMember.Pronouns.Length} > {Limits.MaxPronounsLength}.");
|
|
if (newMember.Description != null && newMember.Description.Length > Limits.MaxDescriptionLength)
|
|
return BadRequest($"Member descriptions too long ({newMember.Description.Length} > {Limits.MaxDescriptionLength}.");
|
|
|
|
// Sanity bounds checks
|
|
if (newMember.AvatarUrl != null && newMember.AvatarUrl.Length > 1000)
|
|
return BadRequest();
|
|
if (newMember.Prefix != null && newMember.Prefix.Length > 1000)
|
|
return BadRequest();
|
|
if (newMember.Suffix != null && newMember.Suffix.Length > 1000)
|
|
return BadRequest();
|
|
|
|
var member = await _members.Create(system, newMember.Name);
|
|
|
|
member.Name = newMember.Name;
|
|
member.DisplayName = newMember.DisplayName;
|
|
member.Color = newMember.Color;
|
|
member.AvatarUrl = newMember.AvatarUrl;
|
|
member.Birthday = newMember.Birthday;
|
|
member.Pronouns = newMember.Pronouns;
|
|
member.Description = newMember.Description;
|
|
member.Prefix = newMember.Prefix;
|
|
member.Suffix = newMember.Suffix;
|
|
await _members.Save(member);
|
|
|
|
return Ok(member);
|
|
}
|
|
|
|
[HttpPatch("{hid}")]
|
|
[RequiresSystem]
|
|
public async Task<ActionResult<PKMember>> PatchMember(string hid, [FromBody] PKMember newMember)
|
|
{
|
|
var member = await _members.GetByHid(hid);
|
|
if (member == null) return NotFound("Member not found.");
|
|
|
|
if (member.System != _auth.CurrentSystem.Id) return Unauthorized($"Member '{hid}' is not part of your system.");
|
|
|
|
if (newMember.Name == null)
|
|
return BadRequest("Member name can not be null.");
|
|
|
|
// Explicit bounds checks
|
|
if (newMember.Name != null && newMember.Name.Length > Limits.MaxMemberNameLength)
|
|
return BadRequest($"Member name too long ({newMember.Name.Length} > {Limits.MaxMemberNameLength}.");
|
|
if (newMember.DisplayName != null && newMember.DisplayName.Length > Limits.MaxMemberNameLength)
|
|
return BadRequest($"Member display name too long ({newMember.DisplayName.Length} > {Limits.MaxMemberNameLength}.");
|
|
if (newMember.Pronouns != null && newMember.Pronouns.Length > Limits.MaxPronounsLength)
|
|
return BadRequest($"Member pronouns too long ({newMember.Pronouns.Length} > {Limits.MaxPronounsLength}.");
|
|
if (newMember.Description != null && newMember.Description.Length > Limits.MaxDescriptionLength)
|
|
return BadRequest($"Member descriptions too long ({newMember.Description.Length} > {Limits.MaxDescriptionLength}.");
|
|
|
|
// Sanity bounds checks
|
|
if (newMember.AvatarUrl != null && newMember.AvatarUrl.Length > 1000)
|
|
return BadRequest();
|
|
if (newMember.Prefix != null && newMember.Prefix.Length > 1000)
|
|
return BadRequest();
|
|
if (newMember.Suffix != null && newMember.Suffix.Length > 1000)
|
|
return BadRequest();
|
|
|
|
member.Name = newMember.Name;
|
|
member.DisplayName = newMember.DisplayName;
|
|
member.Color = newMember.Color;
|
|
member.AvatarUrl = newMember.AvatarUrl;
|
|
member.Birthday = newMember.Birthday;
|
|
member.Pronouns = newMember.Pronouns;
|
|
member.Description = newMember.Description;
|
|
member.Prefix = newMember.Prefix;
|
|
member.Suffix = newMember.Suffix;
|
|
await _members.Save(member);
|
|
|
|
return Ok(member);
|
|
}
|
|
|
|
[HttpDelete("{hid}")]
|
|
[RequiresSystem]
|
|
public async Task<ActionResult<PKMember>> DeleteMember(string hid)
|
|
{
|
|
var member = await _members.GetByHid(hid);
|
|
if (member == null) return NotFound("Member not found.");
|
|
|
|
if (member.System != _auth.CurrentSystem.Id) return Unauthorized($"Member '{hid}' is not part of your system.");
|
|
|
|
await _members.Delete(member);
|
|
|
|
return Ok();
|
|
}
|
|
}
|
|
}
|