using System.ComponentModel.DataAnnotations; using API.Context; using API.Validation; using AppContext.Entities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Model; using Services; namespace API.Controllers; [ApiController] [Authorize] public class TeamsController(ITeamService service, ITacticService tactics,IContextAccessor accessor) : ControllerBase { public record CreateTeamRequest( [Name] string Name, [Url] string Picture, [RegularExpression("^#[0-9A-F]{6}$")] string FirstColor, [RegularExpression("^#[0-9A-F]{6}$")] string SecondColor ); [HttpPost("/teams")] public async Task CreateTeam([FromBody] CreateTeamRequest req) { var userId = accessor.CurrentUserId(HttpContext); var team = await service.AddTeam(req.Name, req.Picture, req.FirstColor, req.SecondColor); await service.AddMember(team.Id, userId, MemberRole.Coach); return Ok(team); } [HttpGet("/teams/{teamId:int}/members")] public async Task GetMembersOf(int 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( int UserId, [AllowedValues("PLAYER", "COACH")] string Role ); [HttpPost("/teams/{teamId:int}/members")] public async Task AddMember(int teamId, [FromBody] AddMemberRequest req) { if (!Enum.TryParse(req.Role, true, out var role)) { 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); if (result == null) return Forbid(); return Ok(result); } case ITeamService.TeamAccessibility.NotFound: case ITeamService.TeamAccessibility.Unauthorized: return NotFound(); default: //unreachable return Problem(); } } public record UpdateMemberRequest( [AllowedValues("PLAYER", "COACH")] string Role ); [HttpPut("/team/{teamId:int}/members/{userId:int}")] public async Task UpdateMember(int teamId, int userId, [FromBody] UpdateMemberRequest req) { if (!Enum.TryParse(req.Role, true, out var role)) { 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 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 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(); } } public record ShareTacticToTeamRequest( int TacticId, int TeamId ); [HttpPost("/team/share-tactic")] public async Task ShareTactic([FromBody] ShareTacticToTeamRequest sharedTactic) { var userId = accessor.CurrentUserId(HttpContext); var success = await tactics.ShareTactic(sharedTactic.TacticId, null, sharedTactic.TeamId); return success ? Ok() : BadRequest(); } [HttpDelete("/tactics/shared/{tacticId:int}/team/{teamId:int}")] public async Task UnshareTactic(int tacticId, int teamId) { var currentUserId = accessor.CurrentUserId(HttpContext); var tactic = await tactics.GetTactic(tacticId); if (tactic == null) { return NotFound(); } if (currentUserId != tactic.OwnerId) { return Unauthorized(); } var success = await tactics.UnshareTactic(tacticId, null, teamId); return success ? Ok() : NotFound(); } [HttpGet("/tactics/shared/team/{teamId:int}")] public async Task GetSharedTacticsToTeam(int teamId) { var currentUserId = accessor.CurrentUserId(HttpContext); if (!await service.IsUserInTeam(currentUserId, teamId)) { return Unauthorized(); } var sharedTactics = await service.GetSharedTacticsToTeam(teamId); return sharedTactics != null ? Ok(sharedTactics) : NotFound(); } }