fix conflicts
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is failing Details

shareTactic
Vivien DUFOUR 1 year ago
commit fda24219e2

@ -5,8 +5,13 @@ using Services;
namespace API.Controllers.Admin; namespace API.Controllers.Admin;
/// <summary>
/// WARNING: This controller does not requires the requester to be authenticated, see https://codefirst.iut.uca.fr/git/IQBall/Server-Panel/issues/2
/// </summary>
/// <param name="service"></param>
[ApiController] [ApiController]
public class TeamsAdminController(ITeamService service) : ControllerBase public class TeamsAdminController(ITeamService service, ILogger<TeamsAdminController> logger) : ControllerBase
{ {
public record CountTeamsResponse(int Value); public record CountTeamsResponse(int Value);
@ -14,26 +19,20 @@ public class TeamsAdminController(ITeamService service) : ControllerBase
[HttpGet("/admin/teams/count")] [HttpGet("/admin/teams/count")]
public async Task<CountTeamsResponse> CountTeams() public async Task<CountTeamsResponse> CountTeams()
{ {
logger.LogTrace("Counting teams");
return new CountTeamsResponse(await service.CountTotalTeams()); return new CountTeamsResponse(await service.CountTotalTeams());
} }
// [HttpGet("/admin/users/count")]
// public async Task<CountUsersResponse> CountUsers()
// {
// return new CountUsersResponse(await service.UsersCount());
// }
[HttpGet("/admin/teams")] [HttpGet("/admin/teams")]
public async Task<IEnumerable<Team>> ListTeams( public Task<IEnumerable<Team>> ListTeams(
[Range(0, int.MaxValue, ErrorMessage = "Only positive number allowed")] [Range(0, int.MaxValue, ErrorMessage = "Only positive number allowed")]
int start, int start,
[Range(0, int.MaxValue, ErrorMessage = "Only positive number allowed")] [Range(0, int.MaxValue, ErrorMessage = "Only positive number allowed")]
int n int n
) )
{ {
var result = await service.ListTeams(); logger.LogTrace("Listing teams");
return service.ListTeams(start, n);
return result.Skip(start).Take(n);
} }
public record AddTeamRequest(string Name, string Picture, string FirstColor, string SecondColor); public record AddTeamRequest(string Name, string Picture, string FirstColor, string SecondColor);
@ -41,17 +40,19 @@ public class TeamsAdminController(ITeamService service) : ControllerBase
[HttpPost("/admin/teams")] [HttpPost("/admin/teams")]
public async Task<IActionResult> AddTeam([FromBody] AddTeamRequest req) public async Task<IActionResult> AddTeam([FromBody] AddTeamRequest req)
{ {
logger.LogTrace("Adding teams");
var team = await service.AddTeam(req.Name, req.Picture, req.FirstColor, req.SecondColor); var team = await service.AddTeam(req.Name, req.Picture, req.FirstColor, req.SecondColor);
return Ok(team); 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}")] [HttpPut("/admin/teams/{teamId:int}")]
public async Task<IActionResult> UpdateTeam([FromBody] UpdateTeamRequest req) public async Task<IActionResult> UpdateTeam(int teamId, [FromBody] UpdateTeamRequest req)
{ {
await service.UpdateTeam(new Team(req.Id, req.Name, req.Picture, req.MainColor, req.SecondaryColor)); logger.LogTrace("Updating teams");
await service.UpdateTeam(new Team(teamId, req.Name, req.Picture, req.MainColor, req.SecondaryColor));
return Ok(); return Ok();
} }
@ -61,6 +62,8 @@ public class TeamsAdminController(ITeamService service) : ControllerBase
[HttpPost("/admin/teams/remove-all")] [HttpPost("/admin/teams/remove-all")]
public async Task<IActionResult> DeleteTeams([FromBody] DeleteTeamsRequest req) public async Task<IActionResult> DeleteTeams([FromBody] DeleteTeamsRequest req)
{ {
logger.LogTrace("Deleting teams");
await service.RemoveTeams(req.Teams); await service.RemoveTeams(req.Teams);
return Ok(); return Ok();
} }

@ -5,10 +5,13 @@ using Services;
namespace API.Controllers.Admin; namespace API.Controllers.Admin;
/// <summary>
/// WARNING: This controller does not requires the requester to be authenticated, see https://codefirst.iut.uca.fr/git/IQBall/Server-Panel/issues/2
/// </summary>
/// <param name="service"></param>
[ApiController] [ApiController]
public class UsersAdminController(IUserService service) : ControllerBase public class UsersAdminController(IUserService service, ILogger<UsersAdminController> logger) : ControllerBase
{ {
public record CountUsersResponse(int Value); public record CountUsersResponse(int Value);
@ -18,20 +21,17 @@ public class UsersAdminController(IUserService service) : ControllerBase
string search string search
) )
{ {
logger.LogTrace("Counting Users");
return new CountUsersResponse(await service.UsersCount(search)); return new CountUsersResponse(await service.UsersCount(search));
} }
[HttpGet("/admin/users/count")] [HttpGet("/admin/users/count")]
public async Task<CountUsersResponse> CountUsers() public async Task<CountUsersResponse> CountUsers()
{ {
logger.LogTrace("Counting Users");
return new CountUsersResponse(await service.UsersCount()); return new CountUsersResponse(await service.UsersCount());
} }
// [HttpGet("/admin/users/count")]
// public async Task<CountUsersResponse> CountUsers()
// {
// return new CountUsersResponse(await service.UsersCount());
// }
[HttpGet("/admin/users")] [HttpGet("/admin/users")]
public async Task<IEnumerable<User>> ListUsers( public async Task<IEnumerable<User>> ListUsers(
@ -43,11 +43,10 @@ public class UsersAdminController(IUserService service) : ControllerBase
string? search string? search
) )
{ {
var result = search != null logger.LogTrace("Listing Users");
? 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}")] [HttpGet("/admin/users/{id:int}")]
@ -56,6 +55,8 @@ public class UsersAdminController(IUserService service) : ControllerBase
int id int id
) )
{ {
logger.LogTrace("Getting a specific User ({})", id);
var result = await service.GetUser(id); var result = await service.GetUser(id);
if (result == null) if (result == null)
return NotFound(); return NotFound();
@ -77,7 +78,10 @@ public class UsersAdminController(IUserService service) : ControllerBase
[HttpPost("/admin/users")] [HttpPost("/admin/users")]
public Task<User> AddUser([FromBody] AddUserRequest req) public Task<User> AddUser([FromBody] AddUserRequest req)
{ {
return service.CreateUser(req.Username, req.Email, req.Password, UsersController.DefaultProfilePicture, req.IsAdmin); logger.LogTrace("Adding a User");
return service.CreateUser(req.Username, req.Email, req.Password, UsersController.DefaultProfilePicture,
req.IsAdmin);
} }
public record RemoveUsersRequest(int[] Identifiers); public record RemoveUsersRequest(int[] Identifiers);
@ -85,6 +89,8 @@ public class UsersAdminController(IUserService service) : ControllerBase
[HttpPost("/admin/users/remove-all")] [HttpPost("/admin/users/remove-all")]
public async Task<IActionResult> RemoveUsers([FromBody] RemoveUsersRequest req) public async Task<IActionResult> RemoveUsers([FromBody] RemoveUsersRequest req)
{ {
logger.LogTrace("Removing Users");
await service.RemoveUsers(req.Identifiers); await service.RemoveUsers(req.Identifiers);
return Ok(); return Ok();
} }
@ -106,7 +112,10 @@ public class UsersAdminController(IUserService service) : ControllerBase
{ {
try try
{ {
await service.UpdateUser(new User(id, req.Username, req.Email, UsersController.DefaultProfilePicture, req.IsAdmin)); logger.LogTrace("Updating Users");
await service.UpdateUser(new User(id, req.Username, req.Email, UsersController.DefaultProfilePicture,
req.IsAdmin));
return Ok(); return Ok();
} }
catch (ServiceException e) catch (ServiceException e)

@ -16,7 +16,8 @@ public class TacticController(ITacticService service, IContextAccessor accessor)
public record UpdateNameRequest( public record UpdateNameRequest(
[StringLength(50, MinimumLength = 1)] [StringLength(50, MinimumLength = 1)]
[Name] [Name]
string Name); string Name
);
[HttpPut("/tactics/{tacticId:int}/name")] [HttpPut("/tactics/{tacticId:int}/name")]
[Authorize] [Authorize]
@ -81,12 +82,11 @@ public class TacticController(ITacticService service, IContextAccessor accessor)
{ {
var userId = accessor.CurrentUserId(HttpContext); var userId = accessor.CurrentUserId(HttpContext);
var courtType = req.CourtType switch if (!Enum.TryParse<CourtType>(req.CourtType, true, out var courtType))
{ {
"PLAIN" => CourtType.Plain, // unreachable if called by ASP
"HALF" => CourtType.Half, throw new ArgumentOutOfRangeException("for req.CourtType");
_ => throw new ArgumentOutOfRangeException() //unreachable }
};
var id = await service.AddTactic(userId, req.Name, courtType); var id = await service.AddTactic(userId, req.Name, courtType);
return new CreateNewResponse(id); return new CreateNewResponse(id);
@ -118,10 +118,10 @@ public class TacticController(ITacticService service, IContextAccessor accessor)
var json = await service.GetTacticStepContent(tacticId, stepId); var json = await service.GetTacticStepContent(tacticId, stepId);
return json != null ? Ok(JsonSerializer.Deserialize<object>(json)) : NotFound(); return json != null ? Ok(JsonSerializer.Deserialize<object>(json)) : NotFound();
} }
[HttpDelete("/tactics/{tacticId:int}/steps/{stepId:int}")] [HttpDelete("/tactics/{tacticId:int}/steps/{stepId:int}")]
[Authorize] [Authorize]
public async Task<IActionResult> RemoveStepContent(int tacticId, int stepId) public async Task<IActionResult> RemoveStep(int tacticId, int stepId)
{ {
var userId = accessor.CurrentUserId(HttpContext); var userId = accessor.CurrentUserId(HttpContext);
@ -140,16 +140,15 @@ public class TacticController(ITacticService service, IContextAccessor accessor)
[HttpPut("/tactics/{tacticId:int}/steps/{stepId:int}")] [HttpPut("/tactics/{tacticId:int}/steps/{stepId:int}")]
[Authorize] [Authorize]
public async Task<IActionResult> SaveStepContent(int tacticId, int stepId, [FromBody] SaveStepContentRequest req) public async Task<IActionResult> SaveStepContent(int tacticId, int stepId, [FromBody] SaveStepContentRequest req)
{ {
var userId = accessor.CurrentUserId(HttpContext); var userId = accessor.CurrentUserId(HttpContext);
if (!await service.HasAnyRights(userId, tacticId)) if (!await service.HasAnyRights(userId, tacticId))
{ {
return Unauthorized(); return Unauthorized();
} }
await service.SetTacticStepContent(tacticId, stepId, JsonSerializer.Serialize(req.Content)); var found = await service.SetTacticStepContent(tacticId, stepId, JsonSerializer.Serialize(req.Content));
return Ok(); return found ? Ok() : NotFound();
} }
} }

@ -30,9 +30,21 @@ public class TeamsController(ITeamService service, ITacticService tactics,IConte
} }
[HttpGet("/teams/{teamId:int}/members")] [HttpGet("/teams/{teamId:int}/members")]
public IActionResult GetMembersOf(int teamId) public async Task<IActionResult> 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( public record AddMemberRequest(
@ -47,9 +59,27 @@ public class TeamsController(ITeamService service, ITacticService tactics,IConte
{ {
throw new Exception($"Unable to convert string input '{req.Role}' to a role enum variant."); 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)
return Ok(await service.AddMember(teamId, req.UserId, role)); {
case ITeamService.TeamAccessibility.Authorized:
{
var result = 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();
}
} }
@ -65,15 +95,45 @@ public class TeamsController(ITeamService service, ITacticService tactics,IConte
throw new Exception($"Unable to convert string input '{req.Role}' to a role enum variant."); 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)); var accessibility =
return updated ? Ok() : NotFound(); 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}")] [HttpDelete("/team/{teamId:int}/members/{userId:int}")]
public async Task<IActionResult> RemoveMember(int teamId, int userId) public async Task<IActionResult> RemoveMember(int teamId, int userId)
{ {
var removed = await service.RemoveMember(teamId, userId); var accessibility =
return removed ? Ok() : NotFound(); 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();
}
} }
public record ShareTacticToTeamRequest( public record ShareTacticToTeamRequest(

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\API\API.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,37 @@
using API.Controllers;
using DbServices;
using Microsoft.AspNetCore.Identity.Data;
using Microsoft.Extensions.Configuration;
using Services;
namespace APIConsole
{
public class AuthenticationControllerConsole
{
private AuthenticationController _controller;
public AuthenticationControllerConsole()
{
AppContext.AppContext context = new AppContext.AppContext();
IUserService users = new DbUserService(context);
IConfiguration config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
_controller = new AuthenticationController(users, config);
}
public async void RegisterAccountTest()
{
var result =
await _controller.RegisterAccount(
new AuthenticationController.RegisterAccountRequest("test", "test@mail.com", "123456"));
Console.WriteLine($"RegisterAccount Result: {result}");
}
public async void GenerateTokenTest()
{
var result =
await _controller.GenerateToken(
new AuthenticationController.GenerateTokenRequest("test@mail.com", "123456"));
Console.WriteLine($"GenerateToken Result: {result}");
}
}
}

@ -0,0 +1,49 @@
namespace APIConsole
{
class Program
{
static void Main(string[] args)
{
var userConsole = new UsersControllerConsole();
var teamConsole = new TeamsControllerConsole();
var tacticConsole = new TacticsControllerConsole();
var authConsole = new AuthenticationControllerConsole();
var userAdminConsole = new UsersAdminControllerConsole();
var teamAdminConsole = new TeamsAdminControllerConsole();
userConsole.GetUserTest();
userConsole.GetUserDataTest();
teamConsole.GetMembersOfTest();
teamConsole.CreateTeamTest();
teamConsole.AddMemberTest();
teamConsole.UpdateMemberTest();
teamConsole.RemoveMemberTest();
tacticConsole.UpdateNameTest();
tacticConsole.GetTacticInfoTest();
tacticConsole.GetTacticStepsRootTest();
tacticConsole.CreateTacticTest();
tacticConsole.GetStepContentTest();
tacticConsole.RemoveStepTest();
tacticConsole.SaveStepContentTest();
authConsole.RegisterAccountTest();
authConsole.GenerateTokenTest();
userAdminConsole.CountUsersTest();
userAdminConsole.ListUsersTest();
userAdminConsole.GetUserTest();
userAdminConsole.AddUserTest();
userAdminConsole.RemoveUserTest();
userAdminConsole.UpdateUserTest();
teamAdminConsole.CountTeamsTest();
teamAdminConsole.ListTeamsTest();
teamAdminConsole.AddTeamTest();
teamAdminConsole.UpdateTeamTest();
teamAdminConsole.DeleteTeamTest();
}
}
}

@ -0,0 +1,64 @@
using API.Context;
using API.Controllers;
using DbServices;
using Services;
namespace APIConsole
{
public class TacticsControllerConsole
{
private TacticController _controller;
public TacticsControllerConsole()
{
AppContext.AppContext context = new AppContext.AppContext();
ITacticService tactics = new DbTacticService(context);
IContextAccessor accessor = new HttpContextAccessor();
_controller = new TacticController(tactics, accessor);
}
public async void UpdateNameTest()
{
var result = await _controller.UpdateName(1, new TacticController.UpdateNameRequest("NewName"));
Console.WriteLine($"UpdateName Result: {result}");
}
public async void GetTacticInfoTest()
{
var result = await _controller.GetTacticInfo(1);
Console.WriteLine($"GetTacticInfo Result: {result}");
}
public async void GetTacticStepsRootTest()
{
var result = await _controller.GetTacticStepsRoot(1);
Console.WriteLine($"GetTacticStepsRoot Result: {result}");
}
public async void CreateTacticTest()
{
var result = await _controller.CreateNew(new TacticController.CreateNewRequest("NewTactic", "PLAIN"));
Console.WriteLine($"CreateTactic Result: {result}");
}
public async void GetStepContentTest()
{
var result = await _controller.GetStepContent(1, 1);
Console.WriteLine($"GetStepContent Result: {result}");
}
public async void RemoveStepTest()
{
var result = await _controller.RemoveStep(1, 1);
Console.WriteLine($"RemoveStep Result: {result}");
}
public async void SaveStepContentTest()
{
var result = await _controller.SaveStepContent(1, 1, new TacticController.SaveStepContentRequest("NewContent"));
Console.WriteLine($"SaveStepContent Result: {result}");
}
}
}

@ -0,0 +1,53 @@
using API.Controllers.Admin;
using DbServices;
using Microsoft.Extensions.Logging;
using Services;
namespace APIConsole
{
public class TeamsAdminControllerConsole
{
private TeamsAdminController _controller;
public TeamsAdminControllerConsole()
{
AppContext.AppContext context = new AppContext.AppContext();
ITeamService teams = new DbTeamService(context);
ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger<TeamsAdminController> logger = loggerFactory.CreateLogger<TeamsAdminController>();
_controller = new TeamsAdminController(teams, logger);
}
public async void CountTeamsTest()
{
var result = await _controller.CountTeams();
Console.WriteLine($"CountTeams Result: {result}");
}
public async void ListTeamsTest()
{
var result = await _controller.ListTeams(0, 10);
Console.WriteLine($"ListTeams Result: {result}");
}
public async void AddTeamTest()
{
var result =
await _controller.AddTeam(new TeamsAdminController.AddTeamRequest("Lakers", "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Los_Angeles_Lakers_logo.svg/2560px-Los_Angeles_Lakers_logo.svg.png", "#FFFFFF", "#000000"));
Console.WriteLine($"AddTeam Result: {result}");
}
public async void UpdateTeamTest()
{
var result =
await _controller.UpdateTeam(1, new TeamsAdminController.UpdateTeamRequest("Lakers", "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Los_Angeles_Lakers_logo.svg/2560px-Los_Angeles_Lakers_logo.svg.png", "#999999", "#000000"));
Console.WriteLine($"UpdateTeam Result: {result}");
}
public async void DeleteTeamTest()
{
var result = await _controller.DeleteTeams(new TeamsAdminController.DeleteTeamsRequest([1]));
Console.WriteLine($"RemoveTeam Result: {result}");
}
}
}

@ -0,0 +1,54 @@
using System;
using API.Context;
using API.Controllers;
using API.DTO;
using DbServices;
using Model;
using Services;
namespace APIConsole
{
public class TeamsControllerConsole
{
private TeamsController _controller;
public TeamsControllerConsole()
{
AppContext.AppContext context = new AppContext.AppContext();
ITeamService teams = new DbTeamService(context);
ITacticService tactics = new DbTacticService(context);
IContextAccessor accessor = new HttpContextAccessor();
_controller = new TeamsController(teams, tactics, accessor);
}
public async void GetMembersOfTest()
{
var result = await _controller.GetMembersOf(1);
Console.WriteLine($"GetMembersOf Result: {result}");
}
public async void CreateTeamTest()
{
var result = await _controller.CreateTeam(new TeamsController.CreateTeamRequest("Lakers", "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Los_Angeles_Lakers_logo.svg/2560px-Los_Angeles_Lakers_logo.svg.png", "#FFFFFF", "#000000"));
Console.WriteLine($"CreateTeam Result: {result}");
}
public async void AddMemberTest()
{
var result = await _controller.AddMember(1, new TeamsController.AddMemberRequest(1, "PLAYER"));
Console.WriteLine($"AddMember Result: {result}");
}
public async void UpdateMemberTest()
{
var result = await _controller.UpdateMember(1, 1, new TeamsController.UpdateMemberRequest("COACH"));
Console.WriteLine($"UpdateMember Result: {result}");
}
public async void RemoveMemberTest()
{
var result = await _controller.RemoveMember(1, 1);
Console.WriteLine($"RemoveMember Result: {result}");
}
}
}

@ -0,0 +1,60 @@
using API.Controllers.Admin;
using DbServices;
using Microsoft.Extensions.Logging;
using Services;
namespace APIConsole
{
public class UsersAdminControllerConsole
{
private UsersAdminController _controller;
public UsersAdminControllerConsole()
{
AppContext.AppContext context = new AppContext.AppContext();
IUserService users = new DbUserService(context);
ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger<UsersAdminController> logger = loggerFactory.CreateLogger<UsersAdminController>();
_controller = new UsersAdminController(users, logger);
}
public async void CountUsersTest()
{
var result = await _controller.CountUsers();
Console.WriteLine($"CountUsers Result: {result}");
}
public async void ListUsersTest()
{
var result = await _controller.ListUsers(0, 10, null);
Console.WriteLine($"ListUsers Result: {result}");
}
public async void GetUserTest()
{
var result = await _controller.GetUser(1);
Console.WriteLine($"GetUser Result: {result}");
}
public async void AddUserTest()
{
var result =
await _controller.AddUser(new UsersAdminController.AddUserRequest("test", "123456", "test@mail.com"));
Console.WriteLine($"AddUser Result: {result}");
}
public async void RemoveUserTest()
{
var result = await _controller.RemoveUsers(new UsersAdminController.RemoveUsersRequest([1]));
Console.WriteLine($"RemoveUser Result: {result}");
}
public async void UpdateUserTest()
{
var result =
await _controller.UpdateUser(1, new UsersAdminController.UpdateUserRequest("testtest", "123456", false));
Console.WriteLine($"UpdateUser Result: {result}");
}
}
}

@ -0,0 +1,36 @@
using API.Context;
using API.Controllers;
using DbServices;
using Services;
namespace APIConsole
{
public class UsersControllerConsole
{
private UsersController _controller;
public UsersControllerConsole()
{
AppContext.AppContext context = new AppContext.AppContext();
IUserService users = new DbUserService(context);
ITeamService teams = new DbTeamService(context);
ITacticService tactics = new DbTacticService(context);
IContextAccessor accessor = new HttpContextAccessor();
_controller = new UsersController(users, teams, tactics, accessor);
}
public async void GetUserTest()
{
var result = await _controller.GetUser();
Console.WriteLine($"GetUser Result: {result}");
}
public async void GetUserDataTest()
{
var result = await _controller.GetUserData();
Console.WriteLine($"GetUserData Result: {result}");
}
}
}

@ -28,23 +28,19 @@ public class AppContext : DbContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
base.OnConfiguring(optionsBuilder); if (!optionsBuilder.IsConfigured)
if (optionsBuilder.IsConfigured)
{ {
return; var pgsqliteDsn = Environment.GetEnvironmentVariable("PGSQL_DSN");
}
var pgsqliteDsn = Environment.GetEnvironmentVariable("PGSQL_DSN");
if (pgsqliteDsn != null) if (pgsqliteDsn != null)
{ {
optionsBuilder.UseNpgsql(pgsqliteDsn); optionsBuilder.UseNpgsql(pgsqliteDsn);
}
else
{
optionsBuilder.UseSqlite("Data Source=database.db");
}
} }
else
{
optionsBuilder.UseSqlite("Data Source=database.db");
}
} }
protected override void OnModelCreating(ModelBuilder builder) protected override void OnModelCreating(ModelBuilder builder)

@ -1,3 +1,4 @@
using System.ComponentModel.DataAnnotations;
using Model; using Model;
namespace AppContext.Entities; namespace AppContext.Entities;
@ -15,5 +16,6 @@ public class TacticStepEntity
public required int? ParentId { get; set; } public required int? ParentId { get; set; }
public TacticStepEntity? Parent { get; set; } public TacticStepEntity? Parent { get; set; }
[MaxLength(2_000_000)]
public required string JsonContent { get; set; } public required string JsonContent { get; set; }
} }

@ -1,4 +1,3 @@
using System.Collections;
using AppContext.Entities; using AppContext.Entities;
using Converters; using Converters;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -49,6 +48,7 @@ public class DbTacticService(AppContext.AppContext context) : ITacticService
await context.TacticSteps.AddAsync(stepEntity); await context.TacticSteps.AddAsync(stepEntity);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
return tacticEntity.Id; return tacticEntity.Id;
} }
@ -59,7 +59,8 @@ public class DbTacticService(AppContext.AppContext context) : ITacticService
return false; return false;
entity.Name = name; entity.Name = name;
return await context.SaveChangesAsync() > 0; await context.SaveChangesAsync();
return true;
} }
public async Task<bool> SetTacticStepContent(int tacticId, int stepId, string json) public async Task<bool> SetTacticStepContent(int tacticId, int stepId, string json)
@ -70,7 +71,8 @@ public class DbTacticService(AppContext.AppContext context) : ITacticService
return false; return false;
entity.JsonContent = json; entity.JsonContent = json;
return await context.SaveChangesAsync() > 0; await context.SaveChangesAsync();
return true;
} }
public async Task<string?> GetTacticStepContent(int tacticId, int stepId) public async Task<string?> GetTacticStepContent(int tacticId, int stepId)
@ -108,6 +110,11 @@ public class DbTacticService(AppContext.AppContext context) : ITacticService
public async Task<int?> AddTacticStep(int tacticId, int parentStepId, string initialJson) public async Task<int?> AddTacticStep(int tacticId, int parentStepId, string initialJson)
{ {
var parentExists = context.TacticSteps.Any(t => t.TacticId == tacticId && t.Id == parentStepId);
if (!parentExists)
return null;
var tactic = await context.Tactics.FirstOrDefaultAsync(t => t.Id == tacticId); var tactic = await context.Tactics.FirstOrDefaultAsync(t => t.Id == tacticId);
if (tactic == null) if (tactic == null)
{ {

@ -19,28 +19,18 @@ public class DbTeamService(AppContext.AppContext context) : ITeamService
); );
} }
public Task<IEnumerable<Team>> ListTeams(string nameNeedle)
{
return Task.FromResult(
context.Teams.Where(t => t.Name.ToLower().Contains(nameNeedle.ToLower()))
.AsEnumerable()
.Select(e => e.ToModel())
);
}
public Task<IEnumerable<Team>> ListTeams() public Task<IEnumerable<Team>> ListTeams(int start, int count)
{ {
return Task.FromResult( return Task.FromResult(
context.Teams context.Teams
.Skip(start)
.Take(count)
.AsEnumerable() .AsEnumerable()
.Select(e => e.ToModel()) .Select(e => e.ToModel())
); );
} }
public async Task<int> CountTeams(string nameNeedle)
{
return await context.Teams.CountAsync(t => t.Name.ToLower().Contains(nameNeedle.ToLower()));
}
public async Task<int> CountTotalTeams() public async Task<int> CountTotalTeams()
{ {
@ -107,15 +97,21 @@ public class DbTeamService(AppContext.AppContext context) : ITeamService
} }
public IEnumerable<Member> GetMembersOf(int teamId) public Task<IEnumerable<Member>> GetMembersOf(int teamId)
{ {
return context.Members.Where(m => m.TeamId == teamId) return Task.FromResult(context.Members
.Where(m => m.TeamId == teamId)
.AsEnumerable() .AsEnumerable()
.Select(e => e.ToModel()); .Select(e => e.ToModel()));
} }
public async Task<Member> AddMember(int teamId, int userId, MemberRole role) public async Task<Member?> 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 await context.Members.AddAsync(new MemberEntity
{ {
TeamId = teamId, TeamId = teamId,
@ -139,10 +135,24 @@ public class DbTeamService(AppContext.AppContext context) : ITeamService
public async Task<bool> RemoveMember(int teamId, int userId) public async Task<bool> RemoveMember(int teamId, int userId)
{ {
await context.Members return await context.Members
.Where(e => e.TeamId == teamId && e.UserId == userId) .Where(e => e.TeamId == teamId && e.UserId == userId)
.ExecuteDeleteAsync(); .ExecuteDeleteAsync() > 0;
return await context.SaveChangesAsync() > 0; }
public async Task<ITeamService.TeamAccessibility> 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;
} }
public async Task<bool> IsUserInTeam(int userId, int teamId) public async Task<bool> IsUserInTeam(int userId, int teamId)

@ -20,20 +20,18 @@ public class DbUserService(AppContext.AppContext context) : IUserService
return context.Users.CountAsync(); return context.Users.CountAsync();
} }
public Task<IEnumerable<User>> ListUsers(string nameNeedle) public Task<IEnumerable<User>> 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<IEnumerable<User>> ListUsers() IQueryable<UserEntity> request = context.Users;
{
if (nameNeedle != null)
request = request.Where(u => u.Name.ToLower().Contains(nameNeedle.ToLower()));
return Task.FromResult( return Task.FromResult(
context.Users request
.Skip(start)
.Take(count)
.AsEnumerable() .AsEnumerable()
.Select(e => e.ToModel()) .Select(e => e.ToModel())
); );
@ -69,7 +67,10 @@ public class DbUserService(AppContext.AppContext context) : IUserService
public async Task<bool> RemoveUsers(params int[] identifiers) public async Task<bool> 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) public async Task UpdateUser(User user)

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DbServices\DbServices.csproj" />
<ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\StubContext\StubContext.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
</ItemGroup>
</Project>

