using System.Net; using System.Net.Http.Json; using System.Text.Json; using FluentAssertions; using foodmarket.IntegrationTests.Support; using Xunit; namespace foodmarket.IntegrationTests; [Collection(ApiCollection.Name)] public class PermissionTests { private readonly ApiFactory _factory; public PermissionTests(ApiFactory factory) => _factory = factory; [Fact] public async Task Custom_role_without_ProductsEdit_gets_403_on_put_product() { var admin = new ApiActor(_factory.CreateClient()); await admin.SignupAndLoginAsync($"permadmin-{Guid.NewGuid():N}"); // Кастомная роль: просмотр товаров, но БЕЗ права правки. var roleResp = await admin.Http.PostAsJsonAsync("/api/organization/employee-roles", new { name = $"Viewer-{Guid.NewGuid():N}", description = "view only", permissions = new { productsView = true, productsEdit = false }, }); roleResp.EnsureSuccessStatusCode(); var roleId = (await roleResp.Content.ReadFromJsonAsync()).GetProperty("id").GetString(); // Сотрудник с логином на этой роли. var empEmail = $"viewer-{Guid.NewGuid():N}@example.kz"; var empResp = await admin.Http.PostAsJsonAsync("/api/organization/employees", new { lastName = "Просмотров", firstName = "Вью", roleId, isActive = true, createAccount = true, email = empEmail, }); empResp.EnsureSuccessStatusCode(); var pwd = (await empResp.Content.ReadFromJsonAsync()).GetProperty("generatedPassword").GetString()!; var viewer = new ApiActor(_factory.CreateClient()); viewer.UseToken(await viewer.TokenAsync(empEmail, pwd)); // Авторизация проверяется до биндинга тела: несуществующий id → 403, если нет права. using var put = await viewer.Http.PutAsJsonAsync($"/api/catalog/products/{Guid.NewGuid()}", new { }); put.StatusCode.Should().Be(HttpStatusCode.Forbidden); // Чтение (ProductsView) разрешено. using var get = await viewer.Http.GetAsync("/api/catalog/products"); get.StatusCode.Should().Be(HttpStatusCode.OK); } [Fact] public async Task Admin_passes_permission_gate() { var admin = new ApiActor(_factory.CreateClient()); await admin.SignupAndLoginAsync($"permadmin2-{Guid.NewGuid():N}"); // Админ проходит permission-гейт (дальше — 404/400 на несуществующем товаре, но НЕ 403). using var put = await admin.Http.PutAsJsonAsync($"/api/catalog/products/{Guid.NewGuid()}", new { }); put.StatusCode.Should().NotBe(HttpStatusCode.Forbidden); } }