feat(api): migrar controllers admin a RequirePermission [UDT-006]
This commit is contained in:
@@ -130,7 +130,7 @@ public sealed class PermisosEndpointTests : IAsyncLifetime
|
||||
// ── GET /api/v1/permisos — catalog ───────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task GetPermisos_WithAdmin_Returns200With18Items()
|
||||
public async Task GetPermisos_WithAdmin_Returns200With21Items()
|
||||
{
|
||||
var token = await GetBearerTokenAsync(AdminUsername, AdminPassword);
|
||||
using var req = BuildRequest(HttpMethod.Get, "/api/v1/permisos", bearerToken: token);
|
||||
@@ -138,7 +138,8 @@ public sealed class PermisosEndpointTests : IAsyncLifetime
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
var list = await resp.Content.ReadFromJsonAsync<JsonElement>();
|
||||
Assert.Equal(18, list.GetArrayLength());
|
||||
// V007 (UDT-006) adds 3 new admin permisos → 21 total
|
||||
Assert.Equal(21, list.GetArrayLength());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -181,7 +182,7 @@ public sealed class PermisosEndpointTests : IAsyncLifetime
|
||||
// ── GET /api/v1/roles/{codigo}/permisos ──────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task GetRolPermisos_AdminRol_Returns200With18Items()
|
||||
public async Task GetRolPermisos_AdminRol_Returns200With21Items()
|
||||
{
|
||||
var token = await GetBearerTokenAsync(AdminUsername, AdminPassword);
|
||||
using var req = BuildRequest(HttpMethod.Get, "/api/v1/roles/admin/permisos", bearerToken: token);
|
||||
@@ -189,7 +190,8 @@ public sealed class PermisosEndpointTests : IAsyncLifetime
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
|
||||
var list = await resp.Content.ReadFromJsonAsync<JsonElement>();
|
||||
Assert.Equal(18, list.GetArrayLength());
|
||||
// V007 (UDT-006) adds 3 new admin permisos → 21 total
|
||||
Assert.Equal(21, list.GetArrayLength());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -424,4 +426,63 @@ public sealed class PermisosEndpointTests : IAsyncLifetime
|
||||
await DeleteUsuarioIfExistsAsync(username);
|
||||
}
|
||||
}
|
||||
|
||||
// ── UDT-006: 403 ProblemDetails shape ─────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task GetPermisos_WithCajeroToken_Returns403WithProblemDetailsShape()
|
||||
{
|
||||
const string username = "udt006_permisos_403_cajero";
|
||||
try
|
||||
{
|
||||
var token = await CreateNonAdminUserAndGetTokenAsync(username);
|
||||
using var req = BuildRequest(HttpMethod.Get, "/api/v1/permisos", bearerToken: token);
|
||||
var resp = await _client.SendAsync(req);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Forbidden, resp.StatusCode);
|
||||
Assert.Contains("problem+json", resp.Content.Headers.ContentType?.MediaType ?? "");
|
||||
|
||||
var json = await resp.Content.ReadFromJsonAsync<JsonElement>();
|
||||
Assert.Equal(403, json.GetProperty("status").GetInt32());
|
||||
Assert.Equal("Acceso denegado", json.GetProperty("title").GetString());
|
||||
Assert.True(json.TryGetProperty("permisoRequerido", out var perm),
|
||||
"Response must contain 'permisoRequerido'");
|
||||
// GET /permisos migra a administracion:permisos:ver
|
||||
Assert.Equal("administracion:permisos:ver", perm.GetString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
await DeleteUsuarioIfExistsAsync(username);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PutRolPermisos_WithCajeroToken_Returns403WithProblemDetailsShape()
|
||||
{
|
||||
const string username = "udt006_put_permisos_403";
|
||||
try
|
||||
{
|
||||
var token = await CreateNonAdminUserAndGetTokenAsync(username);
|
||||
using var req = BuildRequest(
|
||||
HttpMethod.Put,
|
||||
"/api/v1/roles/cajero/permisos",
|
||||
new { codigos = new[] { "ventas:contado:crear" } },
|
||||
token);
|
||||
var resp = await _client.SendAsync(req);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Forbidden, resp.StatusCode);
|
||||
Assert.Contains("problem+json", resp.Content.Headers.ContentType?.MediaType ?? "");
|
||||
|
||||
var json = await resp.Content.ReadFromJsonAsync<JsonElement>();
|
||||
Assert.Equal(403, json.GetProperty("status").GetInt32());
|
||||
Assert.True(json.TryGetProperty("permisoRequerido", out var perm),
|
||||
"Response must contain 'permisoRequerido'");
|
||||
// PUT /roles/{c}/permisos migra a administracion:roles_permisos:gestionar
|
||||
Assert.Equal("administracion:roles_permisos:gestionar", perm.GetString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
await DeleteUsuarioIfExistsAsync(username);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,4 +350,51 @@ public sealed class RolesEndpointTests : IAsyncLifetime
|
||||
Assert.Equal(HttpStatusCode.NotFound, resp.StatusCode);
|
||||
}
|
||||
|
||||
// ── UDT-006: 403 ProblemDetails shape ────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task GetRoles_WithCajeroToken_Returns403WithProblemDetailsShape()
|
||||
{
|
||||
const string username = "udt006_roles_403_cajero";
|
||||
try
|
||||
{
|
||||
var token = await CreateCajeroTokenAsync(username);
|
||||
var resp = await _client.SendAsync(BuildRequest(HttpMethod.Get, Endpoint, bearerToken: token));
|
||||
|
||||
Assert.Equal(HttpStatusCode.Forbidden, resp.StatusCode);
|
||||
Assert.Contains("problem+json", resp.Content.Headers.ContentType?.MediaType ?? "");
|
||||
|
||||
var json = await resp.Content.ReadFromJsonAsync<JsonElement>();
|
||||
Assert.Equal(403, json.GetProperty("status").GetInt32());
|
||||
Assert.Equal("Acceso denegado", json.GetProperty("title").GetString());
|
||||
Assert.True(json.TryGetProperty("permisoRequerido", out var perm),
|
||||
"Response must contain 'permisoRequerido'");
|
||||
// RolesController migra a administracion:roles:gestionar
|
||||
Assert.Equal("administracion:roles:gestionar", perm.GetString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
await DeleteUsuarioIfExistsAsync(username);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: create cajero user via SQL and return token
|
||||
private async Task<string> CreateCajeroTokenAsync(string username)
|
||||
{
|
||||
var adminToken = await GetBearerTokenAsync(AdminUsername, AdminPassword);
|
||||
using var mkUser = BuildRequest(HttpMethod.Post, "/api/v1/users", new
|
||||
{
|
||||
username,
|
||||
password = "Secure1234!",
|
||||
nombre = "Cajero",
|
||||
apellido = "Test",
|
||||
email = (string?)null,
|
||||
rol = "cajero"
|
||||
}, adminToken);
|
||||
var mkResp = await _client.SendAsync(mkUser);
|
||||
if (mkResp.StatusCode != HttpStatusCode.Created && mkResp.StatusCode != HttpStatusCode.Conflict)
|
||||
Assert.Fail($"Seed cajero failed: {mkResp.StatusCode}");
|
||||
return await GetBearerTokenAsync(username, "Secure1234!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -388,6 +388,56 @@ public sealed class CreateUsuarioEndpointTests : IAsyncLifetime
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// UDT-006 Scenario: 403 con ProblemDetails shape — token cajero sin permiso administracion:usuarios:gestionar
|
||||
// ---------------------------------------------------------------------------
|
||||
[Fact]
|
||||
public async Task CreateUsuario_WithCajeroRole_Returns403WithProblemDetailsShape()
|
||||
{
|
||||
const string username = "udt006_403_shape_test";
|
||||
try
|
||||
{
|
||||
var token = await CreateCajeroTokenAsync(username);
|
||||
using var request = BuildRequest(HttpMethod.Post, Endpoint, ValidCreateBody("shape_target"), token);
|
||||
var response = await _client.SendAsync(request);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
|
||||
// Content-Type must be application/problem+json
|
||||
Assert.Contains("problem+json", response.Content.Headers.ContentType?.MediaType ?? "");
|
||||
|
||||
var json = await response.Content.ReadFromJsonAsync<JsonElement>();
|
||||
Assert.Equal(403, json.GetProperty("status").GetInt32());
|
||||
Assert.Equal("Acceso denegado", json.GetProperty("title").GetString());
|
||||
Assert.True(json.TryGetProperty("permisoRequerido", out var perm),
|
||||
"Response must contain 'permisoRequerido'");
|
||||
Assert.Equal("administracion:usuarios:gestionar", perm.GetString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
await DeleteUsuarioAsync(username);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: create a cajero user and return its token
|
||||
private async Task<string> CreateCajeroTokenAsync(string username)
|
||||
{
|
||||
var adminToken = await GetBearerTokenAsync(AdminUsername, AdminPassword);
|
||||
using var mkUser = BuildRequest(HttpMethod.Post, Endpoint, new
|
||||
{
|
||||
username,
|
||||
password = "Secure1234!",
|
||||
nombre = "Cajero",
|
||||
apellido = "Test",
|
||||
email = (string?)null,
|
||||
rol = "cajero"
|
||||
}, adminToken);
|
||||
var mkResp = await _client.SendAsync(mkUser);
|
||||
if (mkResp.StatusCode != HttpStatusCode.Created && mkResp.StatusCode != HttpStatusCode.Conflict)
|
||||
Assert.Fail($"Seed cajero failed: {mkResp.StatusCode}");
|
||||
return await GetBearerTokenAsync(username, "Secure1234!");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Scenario 7 (UDT-004 Phase 5.3): 400 — rol existe pero está inactivo
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user