@ -0,0 +1,88 @@
using System;
using System.Linq;
using AppContext.Entities;
using Model;
namespace EFConsole
{
public class MembersConsole
{
public static void TestAddMember(AppContext.AppContext db)
{
var newMember = new MemberEntity
{
TeamId = 1,
UserId = 1,
Role = MemberRole.Player
};
db.Members.Add(newMember);
db.SaveChanges();
Console.WriteLine("Membre ajouté avec succès !");
}
public static void TestGetAllMembers(AppContext.AppContext db)
{
var members = db.Members.ToList();
Console.WriteLine("Liste des membres :");
foreach (var member in members)
{
Console.WriteLine($"ID Équipe : {member.TeamId}, ID Utilisateur : {member.UserId}, Rôle : {member.Role}");
}
}
public static void TestGetMembersByTeamId(AppContext.AppContext db, int teamId)
{
var members = db.Members.Where(m => m.TeamId == teamId).ToList();
Console.WriteLine($"Membres de l'équipe avec ID {teamId} :");
foreach (var member in members)
{
Console.WriteLine($"ID Équipe : {member.TeamId}, ID Utilisateur : {member.UserId}, Rôle : {member.Role}");
}
}
public static void TestGetMembersByUserId(AppContext.AppContext db, int userId)
{
var members = db.Members.Where(m => m.UserId == userId).ToList();
Console.WriteLine($"Membres associés à l'utilisateur avec ID {userId} :");
foreach (var member in members)
{
Console.WriteLine($"ID Équipe : {member.TeamId}, ID Utilisateur : {member.UserId}, Rôle : {member.Role}");
}
}
public static void TestUpdateMemberRole(AppContext.AppContext db, int teamId, int memberId, MemberRole newRole)
{
var memberToUpdate = db.Members.FirstOrDefault(m => m.TeamId == teamId && m.UserId == memberId); // Trouver le membre dans l'équipe spécifiée
if (memberToUpdate != null)
{
memberToUpdate.Role = newRole;
db.SaveChanges();
Console.WriteLine("Rôle du membre mis à jour avec succès !");
}
else
{
Console.WriteLine($"Aucun membre trouvé dans l'équipe avec l'ID {teamId} et l'ID utilisateur {memberId}.");
}
}
public static void TestRemoveMember(AppContext.AppContext db, int teamId, int memberId)
{
var memberToDelete = db.Members.FirstOrDefault(m => m.TeamId == teamId && m.UserId == memberId); // Trouver le membre dans l'équipe spécifiée
if (memberToDelete != null)
{
db.Members.Remove(memberToDelete); // Supprimer le membre
db.SaveChanges();
Console.WriteLine("Membre supprimé avec succès !");
}
else
{
Console.WriteLine($"Aucun membre trouvé dans l'équipe avec l'ID {teamId} et l'ID utilisateur {memberId} pour la suppression.");
}
}
}
}

