Le plafond de 5 utilisateurs existe enfin cote serveur
CreateUser ne comptait rien. Ce qui a ete livre le 12/08 dans manager-app -- compteur « X / 5 » et bouton d'ajout desactive -- est un garde-fou d'interface : un POST direct sur l'API passait toujours. Le controle est desormais fait la ou il est opposable, et rend 422. Cote front, rien a retoucher : le resultat d'invokeAPI est deja lu depuis le correctif du 409 e-mail deja pris, donc le message remontera tel quel. Deux choix, tous deux documentes dans le code : - 5 en dur. Le faire varier par plan serait une colonne sur SubscriptionPlan, qui n'en porte aucune sur les utilisateurs -- donc une migration apres le gel du schema (lot B). Dette V1 assumee. - Le SuperAdmin n'y est pas soumis. C'est la seule porte de service qui reste tant qu'aucun champ ne permet de relever la limite d'un client, et ca s'aligne sur le front, qui ne lui montre deja pas le compteur. L'inscription self-service (OnboardingController) n'est pas concernee : elle cree le premier utilisateur d'une instance neuve. 4 tests : au plafond, sous le plafond, plafond par instance, SuperAdmin exempte. dotnet test 175/175. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
805ca5cf3d
commit
a3e0b4df71
@ -157,6 +157,75 @@ namespace ManagerService.Tests.Controllers
|
||||
Assert.Null(db.Users.Single().PasswordTokenHash);
|
||||
}
|
||||
|
||||
// ── PLAFOND DE 5 UTILISATEURS ────────────────────────────────────────
|
||||
|
||||
private static void SeedUsers(MyInfoMateDbContext db, int count, string instanceId)
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
db.Users.Add(new User
|
||||
{
|
||||
Id = $"{instanceId}-u{i}",
|
||||
Email = $"{instanceId}-{i}@a.be",
|
||||
Password = "x",
|
||||
LastName = "A",
|
||||
Token = $"{instanceId}-t{i}",
|
||||
InstanceId = instanceId
|
||||
});
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateUser_AtCap_Returns422()
|
||||
{
|
||||
// Le compteur de manager-app est un garde-fou d'interface : un POST direct
|
||||
// passait toujours. C'est ce trou-là que le 422 ferme.
|
||||
using var db = DbContextFactory.Create();
|
||||
SeedUsers(db, 5, "inst-test");
|
||||
|
||||
var result = await BuildController(db, "Manager.instanceadmin").CreateUser(MakeNewUser("sixth@a.be"));
|
||||
|
||||
Assert.Equal(422, result.StatusCode);
|
||||
Assert.Equal(5, db.Users.Count(u => u.InstanceId == "inst-test"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateUser_UnderCap_Succeeds()
|
||||
{
|
||||
using var db = DbContextFactory.Create();
|
||||
SeedUsers(db, 4, "inst-test");
|
||||
|
||||
var result = await BuildController(db, "Manager.instanceadmin").CreateUser(MakeNewUser("fifth@a.be"));
|
||||
|
||||
Assert.IsType<OkObjectResult>(result);
|
||||
Assert.Equal(5, db.Users.Count(u => u.InstanceId == "inst-test"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateUser_CapIsPerInstance()
|
||||
{
|
||||
// Une autre instance pleine ne doit pas bloquer celle de l'appelant.
|
||||
using var db = DbContextFactory.Create();
|
||||
SeedUsers(db, 5, "other-inst");
|
||||
|
||||
var result = await BuildController(db, "Manager.instanceadmin").CreateUser(MakeNewUser("first@a.be"));
|
||||
|
||||
Assert.IsType<OkObjectResult>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateUser_SuperAdmin_IsNotCapped()
|
||||
{
|
||||
// Porte de service interne : tant qu'aucun champ ne permet de relever la
|
||||
// limite d'un client, le SuperAdmin doit pouvoir ajouter un siège.
|
||||
using var db = DbContextFactory.Create();
|
||||
SeedUsers(db, 5, "inst-test");
|
||||
|
||||
var result = await BuildController(db, "Manager.superadmin").CreateUser(MakeNewUser("sixth@a.be"));
|
||||
|
||||
Assert.IsType<OkObjectResult>(result);
|
||||
Assert.Equal(6, db.Users.Count(u => u.InstanceId == "inst-test"));
|
||||
}
|
||||
|
||||
// ── UPDATE ───────────────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
|
||||
@ -30,6 +30,18 @@ namespace ManagerService.Controllers
|
||||
private readonly IConfiguration _configuration;
|
||||
IHexIdGeneratorService idService = new HexIdGeneratorService();
|
||||
|
||||
/// <summary>
|
||||
/// Plafond d'utilisateurs par instance, tous plans confondus.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ⚠️ Dette assumee pour la V1 : le chiffre est en dur. Le faire varier par plan
|
||||
/// demanderait une colonne sur SubscriptionPlan, qui n'en porte aucune sur les
|
||||
/// utilisateurs, donc une migration apres le gel du schema (lot B).
|
||||
/// Le SuperAdmin n'est pas soumis au plafond : c'est la porte de service interne
|
||||
/// tant qu'aucun champ ne permet de relever la limite d'un client.
|
||||
/// </remarks>
|
||||
private const int MaxUsersPerInstance = 5;
|
||||
|
||||
public UserController(ILogger<UserController> logger, UserDatabaseService userService, ProfileLogic profileLogic, MyInfoMateDbContext myInfoMateDbContext, IEmailService emailService, IConfiguration configuration)
|
||||
{
|
||||
_logger = logger;
|
||||
@ -113,6 +125,7 @@ namespace ManagerService.Controllers
|
||||
[ProducesResponseType(typeof(UserDetailDTO), 200)]
|
||||
[ProducesResponseType(typeof(string), 400)]
|
||||
[ProducesResponseType(typeof(string), 409)]
|
||||
[ProducesResponseType(typeof(string), 422)]
|
||||
[ProducesResponseType(typeof(string), 500)]
|
||||
[HttpPost]
|
||||
public async Task<ObjectResult> CreateUser([FromBody] UserDetailDTO newUserDTO)
|
||||
@ -131,6 +144,9 @@ namespace ManagerService.Controllers
|
||||
|
||||
User newUser = new User();
|
||||
newUser.InstanceId = IsSuperAdmin() ? newUserDTO.instanceId : GetCallerInstanceId();
|
||||
|
||||
if (!IsSuperAdmin() && _myInfoMateDbContext.Users.Count(u => u.InstanceId == newUser.InstanceId) >= MaxUsersPerInstance)
|
||||
return UnprocessableEntity($"This instance has reached its limit of {MaxUsersPerInstance} users");
|
||||
newUser.Email = newUserDTO.email;
|
||||
newUser.FirstName = newUserDTO.firstName;
|
||||
newUser.LastName = newUserDTO.lastName;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user