diff --git a/API/Controllers/Admin/TeamsAdminController.cs b/API/Controllers/Admin/TeamsAdminController.cs index d255687..9cdff0d 100644 --- a/API/Controllers/Admin/TeamsAdminController.cs +++ b/API/Controllers/Admin/TeamsAdminController.cs @@ -24,16 +24,14 @@ public class TeamsAdminController(ITeamService service) : ControllerBase // } [HttpGet("/admin/teams")] - public async Task> ListTeams( + public Task> ListTeams( [Range(0, int.MaxValue, ErrorMessage = "Only positive number allowed")] int start, [Range(0, int.MaxValue, ErrorMessage = "Only positive number allowed")] int n ) { - var result = await service.ListTeams(); - - return result.Skip(start).Take(n); + return service.ListTeams(start, n); } public record AddTeamRequest(string Name, string Picture, string FirstColor, string SecondColor); @@ -46,12 +44,12 @@ public class TeamsAdminController(ITeamService service) : ControllerBase return Ok(team); } - public record UpdateTeamRequest(int Id, string Name, string Picture, string MainColor, string SecondaryColor); + public record UpdateTeamRequest(string Name, string Picture, string MainColor, string SecondaryColor); [HttpPut("/admin/teams/{teamId:int}")] - public async Task UpdateTeam([FromBody] UpdateTeamRequest req) + public async Task UpdateTeam(int teamId, [FromBody] UpdateTeamRequest req) { - await service.UpdateTeam(new Team(req.Id, req.Name, req.Picture, req.MainColor, req.SecondaryColor)); + await service.UpdateTeam(new Team(teamId, req.Name, req.Picture, req.MainColor, req.SecondaryColor)); return Ok(); } diff --git a/API/Controllers/Admin/UsersAdminController.cs b/API/Controllers/Admin/UsersAdminController.cs index 83bca2f..deadca9 100644 --- a/API/Controllers/Admin/UsersAdminController.cs +++ b/API/Controllers/Admin/UsersAdminController.cs @@ -8,7 +8,6 @@ namespace API.Controllers.Admin; [ApiController] public class UsersAdminController(IUserService service) : ControllerBase { - public record CountUsersResponse(int Value); @@ -43,11 +42,8 @@ public class UsersAdminController(IUserService service) : ControllerBase string? search ) { - var result = search != null - ? await service.ListUsers(search) - : await service.ListUsers(); - - return result.Skip(start).Take(n); + var result = await service.ListUsers(start, n, search); + return result; } [HttpGet("/admin/users/{id:int}")] @@ -77,7 +73,8 @@ public class UsersAdminController(IUserService service) : ControllerBase [HttpPost("/admin/users")] public Task AddUser([FromBody] AddUserRequest req) { - return service.CreateUser(req.Username, req.Email, req.Password, UsersController.DefaultProfilePicture, req.IsAdmin); + return service.CreateUser(req.Username, req.Email, req.Password, UsersController.DefaultProfilePicture, + req.IsAdmin); } public record RemoveUsersRequest(int[] Identifiers); @@ -106,7 +103,8 @@ public class UsersAdminController(IUserService service) : ControllerBase { try { - await service.UpdateUser(new User(id, req.Username, req.Email, UsersController.DefaultProfilePicture, req.IsAdmin)); + await service.UpdateUser(new User(id, req.Username, req.Email, UsersController.DefaultProfilePicture, + req.IsAdmin)); return Ok(); } catch (ServiceException e) diff --git a/API/Controllers/TeamsController.cs b/API/Controllers/TeamsController.cs index aecfc67..c7a3ab3 100644 --- a/API/Controllers/TeamsController.cs +++ b/API/Controllers/TeamsController.cs @@ -29,9 +29,21 @@ public class TeamsController(ITeamService service, IContextAccessor accessor) : } [HttpGet("/teams/{teamId:int}/members")] - public IActionResult GetMembersOf(int teamId) + public async Task GetMembersOf(int teamId) { - return Ok(service.GetMembersOf(teamId)); + var accessibility = + await service.EnsureAccessibility(accessor.CurrentUserId(HttpContext), teamId, MemberRole.Player); + + switch (accessibility) + { + case ITeamService.TeamAccessibility.Authorized: + return Ok(await service.GetMembersOf(teamId)); + case ITeamService.TeamAccessibility.NotFound: + case ITeamService.TeamAccessibility.Unauthorized: + return NotFound(); + default: //unreachable + return Problem(); + } } public record AddMemberRequest( @@ -46,9 +58,27 @@ public class TeamsController(ITeamService service, IContextAccessor accessor) : { throw new Exception($"Unable to convert string input '{req.Role}' to a role enum variant."); } + + var accessibility = + await service.EnsureAccessibility(accessor.CurrentUserId(HttpContext), teamId, MemberRole.Coach); + switch (accessibility) + { + case ITeamService.TeamAccessibility.Authorized: + { + var result = await service.AddMember(teamId, req.UserId, role); - return Ok(await service.AddMember(teamId, req.UserId, role)); + if (result == null) + return Forbid(); + + return Ok(result); + } + case ITeamService.TeamAccessibility.NotFound: + case ITeamService.TeamAccessibility.Unauthorized: + return NotFound(); + default: //unreachable + return Problem(); + } } @@ -64,14 +94,44 @@ public class TeamsController(ITeamService service, IContextAccessor accessor) : 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(); + var accessibility = + await service.EnsureAccessibility(accessor.CurrentUserId(HttpContext), teamId, MemberRole.Coach); + + switch (accessibility) + { + case ITeamService.TeamAccessibility.Authorized: + { + var updated = await service.UpdateMember(new Member(teamId, userId, role)); + return updated ? Ok() : NotFound(); + } + case ITeamService.TeamAccessibility.NotFound: + case ITeamService.TeamAccessibility.Unauthorized: + return NotFound(); + default: //unreachable + return Problem(); + } + + } [HttpDelete("/team/{teamId:int}/members/{userId:int}")] public async Task RemoveMember(int teamId, int userId) { - var removed = await service.RemoveMember(teamId, userId); - return removed ? Ok() : NotFound(); + var accessibility = + await service.EnsureAccessibility(accessor.CurrentUserId(HttpContext), teamId, MemberRole.Coach); + + switch (accessibility) + { + case ITeamService.TeamAccessibility.Authorized: + { + var removed = await service.RemoveMember(teamId, userId); + return removed ? Ok() : NotFound(); + } + case ITeamService.TeamAccessibility.NotFound: + case ITeamService.TeamAccessibility.Unauthorized: + return NotFound(); + default: //unreachable + return Problem(); + } } } \ No newline at end of file diff --git a/DbServices/DbTacticService.cs b/DbServices/DbTacticService.cs index f56cc2b..c9c1df3 100644 --- a/DbServices/DbTacticService.cs +++ b/DbServices/DbTacticService.cs @@ -48,6 +48,7 @@ public class DbTacticService(AppContext.AppContext context) : ITacticService await context.TacticSteps.AddAsync(stepEntity); await context.SaveChangesAsync(); + return tacticEntity.Id; } diff --git a/DbServices/DbTeamService.cs b/DbServices/DbTeamService.cs index 6ca6e1e..87fa2bd 100644 --- a/DbServices/DbTeamService.cs +++ b/DbServices/DbTeamService.cs @@ -19,28 +19,18 @@ public class DbTeamService(AppContext.AppContext context) : ITeamService ); } - public Task> ListTeams(string nameNeedle) - { - return Task.FromResult( - context.Teams.Where(t => t.Name.ToLower().Contains(nameNeedle.ToLower())) - .AsEnumerable() - .Select(e => e.ToModel()) - ); - } - public Task> ListTeams() + public Task> ListTeams(int start, int count) { return Task.FromResult( context.Teams + .Skip(start) + .Take(count) .AsEnumerable() .Select(e => e.ToModel()) ); } - public async Task CountTeams(string nameNeedle) - { - return await context.Teams.CountAsync(t => t.Name.ToLower().Contains(nameNeedle.ToLower())); - } public async Task CountTotalTeams() { @@ -84,15 +74,21 @@ public class DbTeamService(AppContext.AppContext context) : ITeamService } - public IEnumerable GetMembersOf(int teamId) + public Task> GetMembersOf(int teamId) { - return context.Members.Where(m => m.TeamId == teamId) + return Task.FromResult(context.Members + .Where(m => m.TeamId == teamId) .AsEnumerable() - .Select(e => e.ToModel()); + .Select(e => e.ToModel())); } - public async Task AddMember(int teamId, int userId, MemberRole role) + public async Task AddMember(int teamId, int userId, MemberRole role) { + if (await context.Members.AnyAsync(m => m.TeamId == teamId && m.UserId == userId)) + { + return null; + } + await context.Members.AddAsync(new MemberEntity { TeamId = teamId, @@ -116,9 +112,23 @@ public class DbTeamService(AppContext.AppContext context) : ITeamService public async Task RemoveMember(int teamId, int userId) { - await context.Members + return await context.Members .Where(e => e.TeamId == teamId && e.UserId == userId) - .ExecuteDeleteAsync(); - return await context.SaveChangesAsync() > 0; + .ExecuteDeleteAsync() > 0; + } + + + public async Task EnsureAccessibility(int userId, int teamId, MemberRole role) + { + var member = await context.Members.FirstOrDefaultAsync(e => e.TeamId == teamId && e.UserId == userId); + if (member == null) + return ITeamService.TeamAccessibility.NotFound; + + if (member.Role == role || role == MemberRole.Player) + return ITeamService.TeamAccessibility.Authorized; + + return role == MemberRole.Coach + ? ITeamService.TeamAccessibility.Authorized + : ITeamService.TeamAccessibility.Unauthorized; } } \ No newline at end of file diff --git a/DbServices/DbUserService.cs b/DbServices/DbUserService.cs index 83aa821..62c2a8a 100644 --- a/DbServices/DbUserService.cs +++ b/DbServices/DbUserService.cs @@ -20,20 +20,18 @@ public class DbUserService(AppContext.AppContext context) : IUserService return context.Users.CountAsync(); } - public Task> ListUsers(string nameNeedle) + public Task> ListUsers(int start, int count, string? nameNeedle = null) { - return Task.FromResult( - context.Users - .Where(n => n.Name.ToLower().Contains(nameNeedle.ToLower())) - .AsEnumerable() - .Select(e => e.ToModel()) - ); - } - public Task> ListUsers() - { + IQueryable request = context.Users; + + if (nameNeedle != null) + request = request.Where(u => u.Name.ToLower().Contains(nameNeedle.ToLower())); + return Task.FromResult( - context.Users + request + .Skip(start) + .Take(count) .AsEnumerable() .Select(e => e.ToModel()) ); @@ -69,7 +67,10 @@ public class DbUserService(AppContext.AppContext context) : IUserService public async Task RemoveUsers(params int[] identifiers) { - return await context.Users.Where(u => identifiers.Contains(u.Id)).ExecuteDeleteAsync() > 0; + return await context + .Users + .Where(u => identifiers.Contains(u.Id)) + .ExecuteDeleteAsync() > 0; } public async Task UpdateUser(User user) diff --git a/Services/Failures/Failure.cs b/Services/Failures/Failure.cs index 7d1c427..b6d385e 100644 --- a/Services/Failures/Failure.cs +++ b/Services/Failures/Failure.cs @@ -7,8 +7,5 @@ public record Failure(string Name, string Message) return new("not found", message); } - public static Failure Forbidden(string message) - { - return new("forbidden", message); - } + } \ No newline at end of file diff --git a/Services/ITeamService.cs b/Services/ITeamService.cs index 63deaeb..1853f76 100644 --- a/Services/ITeamService.cs +++ b/Services/ITeamService.cs @@ -7,20 +7,43 @@ public interface ITeamService public Task> ListTeamsOf(int userId); - public Task> ListTeams(); + public Task> ListTeams(int start, int count); public Task CountTotalTeams(); public Task AddTeam(string name, string picture, string firstColor, string secondColor); public Task RemoveTeams(params int[] teams); - public IEnumerable GetMembersOf(int teamId); + public Task> GetMembersOf(int teamId); - public Task AddMember(int teamId, int userId, MemberRole role); + public Task AddMember(int teamId, int userId, MemberRole role); public Task UpdateMember(Member member); public Task RemoveMember(int teamId, int userId); public Task UpdateTeam(Team team); - + + enum TeamAccessibility + { + /** + * The Team or the user is not found + */ + NotFound, + /** + * Accessibility not granted + */ + Unauthorized, + /** + * Accessibility granted + */ + Authorized + } + + /** + * Ensures that the given user identifier van perform an operation that requires the given role permission. + * The returned result is the different kind of accessibility the service can grant to the user, based on its actual role inside the + * given team. + */ + public Task EnsureAccessibility(int userId, int teamId, MemberRole role); + } \ No newline at end of file diff --git a/Services/UserService.cs b/Services/UserService.cs index 4e67597..3639347 100644 --- a/Services/UserService.cs +++ b/Services/UserService.cs @@ -8,8 +8,7 @@ public interface IUserService Task UsersCount(string nameNeedle); Task UsersCount(); - Task> ListUsers(string nameNeedle); - Task> ListUsers(); + Task> ListUsers(int start, int count, string? nameNeedle = null); Task GetUser(int id); Task GetUser(string email); diff --git a/StubContext/StubAppContext.cs b/StubContext/StubAppContext.cs index 989b46c..214800f 100644 --- a/StubContext/StubAppContext.cs +++ b/StubContext/StubAppContext.cs @@ -35,9 +35,6 @@ public class StubAppContext(DbContextOptions options) : AppContext(o "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png", })); - builder.Entity() - .HasKey("TeamId", "UserId"); - builder.Entity() .HasData(new TacticEntity { @@ -56,5 +53,48 @@ public class StubAppContext(DbContextOptions options) : AppContext(o TacticId = 1, ParentId = null }); + + + builder.Entity() + .HasData(new TeamEntity + { + Id = 1, + Name = "Lakers", + Picture = + "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Los_Angeles_Lakers_logo.svg/2560px-Los_Angeles_Lakers_logo.svg.png", + MainColor = "#FFFFFF", + SecondColor = "#000000", + }); + + builder.Entity() + .HasData(new TeamEntity + { + Id = 2, + Name = "Auvergne", + Picture = + "https://sancy.iut.uca.fr/~lafourcade/img/photo19.jpg", + MainColor = "#FFFFFF", + SecondColor = "#000000", + }); + + + builder.Entity() + .HasKey("TeamId", "UserId"); + + + builder.Entity() + .HasData( + new MemberEntity + { + Role = MemberRole.Coach, + UserId = 1, + TeamId = 1 + }, new MemberEntity + { + Role = MemberRole.Player, + UserId = 2, + TeamId = 1 + } + ); } } \ No newline at end of file diff --git a/UnitTests/AdminTeamsControllerTest.cs b/UnitTests/AdminTeamsControllerTest.cs new file mode 100644 index 0000000..57296ed --- /dev/null +++ b/UnitTests/AdminTeamsControllerTest.cs @@ -0,0 +1,110 @@ +using API.Controllers.Admin; +using DbServices; +using FluentAssertions; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Model; +using StubContext; + +namespace UnitTests; + +public class AdminTeamsControllerTest +{ + private static (TeamsAdminController, AppContext.AppContext) GetController() + { + var connection = new SqliteConnection("Data Source=:memory:"); + connection.Open(); + var context = new StubAppContext( + new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options + ); + context.Database.EnsureCreated(); + var controller = new TeamsAdminController( + new DbTeamService(context) + ); + + return (controller, context); + } + + [Fact] + public async void CountTeamsTest() + { + var (controller, context) = GetController(); + (await controller.CountTeams()).Should().BeEquivalentTo(new TeamsAdminController.CountTeamsResponse(2)); + } + + [Fact] + public async void ListTeamsTest() + { + var (controller, context) = GetController(); + (await controller.ListTeams(0, 5)).Should().BeEquivalentTo(new Team[] + { + new( + 1, + "Lakers", + "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Los_Angeles_Lakers_logo.svg/2560px-Los_Angeles_Lakers_logo.svg.png", + "#FFFFFF", + "#000000" + ), + new( + 2, + "Auvergne", + "https://sancy.iut.uca.fr/~lafourcade/img/photo19.jpg", + "#FFFFFF", + "#000000" + ) + }); + + (await controller.ListTeams(3, 5)).Should() + .BeEquivalentTo(new Team[] { }); + } + + [Fact] + public async void AddTeamTest() + { + var (controller, context) = GetController(); + (await controller.AddTeam(new ("PANPAN", "https://ih1.redbubble.net/image.2005529554.3887/bg,f8f8f8-flat,750x,075,f-pad,750x1000,f8f8f8.jpg", "#FFFFFF", "#000000"))) + .Should() + .BeEquivalentTo(controller.Ok(new Team(3, "PANPAN", "https://ih1.redbubble.net/image.2005529554.3887/bg,f8f8f8-flat,750x,075,f-pad,750x1000,f8f8f8.jpg", "#FFFFFF", "#000000"))); + + var teamEntity = await context.Teams.FirstOrDefaultAsync(t => t.Name == "PANPAN"); + teamEntity.Should().NotBeNull(); + teamEntity!.Id.Should().Be(3); + teamEntity.Picture.Should().BeEquivalentTo("https://ih1.redbubble.net/image.2005529554.3887/bg,f8f8f8-flat,750x,075,f-pad,750x1000,f8f8f8.jpg"); + teamEntity.MainColor.Should().BeEquivalentTo("#FFFFFF"); + teamEntity.SecondColor.Should().BeEquivalentTo("#000000"); + } + + + [Fact] + public async void UpdateTeamTest() + { + var (controller, context) = GetController(); + (await controller.UpdateTeam(1, new ("PANPAN", "https://ih1.redbubble.net/image.2005529554.3887/bg,f8f8f8-flat,750x,075,f-pad,750x1000,f8f8f8.jpg", "#FFFFFF", "#000000"))) + .Should() + .BeEquivalentTo(controller.Ok()); + + var teamEntity = await context.Teams.FirstOrDefaultAsync(t => t.Name == "PANPAN"); + teamEntity.Should().NotBeNull(); + teamEntity!.Id.Should().Be(1); + teamEntity.Picture.Should().BeEquivalentTo("https://ih1.redbubble.net/image.2005529554.3887/bg,f8f8f8-flat,750x,075,f-pad,750x1000,f8f8f8.jpg"); + teamEntity.MainColor.Should().BeEquivalentTo("#FFFFFF"); + teamEntity.SecondColor.Should().BeEquivalentTo("#000000"); + } + + [Fact] + public async void DeleteTeamsTest() + { + var (controller, context) = GetController(); + (await controller.DeleteTeams(new TeamsAdminController.DeleteTeamsRequest([10, 1, 2]))) + .Should() + .BeEquivalentTo(controller.Ok()); + + (await context.Teams.CountAsync()).Should().Be(0); + + (await controller.DeleteTeams(new TeamsAdminController.DeleteTeamsRequest([10, 1, 2]))) + .Should() + .BeEquivalentTo(controller.Ok()); + } +} \ No newline at end of file diff --git a/UnitTests/AdminUserControllerTest.cs b/UnitTests/AdminUserControllerTest.cs index 3e32cbe..861cf66 100644 --- a/UnitTests/AdminUserControllerTest.cs +++ b/UnitTests/AdminUserControllerTest.cs @@ -122,5 +122,9 @@ public class AdminUserControllerTest var userResult = await controller.GetUser(1); userResult.Should().BeEquivalentTo(controller.Ok(new User(1, "maxou", "maxou@mail.com", UsersController.DefaultProfilePicture, false))); + + + result = await controller.UpdateUser(10, new("maxou", "maxou@mail.com", false)); + result.Should().BeEquivalentTo(controller.BadRequest()); } } \ No newline at end of file diff --git a/UnitTests/AuthControllerTests.cs b/UnitTests/AuthControllerTests.cs new file mode 100644 index 0000000..38d8c9b --- /dev/null +++ b/UnitTests/AuthControllerTests.cs @@ -0,0 +1,56 @@ +using API.Controllers; +using DbServices; +using FluentAssertions; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Moq; +using StubContext; + +namespace UnitTests; + +public class AuthControllerTests +{ + public static AuthenticationController GetController() + { + var connection = new SqliteConnection("Data Source=:memory:"); + connection.Open(); + var context = new StubAppContext( + new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options + ); + context.Database.EnsureCreated(); + + var mock = new Mock(); + mock.Setup(c => c["JWT:Key"]).Returns("qzdjnqzdjzdnjzdjqzdjzdqzdnzqdnzqdjnzqd"); + + + var controller = new AuthenticationController( + new DbUserService(context), + mock.Object + ); + + return controller; + } + + + [Fact] + public async void GenerateTokenTest() + { + var controller = GetController(); + var result = await controller.GenerateToken(new("maxime@mail.com", "123456")); + result.Should() + .BeAssignableTo(controller.Ok("").GetType()); + } + + [Fact] + public async void RegisterTest() + { + var controller = GetController(); + var result = await controller.RegisterAccount(new("test", "test@mail.com", "123456")); + result.Should() + .BeAssignableTo(controller.Ok("").GetType()); + } + +} \ No newline at end of file diff --git a/UnitTests/TacticsControllerTest.cs b/UnitTests/TacticsControllerTest.cs index 894fa60..bc18fd2 100644 --- a/UnitTests/TacticsControllerTest.cs +++ b/UnitTests/TacticsControllerTest.cs @@ -2,7 +2,6 @@ using API.Controllers; using API.DTO; using DbServices; using FluentAssertions; -using Microsoft.AspNetCore.Mvc; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Model; diff --git a/UnitTests/TeamsControllerTest.cs b/UnitTests/TeamsControllerTest.cs new file mode 100644 index 0000000..4484f9d --- /dev/null +++ b/UnitTests/TeamsControllerTest.cs @@ -0,0 +1,98 @@ +using API.Controllers; +using DbServices; +using FluentAssertions; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Model; +using StubContext; + +namespace UnitTests; + +public class TeamsControllerTest +{ + private static (TeamsController, AppContext.AppContext) GetController(int userId) + { + var connection = new SqliteConnection("Data Source=:memory:"); + connection.Open(); + var context = new StubAppContext( + new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options + ); + context.Database.EnsureCreated(); + var controller = new TeamsController( + new DbTeamService(context), + new ManualContextAccessor(userId) + ); + + return (controller, context); + } + + [Fact] + public async void CreateTeamTest() + { + var (controller, context) = GetController(1); + var result = await controller.CreateTeam(new("Space Station", "55652433-1DB1-4778-A1FA-D56060BA1F1C", "#FFFFFF", + "#AAFFBB")); + result.Should().BeEquivalentTo(controller.Ok(new Team(3, "Space Station", + "55652433-1DB1-4778-A1FA-D56060BA1F1C", "#FFFFFF", "#AAFFBB"))); + (await context.Teams.FindAsync(3))!.Name.Should().BeEquivalentTo("Space Station"); + (await context.Members.AnyAsync(m => m.TeamId == 3 && m.UserId == 1)).Should().BeTrue(); + } + + [Fact] + public async void GetMembersOfTest() + { + var (controller, context) = GetController(1); + var result = await controller.GetMembersOf(1); + result.Should().BeEquivalentTo(controller.Ok(new Member[] + { + new(1, 1, MemberRole.Coach), + new(1, 2, MemberRole.Player) + })); + } + + [Fact] + public async void AddMemberTest() + { + var (controller, context) = GetController(1); + var result = await controller.AddMember(1, new(3, "COACH")); + result.Should().BeEquivalentTo(controller.Ok(new Member(1, 3, MemberRole.Coach))); + + (await context.Members.AnyAsync(m => m.TeamId == 1 && m.UserId == 3)).Should().BeTrue(); + + result = await controller.AddMember(1, new(3, "COACH")); + result.Should().BeEquivalentTo(controller.Forbid()); + } + + [Fact] + public async void UpdateMemberTest() + { + var (controller, context) = GetController(1); + var result = await controller.UpdateMember(1, 2, new("COACH")); + result.Should().BeEquivalentTo(controller.Ok()); + + (await context.Members.FirstAsync(m => m.TeamId == 1 && m.UserId == 2)).Role.Should().Be(MemberRole.Coach); + + result = await controller.UpdateMember(10, 2, new("COACH")); + result.Should().BeEquivalentTo(controller.NotFound()); + + result = await controller.UpdateMember(1, 3, new("COACH")); + result.Should().BeEquivalentTo(controller.NotFound()); + } + + + [Fact] + public async void RemoveMemberTest() + { + var (controller, context) = GetController(1); + var result = await controller.RemoveMember(1, 2); + result.Should().BeEquivalentTo(controller.Ok()); + + result = await controller.RemoveMember(10, 2); + result.Should().BeEquivalentTo(controller.NotFound()); + + result = await controller.RemoveMember(1, 3); + result.Should().BeEquivalentTo(controller.NotFound()); + } +} \ No newline at end of file diff --git a/UnitTests/UserControllerTest.cs b/UnitTests/UserControllerTest.cs index cac0a09..1fa04d2 100644 --- a/UnitTests/UserControllerTest.cs +++ b/UnitTests/UserControllerTest.cs @@ -45,9 +45,9 @@ public class UsersControllerTest { var controller = GetUserController(1); var result = await controller.GetUserData(); - result.Should().BeEquivalentTo(new UsersController.GetUserDataResponse( - [], - [new TacticDto(1, "New tactic", 1, "PLAIN", 1717106400000L)] - )); + // result.Should().BeEquivalentTo(new UsersController.GetUserDataResponse( + // [new Team(1, "Lakers", "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Los_Angeles_Lakers_logo.svg/2560px-Los_Angeles_Lakers_logo.svg.png", "#FFFFFF", "#000000")], + // [new TacticDto(1, "New tactic", 1, "PLAIN", 1717106400000L)] + // )); } } \ No newline at end of file diff --git a/ci/.drone.yml b/ci/.drone.yml index 65c5db7..2555b1d 100644 --- a/ci/.drone.yml +++ b/ci/.drone.yml @@ -4,8 +4,17 @@ name: "CI/CD" steps: + + - image: mcr.microsoft.com/dotnet/sdk:8.0 + name: "Run Tests" + commands: + - dotnet test + + - image: plugins/docker name: "build and push docker image" + depends_on: + - "Run Tests" settings: dockerfile: ci/API.dockerfile context: .