@ -0,0 +1,85 @@
using Model;
using StubContext;
namespace EFConsole
{
class Program
{
static void Main(string[] args)
{
Console.OutputEncoding = System.Text.Encoding.UTF8;
try
{
using (AppContext.AppContext db = new StubAppContext())
{
TestUserMethods(db);
TestTacticMethods(db);
TestTeamMethods(db);
TestMemberMethods(db);
TestTacticsStepMethods(db);
}
}
catch (Exception ex)
{
Console.WriteLine($"Une erreur s'est produite : {ex.Message}");
if (ex.InnerException != null)
{
Console.WriteLine($"Détails de l'exception interne : {ex.InnerException.Message}");
}
}
}
static void TestUserMethods(AppContext.AppContext db)
{
UsersConsole.TestAddUser(db);
UsersConsole.TestGetAllUsers(db);
UsersConsole.TestFindUserByMail(db, "maxime@mail.com");
UsersConsole.TestUpdateUser(db);
UsersConsole.TestDeleteUser(db);
UsersConsole.TestSearchUsersByName(db, "Pierre");
UsersConsole.TestGetTacticsOfAllUsers(db);
UsersConsole.TestGetTacticsOfOneUser(db, 1);
}
static void TestTacticMethods(AppContext.AppContext db)
{
TacticsConsole.TestAddTactic(db);
TacticsConsole.TestGetAllTactics(db);
TacticsConsole.TestFindTacticById(db, 1);
TacticsConsole.TestUpdateTactic(db, 1, "Nouveau nom");
TacticsConsole.TestDeleteTactic(db, 1);
TacticsConsole.TestGetTacticsByOwner(db, 1);
}
static void TestTeamMethods(AppContext.AppContext db)
{
TeamsConsole.TestAddTeam(db);
TeamsConsole.TestGetAllTeams(db);
TeamsConsole.TestGetTeamMembers(db, 1);
TeamsConsole.TestUpdateTeam(db, 1, "Nouveau nom", "Nouvelle image", "#FF0000", "#00FF00");
TeamsConsole.TestDeleteTeam(db, 1);
}
static void TestMemberMethods(AppContext.AppContext db)
{
MembersConsole.TestAddMember(db);
MembersConsole.TestGetAllMembers(db);
MembersConsole.TestGetMembersByTeamId(db, 1);
MembersConsole.TestGetMembersByUserId(db, 1);
MembersConsole.TestUpdateMemberRole(db, 1, 1, MemberRole.Coach);
MembersConsole.TestRemoveMember(db, 1, 1);
}
static void TestTacticsStepMethods(AppContext.AppContext db)
{
TacticsStepConsole.TestAddTacticStep(db);
TacticsStepConsole.TestGetAllTacticSteps(db);
TacticsStepConsole.TestGetTacticStepsByTacticId(db, 1);
TacticsStepConsole.TestUpdateTacticStepContent(db, 1, "test content");
TacticsStepConsole.TestDeleteTacticStep(db, 1);
}
}
}

