Skip to content

Commit

Permalink
Version 1.1.0
Browse files Browse the repository at this point in the history
Added user management and require admin rights
  • Loading branch information
pbijdens committed Oct 15, 2024
1 parent e3ff205 commit d4e7dc6
Show file tree
Hide file tree
Showing 17 changed files with 498 additions and 18 deletions.
7 changes: 3 additions & 4 deletions CentaurScores/Controllers/AuthenticationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@ public class AuthenticationController(ITokenService tokenService) : ControllerBa
/// <summary>
/// Send a username and a password to obtain a Bearer token that can be used to authorize for specific operations.
/// </summary>
/// <param name="username">Username, as provided as part of your API key issuance</param>
/// <param name="password">The user's password</param>
/// <param name="model">Model with the requested login details</param>
/// <returns>Either returns a valid JWT token or reports a failed status.</returns>
[HttpPost("login")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<string>> Login([FromForm] string username, [FromForm] string password)
public async Task<ActionResult<string>> Login([FromBody] LoginRequestModel model)
{
string result = await tokenService.GenerateJwtToken(username, password);
string result = await tokenService.GenerateJwtToken(model.Username, model.Password);
return result;
}

Expand Down
5 changes: 4 additions & 1 deletion CentaurScores/Controllers/CompetitionController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using CentaurScores.Model;
using CentaurScores.Attributes;
using CentaurScores.Model;
using CentaurScores.Services;
using Microsoft.AspNetCore.Mvc;

Expand Down Expand Up @@ -47,6 +48,7 @@ public async Task<ActionResult<List<CompetitionModel>>> GetCompetitions()
[HttpPut("{competitionId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<CompetitionModel?>> UpdateCompetition([FromRoute] int competitionId, [FromBody] CompetitionModel model)
{
return await competitionRepository.UpdateCompetition(competitionId, model);
Expand All @@ -62,6 +64,7 @@ public async Task<ActionResult<List<CompetitionModel>>> GetCompetitions()
[HttpDelete("{competitionId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<int>> DeleteCompetition([FromRoute] int competitionId)
{
return await competitionRepository.DeleteCompetition(competitionId);
Expand Down
6 changes: 5 additions & 1 deletion CentaurScores/Controllers/MatchParticipantsController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using CentaurScores.Model;
using CentaurScores.Attributes;
using CentaurScores.Model;
using CentaurScores.Services;
using Microsoft.AspNetCore.Mvc;

Expand Down Expand Up @@ -96,6 +97,7 @@ public async Task<ActionResult<ParticipantModel>> GetParticipantForMatch([FromRo
[HttpPut("{participantId}/scoresheet")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<ParticipantModel>> UpdateParticipantForMatch([FromRoute] int id, [FromRoute] int participantId, [FromBody] ParticipantModel participant)
{
return await matchRepository.UpdateParticipantForMatch(id, participantId, participant);
Expand All @@ -110,6 +112,7 @@ public async Task<ActionResult<ParticipantModel>> UpdateParticipantForMatch([Fro
[HttpDelete("{participantId}/scoresheet")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<int>> DeleteParticipantForMatch([FromRoute] int id, [FromRoute] int participantId)
{
return await matchRepository.DeleteParticipantForMatch(id, participantId);
Expand All @@ -124,6 +127,7 @@ public async Task<ActionResult<int>> DeleteParticipantForMatch([FromRoute] int i
[HttpPost("scoresheet")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<ParticipantModel>> CreateParticipantForMatch([FromRoute] int id, [FromBody] ParticipantModel participant)
{
return await matchRepository.CreateParticipantForMatch(id, participant);
Expand Down
7 changes: 6 additions & 1 deletion CentaurScores/Controllers/MatchesController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using CentaurScores.Migrations;
using CentaurScores.Attributes;
using CentaurScores.Migrations;
using CentaurScores.Model;
using CentaurScores.Services;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -50,6 +51,7 @@ public async Task<ActionResult<MatchModel>> GetMatch([FromRoute] int id)
[HttpPut("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<MatchModel>> UpdateMatch([FromRoute] int id, [FromBody] MatchModel match)
{
return await matchRepository.UpdateMatch(id, match);
Expand All @@ -63,6 +65,7 @@ public async Task<ActionResult<MatchModel>> UpdateMatch([FromRoute] int id, [Fro
[HttpDelete("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<bool>> DeleteMatch([FromRoute] int id)
{
return await matchRepository.DeleteMatch(id);
Expand All @@ -76,6 +79,7 @@ public async Task<ActionResult<bool>> DeleteMatch([FromRoute] int id)
[HttpPost()]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<MatchModel>> CreateMatch([FromBody] MatchModel match)
{
return await matchRepository.CreateMatch(match);
Expand All @@ -102,6 +106,7 @@ public async Task<ActionResult<MatchModel>> CreateMatch([FromBody] MatchModel ma
[HttpPut("{id}/active/{isActive}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<MatchModel>> ActivateMatch([FromRoute] int id, [FromRoute] bool isActive)
{
return await matchRepository.ActivateMatch(id, isActive);
Expand Down
8 changes: 7 additions & 1 deletion CentaurScores/Controllers/ParticipantListsController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using CentaurScores.Model;
using CentaurScores.Attributes;
using CentaurScores.Model;
using CentaurScores.Services;
using Microsoft.AspNetCore.Mvc;

Expand Down Expand Up @@ -46,6 +47,7 @@ public async Task<ActionResult<List<ParticipantListModel>>> GetParticipantLists(
[HttpPut("{listId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<ParticipantListModel?>> UpdateParticipantList([FromRoute] int listId, [FromBody] ParticipantListModel model)
{
return await participantListsRepository.UpdateParticipantList(listId, model);
Expand All @@ -59,6 +61,7 @@ public async Task<ActionResult<List<ParticipantListModel>>> GetParticipantLists(
[HttpDelete("{listId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<int>> DeleteParticipantList([FromRoute] int listId)
{
return await participantListsRepository.DeleteParticipantList(listId);
Expand Down Expand Up @@ -114,6 +117,7 @@ public async Task<ActionResult<List<ParticipantListMemberModel>>> GetParticipant
[HttpPut("{listId}/members/{memberId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<ParticipantListMemberModel?>> UpdateParticipantListMember([FromRoute] int listId, [FromRoute] int memberId, [FromBody] ParticipantListMemberModel model)
{
return await participantListsRepository.UpdateParticipantListMember(listId, memberId, model);
Expand All @@ -128,6 +132,7 @@ public async Task<ActionResult<List<ParticipantListMemberModel>>> GetParticipant
[HttpDelete("{listId}/members/{memberId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<int>> DeleteParticipantListMember([FromRoute] int listId, [FromRoute] int memberId)
{
return await participantListsRepository.DeactivateParticipantListMember(listId, memberId);
Expand All @@ -142,6 +147,7 @@ public async Task<ActionResult<int>> DeleteParticipantListMember([FromRoute] int
[HttpPost("{listId}/members")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<ParticipantListMemberModel?>> CreateParticipantListMember([FromRoute] int listId, [FromBody] ParticipantListMemberModel model)
{
return await participantListsRepository.CreateParticipantListMember(listId, model);
Expand Down
8 changes: 7 additions & 1 deletion CentaurScores/Controllers/PersonalBestContoller.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using CentaurScores.Model;
using CentaurScores.Attributes;
using CentaurScores.Model;
using CentaurScores.Services;
using Microsoft.AspNetCore.Mvc;

Expand Down Expand Up @@ -49,6 +50,7 @@ public async Task<ActionResult<PersonalBestListModel>> GetPersonalBestList([From
[HttpPut("{personalBestListId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<PersonalBestListModel?>> UpdatePersonalBestList([FromRoute] int memberListId, [FromRoute] int personalBestListId, [FromBody] PersonalBestListModel model)
{
return await personalBestService.UpdatePersonalBestList(memberListId, model);
Expand All @@ -63,6 +65,7 @@ public async Task<ActionResult<PersonalBestListModel>> GetPersonalBestList([From
[HttpDelete("{personalBestListId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<int>> DeletePersonalBestList([FromRoute] int memberListId, [FromRoute] int personalBestListId)
{
return await personalBestService.DeletePersonalBestList(memberListId, personalBestListId);
Expand All @@ -77,6 +80,7 @@ public async Task<ActionResult<int>> DeletePersonalBestList([FromRoute] int memb
[HttpPost()]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<PersonalBestListModel?>> CreatePersonalBestList([FromRoute] int memberListId, [FromBody] PersonalBestListModel model)
{
return await personalBestService.CreatePersonalBestList(memberListId, model);
Expand Down Expand Up @@ -122,6 +126,7 @@ public async Task<ActionResult<PersonalBestListEntryModel>> GetPersonalBestListE
[HttpPut("{personalBestListId}/members/{memberId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<PersonalBestListEntryModel?>> UpdatePersonalBestListEntry([FromRoute] int memberListId, [FromRoute] int personalBestListId, [FromRoute] int memberId, [FromBody] PersonalBestListEntryModel model)
{
return await personalBestService.UpdatePersonalBestListEntry(memberListId, personalBestListId, model);
Expand Down Expand Up @@ -150,6 +155,7 @@ public async Task<ActionResult<PersonalBestListEntryModel>> GetPersonalBestListE
[HttpGet("suggestions")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<List<NewPersonalBestModel>>> ScanForRecords([FromRoute] int memberListId)
{
return await personalBestService.CalculateUpdatedRecords(memberListId);
Expand Down
105 changes: 105 additions & 0 deletions CentaurScores/Controllers/UserController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using CentaurScores.Attributes;
using CentaurScores.Model;
using CentaurScores.Services;
using Microsoft.AspNetCore.Mvc;

namespace CentaurScores.Controllers
{
/// <summary>
/// Endpoints for user management.
/// </summary>
/// <remarks>Constructor</remarks>
[ApiController]
[Route("auth")]
public class UserController(IAuthorizationService authorizationService) : ControllerBase
{
/// <summary>
/// Returns the list of all users.
/// </summary>
/// <returns></returns>
[HttpGet("user")]
[Authorize]
public async Task<ActionResult<List<UserModel>>> GetUsers()
{
return await authorizationService.GetUsers();
}

/// <summary>
/// Returns the list of all users.
/// </summary>
/// <returns></returns>
[HttpGet("acl")]
[Authorize]
public async Task<ActionResult<List<UserACLModel>>> GetACLs()
{
return await authorizationService.GetAcls();
}

/// <summary>
/// Creates a new user.
/// </summary>
/// <returns></returns>
[HttpPost("user")]
[Authorize]
public async Task<ActionResult<UserModel>> CreateUser(UserModel model)
{
return await authorizationService.CreateUser(HttpContext.User, model);
}

/// <summary>
/// Creates a new ACL.
/// </summary>
/// <returns></returns>
[HttpPost("acl")]
[Authorize]
public async Task<ActionResult<UserACLModel>> CreateACL(UserACLModel model)
{
return await authorizationService.CreateACL(HttpContext.User, model);
}

/// <summary>
/// Updates a user.
/// </summary>
/// <returns></returns>
[HttpPut("user")]
[Authorize]
public async Task<ActionResult<UserModel>> UpdateUser(UserModel model)
{
return await authorizationService.UpdateUser(HttpContext.User, model);
}

/// <summary>
/// Updates an ACL.
/// </summary>
/// <returns></returns>
[HttpPut("acl")]
[Authorize]
public async Task<ActionResult<UserACLModel>> UpdateACL(UserACLModel model)
{
return await authorizationService.UpdateACL(HttpContext.User, model);
}

/// <summary>
/// Updates a user.
/// </summary>
/// <returns></returns>
[HttpDelete("user/{userId}")]
[Authorize]
public async Task<ActionResult<int>> DeleteUser([FromRoute] int userId)
{
return await authorizationService.DeleteUser(HttpContext.User, userId);
}

/// <summary>
/// Updates an ACL.
/// </summary>
/// <returns></returns>
[HttpDelete("acl/{aclId}")]
[Authorize]
public async Task<ActionResult<int>> DeleteACL([FromRoute] int aclId)
{
return await authorizationService.DeleteACL(HttpContext.User, aclId);
}

}
}
17 changes: 17 additions & 0 deletions CentaurScores/Model/LoginRequestModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace CentaurScores.Model
{
/// <summary>
/// Login request data.
/// </summary>
public class LoginRequestModel
{
/// <summary>
/// USername, case sensitive.
/// </summary>
public string Username { get; set; } = string.Empty;
/// <summary>
/// Password, case sensitive.
/// </summary>
public string Password { get; set; } = string.Empty;
}
}
17 changes: 17 additions & 0 deletions CentaurScores/Model/UserACLModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace CentaurScores.Model
{
/// <summary>
/// ACL
/// </summary>
public class UserACLModel
{
/// <summary>
/// Persistence ID
/// </summary>
public int? Id { get; set; }
/// <summary>
/// Username
/// </summary>
public string Name { get; set; } = string.Empty;
}
}
29 changes: 29 additions & 0 deletions CentaurScores/Model/UserModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace CentaurScores.Model
{
/// <summary>
/// User
/// </summary>
public class UserModel
{
/// <summary>
/// Persistence ID
/// </summary>
public int? Id { get; set; }
/// <summary>
/// Username
/// </summary>
public string Username { get; set; } = string.Empty;
/// <summary>
/// Password, only set when changing the password
/// </summary>
public string Password { get; set; } = string.Empty;
/// <summary>
/// Required when changing the password.
/// </summary>
public string CurrentPassword { get; set; } = string.Empty;
/// <summary>
/// List of ACLs for the user
/// </summary>
public List<UserACLModel> Acls { get; set; } = [];
}
}
Loading

0 comments on commit d4e7dc6

Please sign in to comment.