style(backend): apply dotnet format whitespace normalization
- Applied dotnet format to 24 files in backend/ - Corrects spacing, indentation, and formatting consistency - No functional changes to code logic Ultraworked with Sisyphus <https://github.com/code-yeongyu/oh-my-opencode> Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -56,7 +56,7 @@ public static class ShiftEndpoints
|
||||
ShiftService shiftService)
|
||||
{
|
||||
var result = await shiftService.GetShiftByIdAsync(id);
|
||||
|
||||
|
||||
if (result == null)
|
||||
return TypedResults.NotFound();
|
||||
|
||||
@@ -75,7 +75,7 @@ public static class ShiftEndpoints
|
||||
}
|
||||
|
||||
var (shift, error) = await shiftService.CreateShiftAsync(request, createdById);
|
||||
|
||||
|
||||
if (error != null || shift == null)
|
||||
return TypedResults.BadRequest(error ?? "Failed to create shift");
|
||||
|
||||
@@ -93,7 +93,7 @@ public static class ShiftEndpoints
|
||||
{
|
||||
if (error == "Shift not found")
|
||||
return TypedResults.NotFound();
|
||||
|
||||
|
||||
if (isConflict)
|
||||
return TypedResults.Conflict(error);
|
||||
}
|
||||
@@ -106,7 +106,7 @@ public static class ShiftEndpoints
|
||||
ShiftService shiftService)
|
||||
{
|
||||
var deleted = await shiftService.DeleteShiftAsync(id);
|
||||
|
||||
|
||||
if (!deleted)
|
||||
return TypedResults.NotFound();
|
||||
|
||||
@@ -130,10 +130,10 @@ public static class ShiftEndpoints
|
||||
{
|
||||
if (error == "Shift not found")
|
||||
return TypedResults.NotFound();
|
||||
|
||||
|
||||
if (error == "Cannot sign up for past shifts")
|
||||
return TypedResults.UnprocessableEntity(error);
|
||||
|
||||
|
||||
if (isConflict)
|
||||
return TypedResults.Conflict(error!);
|
||||
}
|
||||
@@ -158,7 +158,7 @@ public static class ShiftEndpoints
|
||||
{
|
||||
if (error == "Sign-up not found")
|
||||
return TypedResults.NotFound();
|
||||
|
||||
|
||||
return TypedResults.UnprocessableEntity(error!);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public static class TaskEndpoints
|
||||
TaskService taskService)
|
||||
{
|
||||
var result = await taskService.GetTaskByIdAsync(id);
|
||||
|
||||
|
||||
if (result == null)
|
||||
return TypedResults.NotFound();
|
||||
|
||||
@@ -66,7 +66,7 @@ public static class TaskEndpoints
|
||||
}
|
||||
|
||||
var (task, error) = await taskService.CreateTaskAsync(request, createdById);
|
||||
|
||||
|
||||
if (error != null || task == null)
|
||||
return TypedResults.BadRequest(error ?? "Failed to create task");
|
||||
|
||||
@@ -84,10 +84,10 @@ public static class TaskEndpoints
|
||||
{
|
||||
if (error == "Task not found")
|
||||
return TypedResults.NotFound();
|
||||
|
||||
|
||||
if (isConflict)
|
||||
return TypedResults.Conflict(error);
|
||||
|
||||
|
||||
return TypedResults.UnprocessableEntity(error);
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ public static class TaskEndpoints
|
||||
TaskService taskService)
|
||||
{
|
||||
var deleted = await taskService.DeleteTaskAsync(id);
|
||||
|
||||
|
||||
if (!deleted)
|
||||
return TypedResults.NotFound();
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ public class TenantValidationMiddleware
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.Request.Headers.TryGetValue("X-Tenant-Id", out var tenantIdHeader) ||
|
||||
if (!context.Request.Headers.TryGetValue("X-Tenant-Id", out var tenantIdHeader) ||
|
||||
string.IsNullOrWhiteSpace(tenantIdHeader))
|
||||
{
|
||||
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
|
||||
@@ -84,7 +84,7 @@ var app = builder.Build();
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
|
||||
|
||||
using var scope = app.Services.CreateScope();
|
||||
var seedService = scope.ServiceProvider.GetRequiredService<SeedDataService>();
|
||||
await seedService.SeedAsync();
|
||||
@@ -113,7 +113,7 @@ var summaries = new[]
|
||||
|
||||
app.MapGet("/weatherforecast", () =>
|
||||
{
|
||||
var forecast = Enumerable.Range(1, 5).Select(index =>
|
||||
var forecast = Enumerable.Range(1, 5).Select(index =>
|
||||
new WeatherForecast
|
||||
(
|
||||
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
|
||||
|
||||
@@ -42,7 +42,7 @@ public class MemberSyncService
|
||||
|
||||
var email = httpContext.User.FindFirst("email")?.Value ?? httpContext.User.FindFirst("preferred_username")?.Value ?? "unknown@example.com";
|
||||
var name = httpContext.User.FindFirst("name")?.Value ?? email.Split('@')[0];
|
||||
|
||||
|
||||
var roleClaim = httpContext.User.FindFirst(System.Security.Claims.ClaimTypes.Role)?.Value ?? "Member";
|
||||
var clubRole = roleClaim.ToLowerInvariant() switch
|
||||
{
|
||||
|
||||
@@ -57,7 +57,7 @@ public class ShiftService
|
||||
public async Task<ShiftDetailDto?> GetShiftByIdAsync(Guid id)
|
||||
{
|
||||
var shift = await _context.Shifts.FindAsync(id);
|
||||
|
||||
|
||||
if (shift == null)
|
||||
return null;
|
||||
|
||||
@@ -91,7 +91,7 @@ public class ShiftService
|
||||
public async Task<(ShiftDetailDto? shift, string? error)> CreateShiftAsync(CreateShiftRequest request, Guid createdById)
|
||||
{
|
||||
var tenantId = _tenantProvider.GetTenantId();
|
||||
|
||||
|
||||
var shift = new Shift
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
@@ -132,7 +132,7 @@ public class ShiftService
|
||||
public async Task<(ShiftDetailDto? shift, string? error, bool isConflict)> UpdateShiftAsync(Guid id, UpdateShiftRequest request)
|
||||
{
|
||||
var shift = await _context.Shifts.FindAsync(id);
|
||||
|
||||
|
||||
if (shift == null)
|
||||
return (null, "Shift not found", false);
|
||||
|
||||
@@ -197,7 +197,7 @@ public class ShiftService
|
||||
public async Task<bool> DeleteShiftAsync(Guid id)
|
||||
{
|
||||
var shift = await _context.Shifts.FindAsync(id);
|
||||
|
||||
|
||||
if (shift == null)
|
||||
return false;
|
||||
|
||||
@@ -212,7 +212,7 @@ public class ShiftService
|
||||
var tenantId = _tenantProvider.GetTenantId();
|
||||
|
||||
var shift = await _context.Shifts.FindAsync(shiftId);
|
||||
|
||||
|
||||
if (shift == null)
|
||||
return (false, "Shift not found", false);
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ public class TaskService
|
||||
public async Task<TaskDetailDto?> GetTaskByIdAsync(Guid id)
|
||||
{
|
||||
var workItem = await _context.WorkItems.FindAsync(id);
|
||||
|
||||
|
||||
if (workItem == null)
|
||||
return null;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class TaskService
|
||||
public async Task<(TaskDetailDto? task, string? error)> CreateTaskAsync(CreateTaskRequest request, Guid createdById)
|
||||
{
|
||||
var tenantId = _tenantProvider.GetTenantId();
|
||||
|
||||
|
||||
var workItem = new WorkItem
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
@@ -111,7 +111,7 @@ public class TaskService
|
||||
public async Task<(TaskDetailDto? task, string? error, bool isConflict)> UpdateTaskAsync(Guid id, UpdateTaskRequest request)
|
||||
{
|
||||
var workItem = await _context.WorkItems.FindAsync(id);
|
||||
|
||||
|
||||
if (workItem == null)
|
||||
return (null, "Task not found", false);
|
||||
|
||||
@@ -172,7 +172,7 @@ public class TaskService
|
||||
public async Task<bool> DeleteTaskAsync(Guid id)
|
||||
{
|
||||
var workItem = await _context.WorkItems.FindAsync(id);
|
||||
|
||||
|
||||
if (workItem == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace WorkClub.Application;
|
||||
namespace WorkClub.Application;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace WorkClub.Infrastructure;
|
||||
namespace WorkClub.Infrastructure;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ public class AppDbContext : DbContext
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
|
||||
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,11 @@ public class SaveChangesTenantInterceptor : SaveChangesInterceptor
|
||||
|
||||
private void SetTenantIdForNewEntities(DbContext? context)
|
||||
{
|
||||
if (context == null) return;
|
||||
if (context == null)
|
||||
return;
|
||||
|
||||
var tenantId = _tenantAccessor.MultiTenantContext?.TenantInfo?.Identifier;
|
||||
|
||||
|
||||
if (string.IsNullOrWhiteSpace(tenantId))
|
||||
{
|
||||
_logger.LogWarning("No tenant context available for SaveChanges");
|
||||
@@ -61,7 +62,7 @@ public class SaveChangesTenantInterceptor : SaveChangesInterceptor
|
||||
if (string.IsNullOrWhiteSpace(tenantEntity.TenantId))
|
||||
{
|
||||
tenantEntity.TenantId = tenantId;
|
||||
_logger.LogDebug("Set TenantId for entity {EntityType}: {TenantId}",
|
||||
_logger.LogDebug("Set TenantId for entity {EntityType}: {TenantId}",
|
||||
entry.Entity.GetType().Name, tenantId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class TenantDbConnectionInterceptor : DbConnectionInterceptor
|
||||
await base.ConnectionOpeningAsync(connection, eventData, result, cancellationToken);
|
||||
|
||||
var tenantId = _tenantAccessor.MultiTenantContext?.TenantInfo?.Identifier;
|
||||
|
||||
|
||||
if (string.IsNullOrWhiteSpace(tenantId))
|
||||
{
|
||||
_logger.LogWarning("No tenant context available for database connection");
|
||||
@@ -40,7 +40,7 @@ public class TenantDbConnectionInterceptor : DbConnectionInterceptor
|
||||
{
|
||||
await using var command = npgsqlConnection.CreateCommand();
|
||||
command.CommandText = $"SET LOCAL app.current_tenant_id = '{tenantId}'";
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
await command.ExecuteNonQueryAsync(cancellationToken);
|
||||
@@ -61,7 +61,7 @@ public class TenantDbConnectionInterceptor : DbConnectionInterceptor
|
||||
base.ConnectionOpened(connection, eventData);
|
||||
|
||||
var tenantId = _tenantAccessor.MultiTenantContext?.TenantInfo?.Identifier;
|
||||
|
||||
|
||||
if (string.IsNullOrWhiteSpace(tenantId))
|
||||
{
|
||||
_logger.LogWarning("No tenant context available for database connection");
|
||||
@@ -72,7 +72,7 @@ public class TenantDbConnectionInterceptor : DbConnectionInterceptor
|
||||
{
|
||||
using var command = npgsqlConnection.CreateCommand();
|
||||
command.CommandText = $"SET LOCAL app.current_tenant_id = '{tenantId}'";
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
command.ExecuteNonQuery();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
@@ -27,7 +27,7 @@ public class TenantProvider : ITenantProvider
|
||||
{
|
||||
throw new InvalidOperationException("Tenant context is not available");
|
||||
}
|
||||
|
||||
|
||||
return tenantInfo.Identifier;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class TenantProvider : ITenantProvider
|
||||
|
||||
var tenantId = GetTenantId();
|
||||
var clubsClaim = httpContext.User.FindFirst("clubs")?.Value;
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(clubsClaim))
|
||||
{
|
||||
throw new InvalidOperationException("User does not have clubs claim");
|
||||
|
||||
@@ -20,7 +20,7 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
{
|
||||
using var scope = Factory.Services.CreateScope();
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
// Clean up and setup test data
|
||||
context.Clubs.RemoveRange(context.Clubs);
|
||||
context.Members.RemoveRange(context.Members);
|
||||
@@ -29,7 +29,7 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
// Create test clubs
|
||||
var club1Id = Guid.NewGuid();
|
||||
var club2Id = Guid.NewGuid();
|
||||
|
||||
|
||||
var club1 = new Club
|
||||
{
|
||||
Id = club1Id,
|
||||
@@ -107,8 +107,8 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
{
|
||||
// Arrange - admin is member of 2 clubs
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant1"] = "Admin",
|
||||
["tenant2"] = "Member"
|
||||
}, userId: "admin-user-id");
|
||||
@@ -118,7 +118,7 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var clubs = await response.Content.ReadFromJsonAsync<List<ClubListResponse>>();
|
||||
Assert.NotNull(clubs);
|
||||
Assert.Equal(2, clubs.Count);
|
||||
@@ -131,8 +131,8 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
{
|
||||
// Arrange - manager is only member of club1
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("manager@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("manager@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant1"] = "Manager"
|
||||
}, userId: "manager-user-id");
|
||||
|
||||
@@ -141,7 +141,7 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var clubs = await response.Content.ReadFromJsonAsync<List<ClubListResponse>>();
|
||||
Assert.NotNull(clubs);
|
||||
Assert.Single(clubs);
|
||||
@@ -153,8 +153,8 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
{
|
||||
// Arrange
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant1"] = "Admin"
|
||||
}, userId: "admin-user-id");
|
||||
|
||||
@@ -163,7 +163,7 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var club = await response.Content.ReadFromJsonAsync<ClubDetailResponse>();
|
||||
Assert.NotNull(club);
|
||||
Assert.Equal("Test Tennis Club", club.Name);
|
||||
@@ -176,8 +176,8 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
{
|
||||
// Arrange
|
||||
SetTenant("tenant2");
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant2"] = "Member"
|
||||
}, userId: "admin-user-id");
|
||||
|
||||
@@ -186,7 +186,7 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var club = await response.Content.ReadFromJsonAsync<ClubDetailResponse>();
|
||||
Assert.NotNull(club);
|
||||
Assert.Equal("Test Cycling Club", club.Name);
|
||||
@@ -197,8 +197,8 @@ public class ClubEndpointsTests : IntegrationTestBase
|
||||
public async Task GetClubsCurrent_NoTenantContext_ReturnsBadRequest()
|
||||
{
|
||||
// Arrange - no tenant header set
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant1"] = "Admin"
|
||||
}, userId: "admin-user-id");
|
||||
|
||||
|
||||
@@ -78,10 +78,10 @@ public class MigrationTests : IAsyncLifetime
|
||||
|
||||
// TenantId indexes
|
||||
Assert.Contains(indexes, i => i.Contains("tenant_id"));
|
||||
|
||||
|
||||
// ClubId indexes
|
||||
Assert.Contains(indexes, i => i.Contains("club_id"));
|
||||
|
||||
|
||||
// Status indexes for WorkItem
|
||||
Assert.Contains(indexes, i => i.Contains("status"));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class RlsTests : IAsyncLifetime
|
||||
|
||||
await _container.StartAsync();
|
||||
_connectionString = _container.GetConnectionString();
|
||||
|
||||
|
||||
_adminConnectionString = _connectionString.Replace("app_user", "app_admin")
|
||||
.Replace("apppass", "adminpass");
|
||||
|
||||
@@ -62,7 +62,7 @@ public class RlsTests : IAsyncLifetime
|
||||
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
|
||||
await connection.ExecuteAsync("SET LOCAL app.current_tenant_id = 'tenant-1'");
|
||||
|
||||
var clubs = (await connection.QueryAsync<Club>(
|
||||
@@ -79,7 +79,7 @@ public class RlsTests : IAsyncLifetime
|
||||
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
|
||||
await connection.ExecuteAsync("SET LOCAL app.current_tenant_id = 'tenant-1'");
|
||||
var tenant1Clubs = (await connection.QueryAsync<Club>(
|
||||
"SELECT * FROM clubs")).ToList();
|
||||
@@ -92,7 +92,7 @@ public class RlsTests : IAsyncLifetime
|
||||
Assert.NotEmpty(tenant2Clubs);
|
||||
Assert.All(tenant1Clubs, c => Assert.Equal("tenant-1", c.TenantId));
|
||||
Assert.All(tenant2Clubs, c => Assert.Equal("tenant-2", c.TenantId));
|
||||
|
||||
|
||||
var tenant1Ids = tenant1Clubs.Select(c => c.Id).ToHashSet();
|
||||
var tenant2Ids = tenant2Clubs.Select(c => c.Id).ToHashSet();
|
||||
Assert.Empty(tenant1Ids.Intersect(tenant2Ids));
|
||||
@@ -105,7 +105,7 @@ public class RlsTests : IAsyncLifetime
|
||||
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
|
||||
await connection.ExecuteAsync("SET LOCAL app.current_tenant_id = 'tenant-1'");
|
||||
var tenant1Count = await connection.ExecuteScalarAsync<int>(
|
||||
"SELECT COUNT(*) FROM work_items");
|
||||
@@ -141,7 +141,7 @@ public class RlsTests : IAsyncLifetime
|
||||
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
|
||||
await connection.ExecuteAsync("SET LOCAL app.current_tenant_id = 'tenant-1'");
|
||||
var signups = (await connection.QueryAsync<ShiftSignup>(
|
||||
"SELECT * FROM shift_signups")).ToList();
|
||||
@@ -164,7 +164,7 @@ public class RlsTests : IAsyncLifetime
|
||||
|
||||
var club1Id = Guid.NewGuid();
|
||||
var club2Id = Guid.NewGuid();
|
||||
|
||||
|
||||
await adminConn.ExecuteAsync(@"
|
||||
INSERT INTO clubs (id, tenant_id, name, sport_type, created_at, updated_at)
|
||||
VALUES (@Id1, 'tenant-1', 'Club 1', 0, NOW(), NOW()),
|
||||
|
||||
@@ -18,10 +18,10 @@ public abstract class IntegrationTestBase : IClassFixture<CustomWebApplicationFa
|
||||
var clubsJson = JsonSerializer.Serialize(clubs);
|
||||
Client.DefaultRequestHeaders.Remove("X-Test-Clubs");
|
||||
Client.DefaultRequestHeaders.Add("X-Test-Clubs", clubsJson);
|
||||
|
||||
|
||||
Client.DefaultRequestHeaders.Remove("X-Test-Email");
|
||||
Client.DefaultRequestHeaders.Add("X-Test-Email", email);
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
{
|
||||
Client.DefaultRequestHeaders.Remove("X-Test-UserId");
|
||||
|
||||
@@ -20,14 +20,14 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
{
|
||||
using var scope = Factory.Services.CreateScope();
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Members.RemoveRange(context.Members);
|
||||
context.Clubs.RemoveRange(context.Clubs);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
var club1Id = Guid.NewGuid();
|
||||
var club2Id = Guid.NewGuid();
|
||||
|
||||
|
||||
context.Clubs.AddRange(
|
||||
new Club
|
||||
{
|
||||
@@ -109,15 +109,15 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
public async Task GetMembers_ReturnsOnlyCurrentTenantMembers()
|
||||
{
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant1"] = "Admin"
|
||||
}, userId: "admin-user-id");
|
||||
|
||||
var response = await Client.GetAsync("/api/members");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var members = await response.Content.ReadFromJsonAsync<List<MemberListResponse>>();
|
||||
Assert.NotNull(members);
|
||||
Assert.Equal(3, members.Count);
|
||||
@@ -128,15 +128,15 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
public async Task GetMembers_DifferentTenant_ReturnsDifferentMembers()
|
||||
{
|
||||
SetTenant("tenant2");
|
||||
AuthenticateAs("other@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("other@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant2"] = "Member"
|
||||
}, userId: "other-user-id");
|
||||
|
||||
var response = await Client.GetAsync("/api/members");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var members = await response.Content.ReadFromJsonAsync<List<MemberListResponse>>();
|
||||
Assert.NotNull(members);
|
||||
Assert.Single(members);
|
||||
@@ -147,8 +147,8 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
public async Task GetMembers_AsViewer_ReturnsForbidden()
|
||||
{
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("viewer@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("viewer@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant1"] = "Viewer"
|
||||
}, userId: "viewer-user-id");
|
||||
|
||||
@@ -165,15 +165,15 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
var member = await context.Members.FirstAsync(m => m.Email == "manager@test.com");
|
||||
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant1"] = "Admin"
|
||||
}, userId: "admin-user-id");
|
||||
|
||||
var response = await Client.GetAsync($"/api/members/{member.Id}");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<MemberDetailResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(member.Id, result.Id);
|
||||
@@ -190,8 +190,8 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
var tenant1Member = await context.Members.FirstAsync(m => m.TenantId == "tenant1");
|
||||
|
||||
SetTenant("tenant2");
|
||||
AuthenticateAs("other@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("other@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant2"] = "Member"
|
||||
}, userId: "other-user-id");
|
||||
|
||||
@@ -204,15 +204,15 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
public async Task GetMembersMe_ReturnsCurrentUserMembership()
|
||||
{
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("manager@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("manager@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant1"] = "Manager"
|
||||
}, userId: "manager-user-id");
|
||||
|
||||
var response = await Client.GetAsync("/api/members/me");
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<MemberDetailResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("Manager User", result.DisplayName);
|
||||
@@ -224,8 +224,8 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
public async Task MemberAutoSync_NewUser_CreatesMembeRecordFromJwt()
|
||||
{
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("newuser@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("newuser@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant1"] = "Member"
|
||||
}, userId: "new-user-id");
|
||||
|
||||
@@ -236,7 +236,7 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
using var scope = Factory.Services.CreateScope();
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var syncedMember = await context.Members.FirstOrDefaultAsync(m => m.ExternalUserId == "new-user-id");
|
||||
|
||||
|
||||
Assert.NotNull(syncedMember);
|
||||
Assert.Equal("newuser@test.com", syncedMember.Email);
|
||||
Assert.Equal("tenant1", syncedMember.TenantId);
|
||||
@@ -251,8 +251,8 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
var initialCount = await context1.Members.CountAsync(m => m.ExternalUserId == "admin-user-id");
|
||||
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
AuthenticateAs("admin@test.com", new Dictionary<string, string>
|
||||
{
|
||||
["tenant1"] = "Admin"
|
||||
}, userId: "admin-user-id");
|
||||
|
||||
@@ -262,7 +262,7 @@ public class MemberEndpointsTests : IntegrationTestBase
|
||||
using var scope2 = Factory.Services.CreateScope();
|
||||
var context2 = scope2.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var finalCount = await context2.Members.CountAsync(m => m.ExternalUserId == "admin-user-id");
|
||||
|
||||
|
||||
Assert.Equal(initialCount, finalCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class TenantValidationTests : IClassFixture<CustomWebApplicationFactory>
|
||||
{ "club-1", "admin" }
|
||||
};
|
||||
var token = CreateTestJwt(clubs);
|
||||
|
||||
|
||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||
_client.DefaultRequestHeaders.Add("X-Tenant-Id", "club-1");
|
||||
|
||||
@@ -54,7 +54,7 @@ public class TenantValidationTests : IClassFixture<CustomWebApplicationFactory>
|
||||
{ "club-1", "admin" }
|
||||
};
|
||||
var token = CreateTestJwt(clubs);
|
||||
|
||||
|
||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||
_client.DefaultRequestHeaders.Add("X-Tenant-Id", "club-2"); // User not member of club-2
|
||||
|
||||
@@ -74,7 +74,7 @@ public class TenantValidationTests : IClassFixture<CustomWebApplicationFactory>
|
||||
{ "club-1", "admin" }
|
||||
};
|
||||
var token = CreateTestJwt(clubs);
|
||||
|
||||
|
||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||
// No X-Tenant-Id header
|
||||
|
||||
@@ -133,7 +133,7 @@ public class CustomWebApplicationFactory : WebApplicationFactory<Program>
|
||||
{
|
||||
services.AddAuthentication("TestScheme")
|
||||
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("TestScheme", options => { });
|
||||
|
||||
|
||||
services.AddAuthorization();
|
||||
});
|
||||
|
||||
@@ -157,19 +157,19 @@ public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
var authHeader = Request.Headers.Authorization.ToString();
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer "))
|
||||
{
|
||||
return Task.FromResult(AuthenticateResult.NoResult());
|
||||
}
|
||||
|
||||
var token = authHeader.Substring("Bearer ".Length).Trim();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("test-secret-key-for-jwt-signing-must-be-at-least-32-chars"));
|
||||
|
||||
|
||||
var validationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
@@ -183,7 +183,7 @@ public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions
|
||||
|
||||
var principal = handler.ValidateToken(token, validationParameters, out _);
|
||||
var ticket = new AuthenticationTicket(principal, "TestScheme");
|
||||
|
||||
|
||||
return Task.FromResult(AuthenticateResult.Success(ticket));
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
{
|
||||
using var scope = Factory.Services.CreateScope();
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
// Clean up existing test data
|
||||
context.ShiftSignups.RemoveRange(context.ShiftSignups);
|
||||
context.Shifts.RemoveRange(context.Shifts);
|
||||
@@ -31,7 +31,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
{
|
||||
// Arrange
|
||||
var clubId = Guid.NewGuid();
|
||||
|
||||
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("manager@test.com", new Dictionary<string, string> { ["tenant1"] = "Manager" });
|
||||
|
||||
@@ -51,7 +51,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<ShiftDetailResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("Morning Shift", result.Title);
|
||||
@@ -64,7 +64,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
{
|
||||
// Arrange
|
||||
var clubId = Guid.NewGuid();
|
||||
|
||||
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("viewer@test.com", new Dictionary<string, string> { ["tenant1"] = "Viewer" });
|
||||
|
||||
@@ -90,11 +90,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var clubId = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
// Shift in date range
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
@@ -109,7 +109,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
// Shift outside date range
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
@@ -124,7 +124,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<ShiftListResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Single(result.Items);
|
||||
@@ -155,11 +155,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var createdBy = Guid.NewGuid();
|
||||
var memberId = Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
Id = shiftId,
|
||||
@@ -175,7 +175,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
context.ShiftSignups.Add(new ShiftSignup
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
@@ -184,7 +184,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
MemberId = memberId,
|
||||
SignedUpAt = now
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<ShiftDetailResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(shiftId, result.Id);
|
||||
@@ -213,11 +213,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var clubId = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
Id = shiftId,
|
||||
@@ -231,7 +231,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<ShiftDetailResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("Updated Title", result.Title);
|
||||
@@ -264,11 +264,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var clubId = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
Id = shiftId,
|
||||
@@ -282,7 +282,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||
|
||||
|
||||
// Verify shift is deleted
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
@@ -312,11 +312,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var clubId = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
Id = shiftId,
|
||||
@@ -330,7 +330,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -352,11 +352,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var clubId = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
Id = shiftId,
|
||||
@@ -370,7 +370,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
// Verify signup was created
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
@@ -400,11 +400,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var clubId = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
Id = shiftId,
|
||||
@@ -418,7 +418,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
// Add one signup to fill capacity
|
||||
context.ShiftSignups.Add(new ShiftSignup
|
||||
{
|
||||
@@ -428,7 +428,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
MemberId = Guid.NewGuid(),
|
||||
SignedUpAt = now
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -450,11 +450,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var clubId = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
Id = shiftId,
|
||||
@@ -468,7 +468,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now.AddDays(-1),
|
||||
UpdatedAt = now.AddDays(-1)
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -491,11 +491,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var createdBy = Guid.NewGuid();
|
||||
var memberId = Guid.Parse("00000000-0000-0000-0000-000000000001"); // Fixed member ID
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
Id = shiftId,
|
||||
@@ -509,7 +509,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
// Add existing signup
|
||||
context.ShiftSignups.Add(new ShiftSignup
|
||||
{
|
||||
@@ -519,7 +519,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
MemberId = memberId,
|
||||
SignedUpAt = now
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -542,11 +542,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var createdBy = Guid.NewGuid();
|
||||
var memberId = Guid.Parse("00000000-0000-0000-0000-000000000001");
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
Id = shiftId,
|
||||
@@ -560,7 +560,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
context.ShiftSignups.Add(new ShiftSignup
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
@@ -569,7 +569,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
MemberId = memberId,
|
||||
SignedUpAt = now
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -581,7 +581,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
// Verify signup was deleted
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
@@ -599,11 +599,11 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
var clubId = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.Shifts.Add(new Shift
|
||||
{
|
||||
Id = shiftId,
|
||||
@@ -617,7 +617,7 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
});
|
||||
|
||||
|
||||
// Add one signup (leaving one slot)
|
||||
context.ShiftSignups.Add(new ShiftSignup
|
||||
{
|
||||
@@ -627,29 +627,29 @@ public class ShiftCrudTests : IntegrationTestBase
|
||||
MemberId = Guid.NewGuid(),
|
||||
SignedUpAt = now
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
SetTenant("tenant1");
|
||||
|
||||
|
||||
// Act - Simulate two concurrent requests
|
||||
var member1 = Guid.NewGuid();
|
||||
var member2 = Guid.NewGuid();
|
||||
|
||||
|
||||
AuthenticateAs("member1@test.com", new Dictionary<string, string> { ["tenant1"] = "Member" }, member1.ToString());
|
||||
var response1Task = Client.PostAsync($"/api/shifts/{shiftId}/signup", null);
|
||||
|
||||
|
||||
AuthenticateAs("member2@test.com", new Dictionary<string, string> { ["tenant1"] = "Member" }, member2.ToString());
|
||||
var response2Task = Client.PostAsync($"/api/shifts/{shiftId}/signup", null);
|
||||
|
||||
|
||||
var responses = await Task.WhenAll(response1Task, response2Task);
|
||||
|
||||
// Assert - One should succeed (200), one should fail (409)
|
||||
var statuses = responses.Select(r => r.StatusCode).OrderBy(s => s).ToList();
|
||||
Assert.Contains(HttpStatusCode.OK, statuses);
|
||||
Assert.Contains(HttpStatusCode.Conflict, statuses);
|
||||
|
||||
|
||||
// Verify only 2 total signups exist (capacity limit enforced)
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
{
|
||||
using var scope = Factory.Services.CreateScope();
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
// Clean up existing test data
|
||||
context.WorkItems.RemoveRange(context.WorkItems);
|
||||
await context.SaveChangesAsync();
|
||||
@@ -32,7 +32,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
// Arrange
|
||||
var club1 = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
|
||||
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("manager@test.com", new Dictionary<string, string> { ["tenant1"] = "Manager" });
|
||||
|
||||
@@ -48,7 +48,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<TaskDetailResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("New Task", result.Title);
|
||||
@@ -62,7 +62,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
{
|
||||
// Arrange
|
||||
var club1 = Guid.NewGuid();
|
||||
|
||||
|
||||
SetTenant("tenant1");
|
||||
AuthenticateAs("viewer@test.com", new Dictionary<string, string> { ["tenant1"] = "Viewer" });
|
||||
|
||||
@@ -85,11 +85,11 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
// Arrange
|
||||
var club1 = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
// Create tasks for tenant1
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
@@ -102,7 +102,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
@@ -114,7 +114,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
// Create task for tenant2
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
@@ -127,7 +127,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<TaskListResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(2, result.Items.Count);
|
||||
@@ -153,11 +153,11 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
// Arrange
|
||||
var club1 = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
@@ -169,7 +169,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
@@ -181,7 +181,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<TaskListResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Single(result.Items);
|
||||
@@ -208,11 +208,11 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
var taskId = Guid.NewGuid();
|
||||
var club1 = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
Id = taskId,
|
||||
@@ -225,7 +225,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<TaskDetailResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(taskId, result.Id);
|
||||
@@ -252,11 +252,11 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
var taskId = Guid.NewGuid();
|
||||
var club1 = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
Id = taskId,
|
||||
@@ -268,7 +268,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<TaskDetailResponse>();
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("Updated Title", result.Title);
|
||||
@@ -300,11 +300,11 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
var taskId = Guid.NewGuid();
|
||||
var club1 = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
Id = taskId,
|
||||
@@ -316,7 +316,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -342,11 +342,11 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
var taskId = Guid.NewGuid();
|
||||
var club1 = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
Id = taskId,
|
||||
@@ -358,7 +358,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
|
||||
// Second update (should detect concurrency conflict if RowVersion is checked)
|
||||
var updateRequest2 = new { Title = "Update 2" };
|
||||
|
||||
|
||||
// Act
|
||||
var response2 = await Client.PatchAsync($"/api/tasks/{taskId}", JsonContent.Create(updateRequest2));
|
||||
|
||||
@@ -397,11 +397,11 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
var taskId = Guid.NewGuid();
|
||||
var club1 = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
Id = taskId,
|
||||
@@ -413,7 +413,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||
|
||||
|
||||
// Verify task is deleted
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
@@ -442,11 +442,11 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
var taskId = Guid.NewGuid();
|
||||
var club1 = Guid.NewGuid();
|
||||
var createdBy = Guid.NewGuid();
|
||||
|
||||
|
||||
using (var scope = Factory.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
|
||||
context.WorkItems.Add(new WorkItem
|
||||
{
|
||||
Id = taskId,
|
||||
@@ -458,7 +458,7 @@ public class TaskCrudTests : IntegrationTestBase
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
});
|
||||
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace WorkClub.Tests.Integration;
|
||||
namespace WorkClub.Tests.Integration;
|
||||
|
||||
public class UnitTest1
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user