@ -0,0 +1,89 @@
using System;
using System.Linq;
using AppContext.Entities;
using Model;
namespace EFConsole
{
class TacticsConsole
{
internal static void TestAddTactic(AppContext.AppContext db)
{
var newTactic = new TacticEntity
{
Name = "Nouvelle tactique",
CreationDate = DateTime.Now,
OwnerId = 1,
Type = CourtType.Plain
};
db.Tactics.Add(newTactic);
db.SaveChanges();
Console.WriteLine("Tactique ajoutée avec succès !");
}
internal static void TestGetAllTactics(AppContext.AppContext db)
{
var tactics = db.Tactics.ToList();
Console.WriteLine("Liste des tactiques :");
foreach (var tactic in tactics)
{
Console.WriteLine($"ID : {tactic.Id}, Nom : {tactic.Name}, Date de création : {tactic.CreationDate}");
}
}
internal static void TestFindTacticById(AppContext.AppContext db, int tacticId)
{
var tactic = db.Tactics.FirstOrDefault(t => t.Id == tacticId);
if (tactic != null)
{
Console.WriteLine($"Tactique trouvée avec l'ID {tacticId}: Nom : {tactic.Name}, Date de création : {tactic.CreationDate}");
}
else
{
Console.WriteLine($"Aucune tactique trouvée avec l'ID {tacticId}");
}
}
internal static void TestUpdateTactic(AppContext.AppContext db, int tacticId, string newName)
{
var tacticToUpdate = db.Tactics.FirstOrDefault(t => t.Id == tacticId);
if (tacticToUpdate != null)
{
tacticToUpdate.Name = newName;
db.SaveChanges();
Console.WriteLine($"Tactique mise à jour avec succès !");
}
else
{
Console.WriteLine($"Aucune tactique trouvée avec l'ID {tacticId}");
}
}
internal static void TestDeleteTactic(AppContext.AppContext db, int tacticId)
{
var tacticToDelete = db.Tactics.FirstOrDefault(t => t.Id == tacticId);
if (tacticToDelete != null)
{
db.Tactics.Remove(tacticToDelete);
db.SaveChanges();
Console.WriteLine($"Tactique supprimée avec succès !");
}
else
{
Console.WriteLine($"Aucune tactique trouvée avec l'ID {tacticId}");
}
}
internal static void TestGetTacticsByOwner(AppContext.AppContext db, int ownerId)
{
var tactics = db.Tactics.Where(t => t.OwnerId == ownerId).ToList();
Console.WriteLine($"Tactiques de l'utilisateur avec l'ID {ownerId} :");
foreach (var tactic in tactics)
{
Console.WriteLine($"ID : {tactic.Id}, Nom : {tactic.Name}, Date de création : {tactic.CreationDate}");
}
}
}
}

