add TeamsController
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
632ac19238
commit
e8bdce981c
@ -1,13 +1,12 @@
|
||||
using API.Validation;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace API;
|
||||
namespace API.Context;
|
||||
|
||||
public static class AppHttpContext
|
||||
public class HttpContextAccessor : IContextAccessor
|
||||
{
|
||||
public static int CurrentUserId(this ControllerBase b)
|
||||
public int CurrentUserId(HttpContext ctx)
|
||||
{
|
||||
var idClaim = b.HttpContext
|
||||
var idClaim = ctx
|
||||
.User
|
||||
.Claims
|
||||
.First(c => c.Type == IdentityData.IdUserClaimName);
|
@ -0,0 +1,6 @@
|
||||
namespace API.Context;
|
||||
|
||||
public interface IContextAccessor
|
||||
{
|
||||
public int CurrentUserId(HttpContext ctx);
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using API.Context;
|
||||
using API.Validation;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Model;
|
||||
using Services;
|
||||
|
||||
namespace API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class TeamsController(ITeamService service, IContextAccessor accessor) : ControllerBase
|
||||
{
|
||||
public record CreateTeamRequest(
|
||||
[Name] string Name,
|
||||
[Url] string Picture,
|
||||
[RegularExpression("^#[0-9A-F]{6}$")] string FirstColor,
|
||||
[RegularExpression("^#[0-9A-F]{6}$")] string SecondColor
|
||||
);
|
||||
|
||||
[HttpPost("/teams")]
|
||||
public async Task<IActionResult> CreateTeam([FromBody] CreateTeamRequest req)
|
||||
{
|
||||
var userId = accessor.CurrentUserId(HttpContext);
|
||||
var team = await service.AddTeam(req.Name, req.Picture, req.FirstColor, req.SecondColor);
|
||||
await service.AddMember(team.Id, userId, MemberRole.Coach);
|
||||
return Ok(team);
|
||||
}
|
||||
|
||||
[HttpGet("/teams/{teamId:int}/members")]
|
||||
public IActionResult GetMembersOf(int teamId)
|
||||
{
|
||||
return Ok(service.GetMembersOf(teamId));
|
||||
}
|
||||
|
||||
public record AddMemberRequest(
|
||||
int UserId,
|
||||
[AllowedValues("PLAYER", "COACH")] string Role
|
||||
);
|
||||
|
||||
[HttpPost("/teams/{teamId:int}/members")]
|
||||
public async Task<IActionResult> AddMember(int teamId, [FromBody] AddMemberRequest req)
|
||||
{
|
||||
if (!Enum.TryParse<MemberRole>(req.Role, true, out var role))
|
||||
{
|
||||
throw new Exception($"Unable to convert string input '{req.Role}' to a role enum variant.");
|
||||
}
|
||||
|
||||
|
||||
return Ok(await service.AddMember(teamId, req.UserId, role));
|
||||
}
|
||||
|
||||
|
||||
public record UpdateMemberRequest(
|
||||
[AllowedValues("PLAYER", "COACH")] string Role
|
||||
);
|
||||
|
||||
[HttpPut("/team/{teamId:int}/members/{userId:int}")]
|
||||
public async Task<IActionResult> UpdateMember(int teamId, int userId, [FromBody] UpdateMemberRequest req)
|
||||
{
|
||||
if (!Enum.TryParse<MemberRole>(req.Role, true, out var role))
|
||||
{
|
||||
throw new Exception($"Unable to convert string input '{req.Role}' to a role enum variant.");
|
||||
}
|
||||
|
||||
var updated = await service.UpdateMember(new Member(teamId, userId, role));
|
||||
return updated ? Ok() : NotFound();
|
||||
}
|
||||
|
||||
[HttpDelete("/team/{teamId:int}/members/{userId:int}")]
|
||||
public async Task<IActionResult> RemoveMember(int teamId, int userId)
|
||||
{
|
||||
var removed = await service.RemoveMember(teamId, userId);
|
||||
return removed ? Ok() : NotFound();
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
namespace Model;
|
||||
|
||||
public record Member(int TeamId, int UserId, MemberRole Role);
|
@ -0,0 +1,7 @@
|
||||
namespace Model;
|
||||
|
||||
public enum MemberRole
|
||||
{
|
||||
Player,
|
||||
Coach
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
using API.Controllers;
|
||||
using API.Controllers.Admin;
|
||||
using DbServices;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Model;
|
||||
using StubContext;
|
||||
|
||||
|
||||
namespace UnitTests;
|
||||
|
||||
public class AdminUserControllerTest
|
||||
{
|
||||
private static UsersAdminController GetUsersController()
|
||||
{
|
||||
var connection = new SqliteConnection("Data Source=:memory:");
|
||||
connection.Open();
|
||||
var context = new StubAppContext(
|
||||
new DbContextOptionsBuilder<AppContext.AppContext>()
|
||||
.UseSqlite(connection)
|
||||
.Options
|
||||
);
|
||||
context.Database.EnsureCreated();
|
||||
var service = new DbUserService(context);
|
||||
return new UsersAdminController(service);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async void CountUsersTest()
|
||||
{
|
||||
var controller = GetUsersController();
|
||||
(await controller.CountUsers()).Should().Be(new UsersAdminController.CountUsersResponse(5));
|
||||
(await controller.CountUsers("a")).Should().BeEquivalentTo(new UsersAdminController.CountUsersResponse(3));
|
||||
(await controller.CountUsers("")).Should().BeEquivalentTo(new UsersAdminController.CountUsersResponse(5));
|
||||
(await controller.CountUsers("^ù$*")).Should().BeEquivalentTo(new UsersAdminController.CountUsersResponse(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void ListUsersTest()
|
||||
{
|
||||
var controller = GetUsersController();
|
||||
(await controller.CountUsers()).Should().Be(new UsersAdminController.CountUsersResponse(5));
|
||||
(await controller.ListUsers(0, 10, null)).Should().BeEquivalentTo(new List<User>
|
||||
{
|
||||
new(1, "maxime", "maxime@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
new(2, "mael", "mael@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
new(3, "yanis", "yanis@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
new(4, "simon", "simon@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
new(5, "vivien", "vivien@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
});
|
||||
(await controller.ListUsers(0, 10, "")).Should().BeEquivalentTo(new List<User>
|
||||
{
|
||||
new(1, "maxime", "maxime@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
new(2, "mael", "mael@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
new(3, "yanis", "yanis@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
new(4, "simon", "simon@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
new(5, "vivien", "vivien@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
});
|
||||
(await controller.ListUsers(0, 10, "a")).Should().BeEquivalentTo(new List<User>
|
||||
{
|
||||
new(1, "maxime", "maxime@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
new(2, "mael", "mael@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
new(3, "yanis", "yanis@mail.com",
|
||||
UsersController.DefaultProfilePicture, true),
|
||||
});
|
||||
(await controller.ListUsers(0, 0, "")).Should().BeEquivalentTo(new List<User> { });
|
||||
(await controller.ListUsers(0, 10, "^ù$*")).Should().BeEquivalentTo(new List<User> { });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetUserTest()
|
||||
{
|
||||
var controller = GetUsersController();
|
||||
var response = await controller.GetUser(0);
|
||||
response.Should().BeEquivalentTo(controller.NotFound());
|
||||
|
||||
response = await controller.GetUser(1);
|
||||
response.Should().BeEquivalentTo(controller.Ok(new User(1, "maxime", "maxime@mail.com",
|
||||
UsersController.DefaultProfilePicture, true)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void AddUserTest()
|
||||
{
|
||||
var controller = GetUsersController();
|
||||
var user = await controller.AddUser(new("Test", "TestPassword", "test@mail.com", true));
|
||||
user.Should().BeEquivalentTo(new User(6, "Test", "test@mail.com", UsersController.DefaultProfilePicture, true));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void RemoveUsersTest()
|
||||
{
|
||||
var controller = GetUsersController();
|
||||
var result = await controller.RemoveUsers(new([1, 4, 3, 5]));
|
||||
result.Should().BeEquivalentTo(controller.Ok());
|
||||
|
||||
var remainingUsers = await controller.ListUsers(0, 10, null);
|
||||
remainingUsers.Should().BeEquivalentTo(new User[] { new(2, "mael", "mael@mail.com",
|
||||
UsersController.DefaultProfilePicture, true) });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void UpdateUserTest()
|
||||
{
|
||||
var controller = GetUsersController();
|
||||
var result = await controller.UpdateUser(1, new("maxou", "maxou@mail.com", false));
|
||||
result.Should().BeEquivalentTo(controller.Ok());
|
||||
|
||||
var userResult = await controller.GetUser(1);
|
||||
userResult.Should().BeEquivalentTo(controller.Ok(new User(1, "maxou", "maxou@mail.com", UsersController.DefaultProfilePicture, false)));
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
global using Xunit;
|
@ -0,0 +1,12 @@
|
||||
using API.Context;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace UnitTests;
|
||||
|
||||
public class ManualContextAccessor(int userId) : IContextAccessor
|
||||
{
|
||||
public int CurrentUserId(HttpContext ctx)
|
||||
{
|
||||
return userId;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
using API.Controllers;
|
||||
using API.DTO;
|
||||
using AppContext.Entities;
|
||||
using DbServices;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Model;
|
||||
using StubContext;
|
||||
|
||||
namespace UnitTests;
|
||||
|
||||
public class TacticsControllerTest
|
||||
{
|
||||
private static (TacticController, AppContext.AppContext) GetController(int userId)
|
||||
{
|
||||
var connection = new SqliteConnection("Data Source=:memory:");
|
||||
connection.Open();
|
||||
var context = new StubAppContext(
|
||||
new DbContextOptionsBuilder<AppContext.AppContext>()
|
||||
.UseSqlite(connection)
|
||||
.Options
|
||||
);
|
||||
context.Database.EnsureCreated();
|
||||
var controller = new TacticController(
|
||||
new DbTacticService(context),
|
||||
new ManualContextAccessor(userId)
|
||||
);
|
||||
|
||||
return (controller, context);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void UpdateName()
|
||||
{
|
||||
var (controller, context) = GetController(1);
|
||||
var result = await controller.UpdateName(1, new("Stade de France"));
|
||||
result.Should().BeEquivalentTo(controller.Ok());
|
||||
|
||||
var tactic = await context.Tactics.FindAsync(1);
|
||||
tactic.Name.Should().BeEquivalentTo("Stade de France");
|
||||
|
||||
result = await controller.UpdateName(-1, new("Stade de France"));
|
||||
result.Should().BeEquivalentTo(controller.Unauthorized());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetTacticInfoTest()
|
||||
{
|
||||
var (controller, context) = GetController(1);
|
||||
var result = await controller.GetTacticInfo(1);
|
||||
result.Should().BeEquivalentTo(controller.Ok(new Tactic(1, "New tactic", 1, CourtType.Plain, new DateTime(2024, 5, 31)).ToDto()));
|
||||
|
||||
result = await controller.GetTacticInfo(100);
|
||||
result.Should().BeEquivalentTo(controller.Unauthorized());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetTacticStepsRoot()
|
||||
{
|
||||
var (controller, context) = GetController(1);
|
||||
var result = await controller.GetTacticStepsRoot(1);
|
||||
result.Should().BeEquivalentTo(controller.Ok(new TacticController.GetTacticStepsTreeResponse(new TacticStep(1, null, [], "{}").ToDto())));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="7.0.0-alpha.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="xunit" Version="2.4.2"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\API\API.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\API\API.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,49 @@
|
||||
using API.Controllers;
|
||||
using DbServices;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Model;
|
||||
using StubContext;
|
||||
|
||||
namespace UnitTests;
|
||||
|
||||
public class UsersControllerTest
|
||||
{
|
||||
private static UsersController GetUserController(int userId)
|
||||
{
|
||||
var connection = new SqliteConnection("Data Source=:memory:");
|
||||
connection.Open();
|
||||
var context = new StubAppContext(
|
||||
new DbContextOptionsBuilder<AppContext.AppContext>()
|
||||
.UseSqlite(connection)
|
||||
.Options
|
||||
);
|
||||
context.Database.EnsureCreated();
|
||||
var controller = new UsersController(
|
||||
new DbUserService(context),
|
||||
new DbTeamService(context),
|
||||
new DbTacticService(context),
|
||||
new ManualContextAccessor(userId)
|
||||
);
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetCurrentUserTest()
|
||||
{
|
||||
var controller = GetUserController(1);
|
||||
var result = await controller.GetUser();
|
||||
result.Should().BeEquivalentTo(new User(1, "maxime", "maxime@mail.com",
|
||||
UsersController.DefaultProfilePicture, true));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetUserDataTest()
|
||||
{
|
||||
var controller = GetUserController(1);
|
||||
var result = await controller.GetUserData();
|
||||
result.Should().BeEquivalentTo(new UsersController.GetUserDataResponse([], []));
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"stryker-config":
|
||||
{
|
||||
"reporters": [
|
||||
"progress",
|
||||
"html"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in new issue