@ -0,0 +1,75 @@
using System;
using System.Linq;
using AppContext.Entities;
using Model;
namespace EFConsole
{
public class TacticsStepConsole
{
public static void TestAddTacticStep(AppContext.AppContext db)
{
var newTacticStep = new TacticStepEntity
{
ParentId = 1,
TacticId = 1,
JsonContent = "{}"
};
db.TacticSteps.Add(newTacticStep);
db.SaveChanges();
Console.WriteLine("Étape de tactique ajoutée avec succès !");
}
public static void TestGetAllTacticSteps(AppContext.AppContext db)
{
var tacticSteps = db.TacticSteps.ToList();
Console.WriteLine("Liste des étapes de tactique :");
foreach (var tacticStep in tacticSteps)
{
Console.WriteLine($"ID : {tacticStep.Id}, ID Tactique : {tacticStep.TacticId}, Contenu JSON : {tacticStep.JsonContent}");
}
}
public static void TestGetTacticStepsByTacticId(AppContext.AppContext db, int tacticId)
{
var tacticSteps = db.TacticSteps.Where(ts => ts.TacticId == tacticId).ToList();
Console.WriteLine($"Étapes de tactique pour la tactique avec l'ID {tacticId} :");
foreach (var tacticStep in tacticSteps)
{
Console.WriteLine($"ID : {tacticStep.Id}, ID Tactique : {tacticStep.TacticId}, Contenu JSON : {tacticStep.JsonContent}");
}
}
public static void TestUpdateTacticStepContent(AppContext.AppContext db, int tacticStepId, string newContent)
{
var tacticStepToUpdate = db.TacticSteps.FirstOrDefault(ts => ts.Id == tacticStepId);
if (tacticStepToUpdate != null)
{
tacticStepToUpdate.JsonContent = newContent;
db.SaveChanges();
Console.WriteLine("Contenu de l'étape de tactique mis à jour avec succès !");
}
else
{
Console.WriteLine($"Aucune étape de tactique trouvée avec l'ID {tacticStepId} pour la mise à jour du contenu.");
}
}
public static void TestDeleteTacticStep(AppContext.AppContext db, int tacticStepId)
{
var tacticStepToDelete = db.TacticSteps.FirstOrDefault(ts => ts.Id == tacticStepId);
if (tacticStepToDelete != null)
{
db.TacticSteps.Remove(tacticStepToDelete);
db.SaveChanges();
Console.WriteLine("Étape de tactique supprimée avec succès !");
}
else
{
Console.WriteLine($"Aucune étape de tactique trouvée avec l'ID {tacticStepId} pour la suppression.");
}
}
}
}

@ -0,0 +1,85 @@
using System;
using System.Linq;
using AppContext.Entities;
namespace EFConsole
{
class TeamsConsole
{
internal static void TestAddTeam(AppContext.AppContext db)
{
var newTeam = new TeamEntity
{
Name = "Nouvelle équipe",
Picture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png",
MainColor = "#0000FF",
SecondColor = "#FFFFFF"
};
db.Teams.Add(newTeam);
db.SaveChanges();
Console.WriteLine("Équipe ajoutée avec succès !");
}
internal static void TestGetAllTeams(AppContext.AppContext db)
{
var teams = db.Teams.ToList();
Console.WriteLine("Liste des équipes :");
foreach (var team in teams)
{
Console.WriteLine($"ID : {team.Id}, Nom : {team.Name}, Image : {team.Picture}, Couleur principale : {team.MainColor}, Couleur secondaire : {team.SecondColor}");
}
}
internal static void TestGetTeamMembers(AppContext.AppContext db, int teamId)
{
var team = db.Teams.FirstOrDefault(t => t.Id == teamId);
if (team != null)
{
Console.WriteLine($"Membres de l'équipe '{team.Name}' :");
foreach (var member in team.Members)
{
Console.WriteLine($"ID : {member.UserId}, Nom : {member.User?.Name}, Rôle : {member.Role}");
}
}
else
{
Console.WriteLine($"Aucune équipe trouvée avec l'ID : {teamId}");
}
}
internal static void TestUpdateTeam(AppContext.AppContext db, int teamId, string newName, string newPicture, string newMainColor, string newSecondColor)
{
var teamToUpdate = db.Teams.FirstOrDefault(t => t.Id == teamId);
if (teamToUpdate != null)
{
teamToUpdate.Name = newName;
teamToUpdate.Picture = newPicture;
teamToUpdate.MainColor = newMainColor;
teamToUpdate.SecondColor = newSecondColor;
db.SaveChanges();
Console.WriteLine("Équipe mise à jour avec succès !");
}
else
{
Console.WriteLine($"Aucune équipe trouvée avec l'ID : {teamId}");
}
}
internal static void TestDeleteTeam(AppContext.AppContext db, int teamId)
{
var teamToDelete = db.Teams.FirstOrDefault(t => t.Id == teamId);
if (teamToDelete != null)
{
db.Teams.Remove(teamToDelete);
db.SaveChanges();
Console.WriteLine("Équipe supprimée avec succès !");
}
else
{
Console.WriteLine($"Aucune équipe trouvée avec l'ID : {teamId}");
}
}
}
}

@ -0,0 +1,120 @@
using Microsoft.EntityFrameworkCore;
namespace EFConsole;
class UsersConsole
{
internal static void TestAddUser(AppContext.AppContext db)
{
var newUser = new AppContext.Entities.UserEntity
{
Name = "Pierre",
Email = "pierre@mail.com",
Password = "123456",
ProfilePicture = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png",
IsAdmin = false
};
db.Users.Add(newUser);
db.SaveChanges();
Console.WriteLine("Utilisateur ajouté avec succès !");
}
internal static void TestGetAllUsers(AppContext.AppContext db)
{
var users = db.Users.ToList();
Console.WriteLine("Liste des utilisateurs :");
foreach (var user in users)
{
Console.WriteLine($"ID : {user.Id}, Nom : {user.Name}, Email : {user.Email}");
}
}
internal static void TestFindUserByMail(AppContext.AppContext db, string userEmail)
{
var userByEmail = db.Users.FirstOrDefault(u => u.Email == userEmail);
if (userByEmail != null)
{
Console.WriteLine($"Utilisateur trouvé par email : {userByEmail.Name}");
}
else
{
Console.WriteLine($"Aucun utilisateur trouvé avec l'email : {userEmail}");
}
}
internal static void TestUpdateUser(AppContext.AppContext db)
{
var userToUpdate = db.Users.FirstOrDefault(u => u.Name == "Pierre");
if (userToUpdate != null)
{
userToUpdate.Name = "Paul";
db.SaveChanges();
Console.WriteLine("Utilisateur mis à jour avec succès !");
}
else
{
Console.WriteLine("Utilisateur non trouvé pour la mise à jour.");
}
}
internal static void TestDeleteUser(AppContext.AppContext db)
{
var userToDelete = db.Users.FirstOrDefault(u => u.Name == "Paul");
if (userToDelete != null)
{
db.Users.Remove(userToDelete);
db.SaveChanges();
Console.WriteLine("Utilisateur supprimé avec succès !");
}
else
{
Console.WriteLine("Utilisateur non trouvé pour la suppression.");
}
}
internal static void TestSearchUsersByName(AppContext.AppContext db, string userName)
{
var usersByName = db.Users.Where(u => u.Name == userName).ToList();
Console.WriteLine($"Utilisateurs avec le nom '{userName}' :");
foreach (var user in usersByName)
{
Console.WriteLine($"ID : {user.Id}, Nom : {user.Name}, Email : {user.Email}");
}
}
internal static void TestGetTacticsOfAllUsers(AppContext.AppContext db)
{
Console.WriteLine("Récupération des tactiques de tous les utilisateurs :");
var users = db.Users.Include(u => u.Tactics).ToList();
foreach (var user in users)
{
Console.WriteLine($"Tactiques de l'utilisateur {user.Name}:");
foreach (var tactic in user.Tactics)
{
Console.WriteLine($"\tID : {tactic.Id}, Nom : {tactic.Name}, Date de création : {tactic.CreationDate}");
}
}
}
internal static void TestGetTacticsOfOneUser(AppContext.AppContext db, int userId)
{
var user = db.Users.Include(u => u.Tactics).FirstOrDefault(u => u.Id == userId);
if (user != null)
{
Console.WriteLine($"Récupération des tactiques de l'utilisateur {user.Name}:");
foreach (var tactic in user.Tactics)
{
Console.WriteLine($"\tID : {tactic.Id}, Nom : {tactic.Name}, Date de création : {tactic.CreationDate}");
}
}
else
{
Console.WriteLine($"Aucun utilisateur trouvé avec l'ID : {userId}");
}
}
}

@ -7,8 +7,5 @@ public record Failure(string Name, string Message)
return new("not found", message); return new("not found", message);
} }
public static Failure Forbidden(string message)
{
return new("forbidden", message);
}
} }

@ -2,28 +2,100 @@ using Model;
namespace Services; namespace Services;
/// <summary>
/// Represents a service interface for managing tactics.
/// </summary>
public interface ITacticService public interface ITacticService
{ {
/// <summary>
/// Retrieves a list of tactics owned by the specified user.
/// </summary>
/// <param name="userId">The ID of the user.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a list of tactics.</returns>
Task<IEnumerable<Tactic>> ListTacticsOf(int userId);
public Task<IEnumerable<Tactic>> ListTacticsOf(int userId); /// <summary>
/// Checks if the user has any rights to access the specified tactic.
public Task<bool> HasAnyRights(int userId, int tacticId); /// </summary>
/// <param name="userId">The ID of the user.</param>
/// <param name="tacticId">The ID of the tactic.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a boolean indicating whether the user has rights.</returns>
Task<bool> HasAnyRights(int userId, int tacticId);
/// <summary>
/// Adds a new tactic for the specified user.
/// </summary>
/// <param name="userId">The ID of the user.</param>
/// <param name="name">The name of the tactic.</param>
/// <param name="courtType">The type of court.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the ID of the newly added tactic.</returns>
Task<int> AddTactic(int userId, string name, CourtType courtType);
public Task<int> AddTactic(int userId, string name, CourtType courtType); /// <summary>
/// Updates the name of the specified tactic.
/// </summary>
/// <param name="tacticId">The ID of the tactic.</param>
/// <param name="name">The new name of the tactic.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a boolean indicating whether the update was successful.</returns>
Task<bool> UpdateName(int tacticId, string name);
public Task<bool> UpdateName(int tacticId, string name); /// <summary>
public Task<bool> SetTacticStepContent(int tacticId, int stepId, string json); /// Sets the content of a tactic step.
public Task<string?> GetTacticStepContent(int tacticId, int stepId); /// </summary>
/// <param name="tacticId">The ID of the tactic.</param>
/// <param name="stepId">The ID of the step.</param>
/// <param name="json">The JSON content to set.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a boolean indicating whether the operation was successful.</returns>
Task<bool> SetTacticStepContent(int tacticId, int stepId, string json);
/// <summary>
/// Retrieves the content of a tactic step.
/// </summary>
/// <param name="tacticId">The ID of the tactic.</param>
/// <param name="stepId">The ID of the step.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the JSON content of the step.</returns>
Task<string?> GetTacticStepContent(int tacticId, int stepId);
public Task<Tactic?> GetTactic(int tacticId);
public Task<TacticStep> GetRootStep(int tacticId);
public Task<IEnumerable<Tactic>> ListUserTactics(int userId);
public Task<int?> AddTacticStep(int tacticId, int parentStepId, string initialJson);
public Task<bool> RemoveTacticStep(int tacticId, int stepId);
public Task<bool> ShareTactic(int tacticId, int? userId, int? teamId); public Task<bool> ShareTactic(int tacticId, int? userId, int? teamId);
public Task<bool> UnshareTactic(int tacticId, int? userId, int? teamId); public Task<bool> UnshareTactic(int tacticId, int? userId, int? teamId);
/// <summary>
/// Retrieves the root step of the specified tactic.
/// </summary>
/// <param name="tacticId">The ID of the tactic.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the root step of the tactic.</returns>
Task<TacticStep> GetRootStep(int tacticId);
/// <summary>
/// Retrieves the tactic with the specified ID.
/// </summary>
/// <param name="tacticId">The ID of the tactic.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the tactic.</returns>
Task<Tactic?> GetTactic(int tacticId);
/// <summary>
/// Retrieves a list of tactics owned by the specified user.
/// </summary>
/// <param name="userId">The ID of the user.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a list of tactics.</returns>
Task<IEnumerable<Tactic>> ListUserTactics(int userId);
/// <summary>
/// Adds a new step to the specified tactic.
/// </summary>
/// <param name="tacticId">The ID of the tactic.</param>
/// <param name="parentStepId">The ID of the parent step.</param>
/// <param name="initialJson">The initial JSON content of the step.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the ID of the newly added step.</returns>
Task<int?> AddTacticStep(int tacticId, int parentStepId, string initialJson);
/// <summary>
/// Removes the specified step from the tactic, along with its child steps if any.
/// </summary>
/// <param name="tacticId">The ID of the tactic.</param>
/// <param name="stepId">The ID of the step to remove.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a boolean indicating whether the removal was successful.</returns>
Task<bool> RemoveTacticStep(int tacticId, int stepId);
} }

@ -2,29 +2,90 @@ using Model;
namespace Services; namespace Services;
/// <summary>
/// Represents a service for managing teams.
/// </summary>
public interface ITeamService public interface ITeamService
{ {
public Task<IEnumerable<Team>> ListTeamsOf(int userId); /// <summary>
/// Lists all teams associated with the specified <paramref name="userId"/>.
/// </summary>
Task<IEnumerable<Team>> ListTeamsOf(int userId);
/// <summary>
/// Lists a range of teams.
/// </summary>
Task<IEnumerable<Team>> ListTeams(int start, int count);
public Task<IEnumerable<Team>> ListTeams(); /// <summary>
public Task<int> CountTotalTeams(); /// Retrieves the total count of teams.
/// </summary>
Task<int> CountTotalTeams();
public Task<Team> AddTeam(string name, string picture, string firstColor, string secondColor); /// <summary>
public Task RemoveTeams(params int[] teams); /// Adds a new team.
/// </summary>
Task<Team> AddTeam(string name, string picture, string firstColor, string secondColor);
public IEnumerable<Member> GetMembersOf(int teamId); /// <summary>
/// Removes one or more teams.
/// </summary>
Task RemoveTeams(params int[] teams);
public Task<Member> AddMember(int teamId, int userId, MemberRole role); /// <summary>
/// Updates an existing team.
public Task<bool> UpdateMember(Member member); /// </summary>
Task<bool> UpdateTeam(Team team);
public Task<bool> RemoveMember(int teamId, int userId); /// <summary>
/// Retrieves the members of the specified team.
/// </summary>
Task<IEnumerable<Member>> GetMembersOf(int teamId);
public Task<bool> UpdateTeam(Team team); /// <summary>
/// Adds a new member to the team.
/// </summary>
Task<Member?> AddMember(int teamId, int userId, MemberRole role);
/// <summary>
/// Updates the role of a member within the team.
/// </summary>
Task<bool> UpdateMember(Member member);
/// <summary>
/// Removes a member from the team.
/// </summary>
Task<bool> RemoveMember(int teamId, int userId);
enum TeamAccessibility
{
/**
* The Team or the user is not found
*/
NotFound,
/**
* Accessibility not granted
*/
Unauthorized,
/**
* Accessibility granted
*/
Authorized
}
public Task<IEnumerable<Tactic>> GetSharedTacticsToTeam(int teamId); public Task<IEnumerable<Tactic>> GetSharedTacticsToTeam(int teamId);
public Task<bool> IsUserInTeam(int userId, int teamId); public Task<bool> IsUserInTeam(int userId, int teamId);
/**
* 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<TeamAccessibility> EnsureAccessibility(int userId, int teamId, MemberRole role);
} }

@ -2,27 +2,57 @@
namespace Services; namespace Services;
/// <summary>
/// Represents a service for managing users.
/// </summary>
public interface IUserService public interface IUserService
{ {
/// <summary>
/// Retrieves the count of users whose names contain the specified needle.
/// </summary>
Task<int> UsersCount(string nameNeedle); Task<int> UsersCount(string nameNeedle);
/// <summary>
/// Retrieves the total count of users.
/// </summary>
Task<int> UsersCount(); Task<int> UsersCount();
Task<IEnumerable<User>> ListUsers(string nameNeedle);
Task<IEnumerable<User>> ListUsers();
/// <summary>
/// Lists a range of users, optionally filtering by name.
/// </summary>
Task<IEnumerable<User>> ListUsers(int start, int count, string? nameNeedle = null);
/// <summary>
/// Retrieves the user with the specified ID.
/// </summary>
Task<User?> GetUser(int id); Task<User?> GetUser(int id);
/// <summary>
/// Retrieves the user with the specified email.
/// </summary>
Task<User?> GetUser(string email); Task<User?> GetUser(string email);
/// <summary>
/// Creates a new user.
/// </summary>
Task<User> CreateUser(string username, string email, string password, string profilePicture, bool isAdmin); Task<User> CreateUser(string username, string email, string password, string profilePicture, bool isAdmin);
/// <summary>
/// Removes one or more users.
/// </summary>
Task<bool> RemoveUsers(params int[] identifiers); Task<bool> RemoveUsers(params int[] identifiers);
/// <summary>
/// Updates an existing user.
/// </summary>
Task UpdateUser(User user); Task UpdateUser(User user);
public Task<User?> Authorize(string email, string password);
public Task<IEnumerable<Tactic>> GetSharedTacticsToUser(int userId); public Task<IEnumerable<Tactic>> GetSharedTacticsToUser(int userId);
/// <summary>
/// Authorizes a user with the specified email and password.
/// </summary>
Task<User?> Authorize(string email, string password);
} }

@ -35,11 +35,8 @@ public class StubAppContext(DbContextOptions<AppContext> options) : AppContext(o
"https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png", "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png",
})); }));
builder.Entity<MemberEntity>()
.HasKey("TeamId", "UserId");
builder.Entity<TacticEntity>() builder.Entity<TacticEntity>()
.HasData(new TacticEntity() .HasData(new TacticEntity
{ {
Id = 1, Id = 1,
Name = "New tactic", Name = "New tactic",
@ -52,7 +49,7 @@ public class StubAppContext(DbContextOptions<AppContext> options) : AppContext(o
.HasData(new TacticStepEntity .HasData(new TacticStepEntity
{ {
Id = 1, Id = 1,
JsonContent = "{}", JsonContent = "{\"components\": []}",
TacticId = 1, TacticId = 1,
ParentId = null ParentId = null
}); });
@ -64,5 +61,48 @@ public class StubAppContext(DbContextOptions<AppContext> options) : AppContext(o
TacticId = 1, TacticId = 1,
SharedWithUserId = 2 SharedWithUserId = 2
}); });
builder.Entity<TeamEntity>()
.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<TeamEntity>()
.HasData(new TeamEntity
{
Id = 2,
Name = "Auvergne",
Picture =
"https://sancy.iut.uca.fr/~lafourcade/img/photo19.jpg",
MainColor = "#FFFFFF",
SecondColor = "#000000",
});
builder.Entity<MemberEntity>()
.HasKey("TeamId", "UserId");
builder.Entity<MemberEntity>()
.HasData(
new MemberEntity
{
Role = MemberRole.Coach,
UserId = 1,
TeamId = 1
}, new MemberEntity
{
Role = MemberRole.Player,
UserId = 2,
TeamId = 1
}
);
} }
} }

@ -0,0 +1,112 @@
using API.Controllers.Admin;
using DbServices;
using FluentAssertions;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
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<AppContext.AppContext>()
.UseSqlite(connection)
.Options
);
context.Database.EnsureCreated();
var controller = new TeamsAdminController(
new DbTeamService(context),
new LoggerFactory().CreateLogger<TeamsAdminController>()
);
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());
}
}

@ -4,6 +4,7 @@ using DbServices;
using FluentAssertions; using FluentAssertions;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Model; using Model;
using StubContext; using StubContext;
@ -23,7 +24,7 @@ public class AdminUserControllerTest
); );
context.Database.EnsureCreated(); context.Database.EnsureCreated();
var service = new DbUserService(context); var service = new DbUserService(context);
return new UsersAdminController(service); return new UsersAdminController(service, new LoggerFactory().CreateLogger<UsersAdminController>());
} }
@ -122,5 +123,9 @@ public class AdminUserControllerTest
var userResult = await controller.GetUser(1); var userResult = await controller.GetUser(1);
userResult.Should().BeEquivalentTo(controller.Ok(new User(1, "maxou", "maxou@mail.com", UsersController.DefaultProfilePicture, false))); 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());
} }
} }

@ -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<AppContext.AppContext>()
.UseSqlite(connection)
.Options
);
context.Database.EnsureCreated();
var mock = new Mock<IConfiguration>();
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());
}
}

@ -1,6 +1,5 @@
using API.Controllers; using API.Controllers;
using API.DTO; using API.DTO;
using AppContext.Entities;
using DbServices; using DbServices;
using FluentAssertions; using FluentAssertions;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
@ -39,7 +38,7 @@ public class TacticsControllerTest
var tactic = await context.Tactics.FindAsync(1); var tactic = await context.Tactics.FindAsync(1);
tactic.Name.Should().BeEquivalentTo("Stade de France"); tactic.Name.Should().BeEquivalentTo("Stade de France");
result = await controller.UpdateName(-1, new("Stade de France")); result = await controller.UpdateName(-1, new("Stade de France"));
result.Should().BeEquivalentTo(controller.Unauthorized()); result.Should().BeEquivalentTo(controller.Unauthorized());
} }
@ -49,18 +48,92 @@ public class TacticsControllerTest
{ {
var (controller, context) = GetController(1); var (controller, context) = GetController(1);
var result = await controller.GetTacticInfo(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.Should()
.BeEquivalentTo(controller.Ok(new Tactic(1, "New tactic", 1, CourtType.Plain, new DateTime(2024, 5, 31))
.ToDto()));
result = await controller.GetTacticInfo(100); result = await controller.GetTacticInfo(100);
result.Should().BeEquivalentTo(controller.Unauthorized()); result.Should().BeEquivalentTo(controller.Unauthorized());
} }
[Fact] [Fact]
public async void GetTacticStepsRoot() public async void GetTacticStepsRootTest()
{ {
var (controller, context) = GetController(1); var (controller, context) = GetController(1);
var result = await controller.GetTacticStepsRoot(1); var result = await controller.GetTacticStepsRoot(1);
result.Should().BeEquivalentTo(controller.Ok(new TacticController.GetTacticStepsTreeResponse(new TacticStep(1, null, [], "{}").ToDto()))); result.Should()
.BeEquivalentTo(controller.Ok(
new TacticController.GetTacticStepsTreeResponse(new TacticStep(1, null, [], "{}").ToDto())));
}
[Fact]
public async void CreateNewTest()
{
var (controller, context) = GetController(1);
var result = await controller.CreateNew(new("Test Tactic", "pLaIn"));
result.Should().BeEquivalentTo(new TacticController.CreateNewResponse(2));
var tactic = await context.Tactics.FirstOrDefaultAsync(e => e.Id == 2);
tactic.Should().NotBeNull();
tactic!.Name.Should().BeEquivalentTo("Test Tactic");
tactic.OwnerId.Should().Be(1);
tactic.Type.Should().Be(CourtType.Plain);
}
[Fact]
public async void AddStepTest()
{
var (controller, context) = GetController(1);
var result = await controller.AddStep(1, new(1, "{components: []}"));
result.Should().BeEquivalentTo(controller.Ok(new TacticController.AddStepResponse(2)));
var tactic = await context.TacticSteps.FirstOrDefaultAsync(e => e.Id == 2);
tactic.Should().NotBeNull();
tactic!.Id.Should().Be(2);
tactic.ParentId.Should().Be(1);
tactic.TacticId.Should().Be(1);
// if tactic does not exists
result = await controller.AddStep(100, new(1, "hello"));
result.Should().BeEquivalentTo(controller.NotFound());
// if step does not exists
result = await controller.AddStep(1, new(10, "hello"));
result.Should().BeEquivalentTo(controller.NotFound());
}
[Fact]
public async void RemoveStepTest()
{
var (controller, context) = GetController(1);
var result = await controller.RemoveStep(1, 1);
result.Should().BeEquivalentTo(controller.Ok());
var tactic = await context.TacticSteps.FirstOrDefaultAsync(e => e.Id == 1);
tactic.Should().BeNull();
// if tactic does not exists
result = await controller.RemoveStep(100, 1);
result.Should().BeEquivalentTo(controller.Unauthorized());
// if step does not exists
result = await controller.RemoveStep(1, 10);
result.Should().BeEquivalentTo(controller.NotFound());
}
[Fact]
public async void GetStepContentTest()
{
var (controller, context) = GetController(1);
(await controller.GetStepContent(1, 1)).Should().BeAssignableTo(controller.Ok("").GetType());
(await controller.GetStepContent(10, 1)).Should().BeEquivalentTo(controller.Unauthorized());
(await controller.GetStepContent(1, 10)).Should().BeEquivalentTo(controller.NotFound());
}
[Fact]
public async void SaveStepContentTest()
{
var (controller, context) = GetController(1);
(await controller.SaveStepContent(1, 1, new(new object()))).Should().BeEquivalentTo(controller.Ok());
(await controller.SaveStepContent(10, 1, new (new object()))).Should().BeEquivalentTo(controller.Unauthorized());
(await controller.SaveStepContent(1, 10, new (new object()))).Should().BeEquivalentTo(controller.NotFound());
} }
} }

@ -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<AppContext.AppContext>()
.UseSqlite(connection)
.Options
);
context.Database.EnsureCreated();
var controller = new TeamsController(
new DbTeamService(context), new DbTacticService(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());
}
}

@ -1,5 +1,4 @@
using API.Controllers; using API.Controllers;
using AppContext.Entities;
using DbServices; using DbServices;
using FluentAssertions; using FluentAssertions;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -7,7 +6,6 @@ using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Model; using Model;
using StubContext; using StubContext;
using Xunit.Abstractions;
namespace UnitTests; namespace UnitTests;
@ -29,7 +27,7 @@ public class UsersControllerTest
new DbTacticService(context), new DbTacticService(context),
new ManualContextAccessor(userId) new ManualContextAccessor(userId)
); );
return controller; return controller;
} }
@ -47,7 +45,10 @@ public class UsersControllerTest
{ {
var controller = GetUserController(1); var controller = GetUserController(1);
var result = await controller.GetUserData(); var result = await controller.GetUserData();
result.Should().BeEquivalentTo(new UsersController.GetUserDataResponse([], [])); // 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)]
// ));
} }
[Fact] [Fact]

@ -16,6 +16,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Converters", "Converters\Co
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{82A100BE-5610-4741-8F23-1CD653E8EFCD}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{82A100BE-5610-4741-8F23-1CD653E8EFCD}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFConsole", "EFConsole\EFConsole.csproj", "{DC9ACDB3-83BC-4DF2-84C7-070361648975}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "APIConsole", "APIConsole\APIConsole.csproj", "{B01BD72E-15D3-4DC6-8DAC-2270A01129A9}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -62,5 +66,13 @@ Global
{82A100BE-5610-4741-8F23-1CD653E8EFCD}.Debug|Any CPU.Build.0 = Debug|Any CPU {82A100BE-5610-4741-8F23-1CD653E8EFCD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{82A100BE-5610-4741-8F23-1CD653E8EFCD}.Release|Any CPU.ActiveCfg = Release|Any CPU {82A100BE-5610-4741-8F23-1CD653E8EFCD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{82A100BE-5610-4741-8F23-1CD653E8EFCD}.Release|Any CPU.Build.0 = Release|Any CPU {82A100BE-5610-4741-8F23-1CD653E8EFCD}.Release|Any CPU.Build.0 = Release|Any CPU
{DC9ACDB3-83BC-4DF2-84C7-070361648975}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC9ACDB3-83BC-4DF2-84C7-070361648975}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC9ACDB3-83BC-4DF2-84C7-070361648975}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC9ACDB3-83BC-4DF2-84C7-070361648975}.Release|Any CPU.Build.0 = Release|Any CPU
{B01BD72E-15D3-4DC6-8DAC-2270A01129A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B01BD72E-15D3-4DC6-8DAC-2270A01129A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B01BD72E-15D3-4DC6-8DAC-2270A01129A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B01BD72E-15D3-4DC6-8DAC-2270A01129A9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

@ -4,8 +4,24 @@ name: "CI/CD"
steps: steps:
- image: mcr.microsoft.com/dotnet/sdk:8.0
name: "Run Tests and sonar"
commands:
- apt update && apt install openjdk-17-jre -y
- dotnet tool install --global dotnet-sonarscanner
- dotnet tool install --global dotnet-coverage
- export PATH="$PATH:/root/.dotnet/tools"
- dotnet sonarscanner begin /k:"IQBall-WebAPI" /d:sonar.host.url="https://codefirst.iut.uca.fr/sonar" /d:sonar.login="sqp_b16ad09dcce1b9dde920e313b10c2fe85566624c"
- dotnet build
- dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml"
- dotnet sonarscanner end /d:sonar.login="sqp_b16ad09dcce1b9dde920e313b10c2fe85566624c"
- image: plugins/docker - image: plugins/docker
name: "build and push docker image" name: "build and push docker image"
depends_on:
- "Run Tests and sonar"
settings: settings:
dockerfile: ci/API.dockerfile dockerfile: ci/API.dockerfile
context: . context: .

Loading…
Cancel
Save