Skip to content

Jwt implementation #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Application/Commands/CancelPlayOfferCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

namespace PlayOfferService.Application.Commands;

public record CancelPlayOfferCommand(Guid PlayOfferId) : IRequest<Task>
public record CancelPlayOfferCommand(Guid PlayOfferId, Guid MemberId) : IRequest<Task>
{
}
2 changes: 1 addition & 1 deletion Application/Commands/CreatePlayOfferCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
using PlayOfferService.Domain.Models;

namespace PlayOfferService.Application.Commands;
public record CreatePlayOfferCommand(CreatePlayOfferDto CreatePlayOfferDto) : IRequest<Guid>
public record CreatePlayOfferCommand(CreatePlayOfferDto CreatePlayOfferDto, Guid CreatorId, Guid ClubId) : IRequest<Guid>
{
}
2 changes: 1 addition & 1 deletion Application/Commands/JoinPlayOfferCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
using PlayOfferService.Domain.Models;

namespace PlayOfferService.Application.Commands;
public record JoinPlayOfferCommand(JoinPlayOfferDto JoinPlayOfferDto) : IRequest<Task>
public record JoinPlayOfferCommand(JoinPlayOfferDto JoinPlayOfferDto, Guid MemberId) : IRequest<Task>
{
}
67 changes: 48 additions & 19 deletions Application/Controllers/PlayOfferController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System.Security.Claims;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PlayOfferService.Application.Commands;
using PlayOfferService.Application.Exceptions;
using PlayOfferService.Application.Queries;
using PlayOfferService.Domain.Models;

Expand All @@ -18,22 +21,22 @@ public PlayOfferController(IMediator mediator)
_mediator = mediator;
}

///<summary>
///Retrieve all Play Offers of a club with a matching id
///</summary>
///<param name="clubId">The id of the club of the play offer</param>
///<returns>Play offers with a matching club id</returns>
///<response code="200">Returns a list of Play offers matching the query params</response>
///<response code="204">No Play offer with matching properties was found</response>
/// <summary>
/// Retrieve all Play Offers of the logged in users club
/// </summary>
/// <returns>Play offers with a matching club id</returns>
/// <response code="200">Returns a list of Play offers matching the query params</response>
/// <response code="204">No Play offer with matching properties was found</response>
[HttpGet]
[Authorize]
[Route("club")]
[ProducesResponseType(typeof(IEnumerable<PlayOfferDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ActionResult), StatusCodes.Status204NoContent)]
[Consumes("application/json")]
[Produces("application/json")]
public async Task<ActionResult<IEnumerable<PlayOfferDto>>> GetByClubIdAsync([FromQuery] Guid clubId)
public async Task<ActionResult<IEnumerable<PlayOfferDto>>> GetByClubIdAsync()
{
//TODO: refactor after jwt implementation to get clubId from token
var clubId = Guid.Parse(User.Claims.First(c => c.Type == "tennisClubId").Value);
var result = await _mediator.Send(new GetPlayOffersByClubIdQuery(clubId));

if (result.Count() == 0)
Expand All @@ -43,21 +46,21 @@ public async Task<ActionResult<IEnumerable<PlayOfferDto>>> GetByClubIdAsync([Fro
}

///<summary>
///Retrieve all Play Offers of a participating member
///Retrieve all Play Offers of a logged in user
///</summary>
///<param name="participantId">The id of the member participating in the play offer</param>
///<returns>List of Play offers with where given member is creator or opponent</returns>
///<response code="200">Returns a list of Play offers matching the query params</response>
///<response code="204">No Play offer with matching properties was found</response>
[HttpGet]
[Authorize]
[Route("participant")]
[ProducesResponseType(typeof(IEnumerable<PlayOffer>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ActionResult), StatusCodes.Status204NoContent)]
[Consumes("application/json")]
[Produces("application/json")]
public async Task<ActionResult<IEnumerable<PlayOfferDto>>> GetByParticipantIdAsync([FromQuery] Guid participantId)
public async Task<ActionResult<IEnumerable<PlayOfferDto>>> GetByParticipantIdAsync()
{
//TODO: refactor after jwt implementation to get participantId from token
var participantId = Guid.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value);
var result = await _mediator.Send(new GetPlayOffersByParticipantIdQuery(participantId));

if (result.Count() == 0)
Expand All @@ -74,6 +77,7 @@ public async Task<ActionResult<IEnumerable<PlayOfferDto>>> GetByParticipantIdAsy
///<response code="200">Returns a List of Play offers with creator matching the query params</response>
///<response code="204">No Play offers with matching creator was found</response>
[HttpGet]
[Authorize]
[Route("search")]
[ProducesResponseType(typeof(IEnumerable<PlayOffer>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ActionResult), StatusCodes.Status204NoContent)]
Expand All @@ -100,23 +104,31 @@ public async Task<ActionResult<IEnumerable<PlayOfferDto>>> GetByCreatorNameAsync


///<summary>
///Create a new Play Offer
///Create a new Play Offer for the logged in user
///</summary>
///<param name="createPlayOfferDto">The Play Offer to create</param>
///<returns>The newly created Play offer</returns>
///<response code="200">Returns the id of the created Play Offer</response>
///<response code="400">Invalid Play Offer structure</response>
///<response code="401">Only members can create Play Offers</response>
[HttpPost]
[Authorize]
[ProducesResponseType(typeof(PlayOffer), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ActionResult), StatusCodes.Status400BadRequest)]
[Consumes("application/json")]
[Produces("application/json")]
public async Task<ActionResult<PlayOffer>> Create(CreatePlayOfferDto createPlayOfferDto)
{
if (User.Claims.First(c => c.Type == "groups").Value != "MEMBER")
return Unauthorized("Only members can create Play Offers!");

var creatorId = Guid.Parse(User.FindFirst(ClaimTypes.NameIdentifier)!.Value);
var clubId = Guid.Parse(User.FindFirst("tennisClubId")!.Value);

Guid result;
try
{
result = await _mediator.Send(new CreatePlayOfferCommand(createPlayOfferDto));
result = await _mediator.Send(new CreatePlayOfferCommand(createPlayOfferDto, creatorId, clubId));
}
catch (Exception e)
{
Expand All @@ -127,22 +139,33 @@ public async Task<ActionResult<PlayOffer>> Create(CreatePlayOfferDto createPlayO
}

///<summary>
///Cancels a Play Offer with a matching id
///Cancels a Play Offer with a matching id of the logged in user
///</summary>
///<param name="playOfferId">The id of the Play Offer to cancel</param>
///<returns>Nothing</returns>
///<response code="200">The Play Offer with the matching id was cancelled</response>
///<response code="400">No Play Offer with matching id found</response>
///<response code="401">Only creator can cancel Play Offers</response>
[HttpDelete]
[Authorize]
[ProducesResponseType(typeof(ActionResult), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ActionResult), StatusCodes.Status400BadRequest)]
[Consumes("application/json")]
[Produces("application/json")]
public async Task<ActionResult> Delete(Guid playOfferId)
{
if (User.Claims.First(c => c.Type == "groups").Value != "MEMBER")
return Unauthorized("Only members can cancel Play Offers!");

var memberId = Guid.Parse(User.FindFirst(ClaimTypes.NameIdentifier)!.Value);

try
{
await _mediator.Send(new CancelPlayOfferCommand(playOfferId));
await _mediator.Send(new CancelPlayOfferCommand(playOfferId, memberId));
}
catch (AuthorizationException e)
{
return Unauthorized(e.Message);
}
catch (Exception e)
{
Expand All @@ -153,23 +176,29 @@ public async Task<ActionResult> Delete(Guid playOfferId)
}

///<summary>
///Adds a given opponentId to a Play Offer and creates a reservation
///Logged in user joins a Play Offer with a matching playOfferId
///</summary>
///<param name="joinPlayOfferDto">The opponentId to add to the Play Offer with the matching playOfferId</param>
///<returns>Nothing</returns>
///<response code="200">The opponentId was added to the Play Offer with the matching playOfferId</response>
///<response code="400">No playOffer with a matching playOfferId found</response>
///<response code="401">Only members can join Play Offers</response>
[HttpPost]
[Authorize]
[Route("join")]
[ProducesResponseType(typeof(ActionResult), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ActionResult), StatusCodes.Status400BadRequest)]
[Consumes("application/json")]
[Produces("application/json")]
public async Task<ActionResult> Join(JoinPlayOfferDto joinPlayOfferDto)
{
if (User.Claims.First(c => c.Type == "groups").Value != "MEMBER")
return Unauthorized("Only members can join Play Offers!");

var memberId = Guid.Parse(User.FindFirst(ClaimTypes.NameIdentifier)!.Value);
try
{
await _mediator.Send(new JoinPlayOfferCommand(joinPlayOfferDto));
await _mediator.Send(new JoinPlayOfferCommand(joinPlayOfferDto, memberId));
}
catch (Exception e)
{
Expand Down
3 changes: 3 additions & 0 deletions Application/Exceptions/AuthorizationException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace PlayOfferService.Application.Exceptions;

public class AuthorizationException(string message) : Exception(message);
3 changes: 3 additions & 0 deletions Application/Handlers/CancelPlayOfferHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public async Task<Task> Handle(CancelPlayOfferCommand request, CancellationToken
var existingPlayOffer = (await _playOfferRepository.GetPlayOffersByIds(request.PlayOfferId)).FirstOrDefault();
if (existingPlayOffer == null)
throw new NotFoundException($"PlayOffer {request.PlayOfferId} not found!");
if (existingPlayOffer.CreatorId != request.MemberId)
throw new AuthorizationException($"PlayOffer {request.PlayOfferId} can only be cancelled by creator!");

if (existingPlayOffer.OpponentId != null)
throw new InvalidOperationException($"PlayOffer {request.PlayOfferId} is already accepted and cannot be cancelled!");
if (existingPlayOffer.IsCancelled)
Expand Down
8 changes: 4 additions & 4 deletions Application/Handlers/CreatePlayOfferHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ public async Task<Guid> Handle(CreatePlayOfferCommand request, CancellationToken
{
var playOfferDto = request.CreatePlayOfferDto;

var club = await _clubRepository.GetClubById(playOfferDto.ClubId);
var club = await _clubRepository.GetClubById(request.ClubId);
if(club == null)
throw new NotFoundException($"Club {request.CreatePlayOfferDto.ClubId} not found");
throw new NotFoundException($"Club {request.ClubId} not found");
switch (club.Status)
{
case Status.LOCKED:
Expand All @@ -36,9 +36,9 @@ public async Task<Guid> Handle(CreatePlayOfferCommand request, CancellationToken
throw new InvalidOperationException("Can't create PlayOffer in deleted club!");
}

var creator = await _memberRepository.GetMemberById(playOfferDto.CreatorId);
var creator = await _memberRepository.GetMemberById(request.CreatorId);
if(creator == null)
throw new NotFoundException($"Member {request.CreatePlayOfferDto.CreatorId} not found!");
throw new NotFoundException($"Member {request.CreatorId} not found!");
switch (creator.Status)
{
case Status.LOCKED:
Expand Down
6 changes: 5 additions & 1 deletion Application/Handlers/GetPlayOffersByClubIdHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ public async Task<IEnumerable<PlayOfferDto>> Handle(GetPlayOffersByClubIdQuery r
var clubDto = new ClubDto((await _clubRepository.GetClubById(request.ClubId))!);
var memberDtos = (await _memberRepository.GetAllMembers()).Select(member => new MemberDto(member)).ToList();
var courtDtos = (await _courtRepository.GetAllCourts()).Select(court => new CourtDto(court)).ToList();
var reservationDtos = (await _reservationRepository.GetAllReservations()).Select(reservation => new ReservationDto(reservation, courtDtos)).ToList();
var reservationDtos = (await _reservationRepository.GetAllReservations())
.Select(reservation => new ReservationDto(
reservation,
courtDtos.First(courtDto => courtDto.Id == reservation.CourtId)))
.ToList();

var playOfferDtos = new List<PlayOfferDto>();
foreach (var playOffer in playOffers)
Expand Down
6 changes: 5 additions & 1 deletion Application/Handlers/GetPlayOffersByCreatorNameHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ public async Task<IEnumerable<PlayOfferDto>> Handle(GetPlayOffersByCreatorNameQu
var clubDto = (await _clubRepository.GetAllClubs()).Select(club => new ClubDto(club)).ToList();
var memberDtos = (await _memberRepository.GetAllMembers()).Select(member => new MemberDto(member)).ToList();
var courtDtos = (await _courtRepository.GetAllCourts()).Select(court => new CourtDto(court)).ToList();
var reservationDtos = (await _reservationRepository.GetAllReservations()).Select(reservation => new ReservationDto(reservation, courtDtos)).ToList();
var reservationDtos = (await _reservationRepository.GetAllReservations())
.Select(reservation => new ReservationDto(
reservation,
courtDtos.First(courtDto => courtDto.Id == reservation.CourtId)))
.ToList();

var playOfferDtos = new List<PlayOfferDto>();
foreach (var playOffer in playOffers)
Expand Down
6 changes: 5 additions & 1 deletion Application/Handlers/GetPlayOffersByParticipantIdHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ public async Task<IEnumerable<PlayOfferDto>> Handle(GetPlayOffersByParticipantId
var clubDto = (await _clubRepository.GetAllClubs()).Select(club => new ClubDto(club)).ToList();
var memberDtos = (await _memberRepository.GetAllMembers()).Select(member => new MemberDto(member)).ToList();
var courtDtos = (await _courtRepository.GetAllCourts()).Select(court => new CourtDto(court)).ToList();
var reservationDtos = (await _reservationRepository.GetAllReservations()).Select(reservation => new ReservationDto(reservation, courtDtos)).ToList();
var reservationDtos = (await _reservationRepository.GetAllReservations())
.Select(reservation => new ReservationDto(
reservation,
courtDtos.First(courtDto => courtDto.Id == reservation.CourtId)))
.ToList();

var playOfferDtos = new List<PlayOfferDto>();
foreach (var playOffer in playOffers)
Expand Down
4 changes: 2 additions & 2 deletions Application/Handlers/JoinPlayOfferHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ public async Task<Task> Handle(JoinPlayOfferCommand request, CancellationToken c
if (existingPlayOffer == null)
throw new NotFoundException($"PlayOffer {request.JoinPlayOfferDto.PlayOfferId} not found!");

var existingOpponent = await _memberRepository.GetMemberById(request.JoinPlayOfferDto.OpponentId);
var existingOpponent = await _memberRepository.GetMemberById(request.MemberId);
if (existingOpponent == null)
throw new NotFoundException($"Member {request.JoinPlayOfferDto.OpponentId} not found!");
throw new NotFoundException($"Member {request.MemberId} not found!");

if (existingOpponent.Id == existingPlayOffer.CreatorId)
throw new InvalidOperationException("Can't join your own PlayOffer!");
Expand Down
6 changes: 3 additions & 3 deletions Domain/DbReadContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.ApplyConfiguration(new BaseEventConfiguration());

// TODO: Remove before coop testing
var testClub = new Club { Id = Guid.Parse("06b812a7-5131-4510-82ff-bffac33e0f3e"), Name = "Test Club", Status = Status.ACTIVE };
var testMemberIds = new List<Guid> { Guid.Parse("40c0981d-e2f8-4af3-ae6c-17f79f3ba8c2"), Guid.Parse("ccc1c8fc-89b5-4026-b190-9d9e7e7bc18d") };
var testClub = new Club { Id = Guid.Parse("1fc64a89-9e63-4e9f-96f7-e2120f0ca6c3"), Name = "Test Club", Status = Status.ACTIVE };
var testMemberIds = new List<Guid> { Guid.Parse("0033506d-2d59-40d3-b996-74a251091027"), Guid.Parse("ccc1c8fc-89b5-4026-b190-9d9e7e7bc18d") };

var testMembers = new List<Object>{
new {Id = testMemberIds[0], ClubId = testClub.Id, Status = Status.ACTIVE, FirstName = "Hans", LastName="Müller", Email="hans@müller.de"},
Expand All @@ -37,7 +37,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
{
Id = Guid.NewGuid(),
ClubId = testClub.Id,
CreatorId = testMemberIds[0],
CreatorId = testMemberIds[1],
ProposedStartTime = DateTime.UtcNow,
ProposedEndTime = DateTime.UtcNow.AddHours(1),
IsCancelled = false
Expand Down
2 changes: 1 addition & 1 deletion Domain/Events/Reservation/ReservationCreatedEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class ReservationCreatedEvent : DomainEvent
[JsonPropertyName("participantIds")]
public List<Guid>? ParticipantIds { get; set; }
[JsonPropertyName("courtIds")]
public List<Guid> CourtIds { get; set; }
public Guid CourtId { get; set; }

public ReservationCreatedEvent(){}
}
Expand Down
16 changes: 16 additions & 0 deletions Domain/Events/Reservation/ReservationLimitExceededEvent.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
using System.Text.Json.Serialization;

namespace PlayOfferService.Domain.Events.Reservation;

public class ReservationLimitExceededEvent : DomainEvent
{
[JsonPropertyName("start")]
public DateTime Start { get; set; }
[JsonPropertyName("end")]
public DateTime End { get; set; }
[JsonPropertyName("reservantId")]
public Guid? ReservantId { get; set; }
[JsonPropertyName("tournamentId")]
public Guid? TournamentId { get; set; }
[JsonPropertyName("participantIds")]
public List<Guid>? ParticipantIds { get; set; }
[JsonPropertyName("courtIds")]
public Guid CourtId { get; set; }

public ReservationLimitExceededEvent(){}
}
15 changes: 15 additions & 0 deletions Domain/Events/Reservation/ReservationRejectedEvent.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
using System.Text.Json.Serialization;
using MediatR;

namespace PlayOfferService.Domain.Events.Reservation;

public class ReservationRejectedEvent : DomainEvent
{
[JsonPropertyName("start")]
public DateTime Start { get; set; }
[JsonPropertyName("end")]
public DateTime End { get; set; }
[JsonPropertyName("reservantId")]
public Guid? ReservantId { get; set; }
[JsonPropertyName("tournamentId")]
public Guid? TournamentId { get; set; }
[JsonPropertyName("participantIds")]
public List<Guid>? ParticipantIds { get; set; }
[JsonPropertyName("courtIds")]
public Guid CourtId { get; set; }

public ReservationRejectedEvent(){}
}
2 changes: 0 additions & 2 deletions Domain/Models/DTOs/CreatePlayOfferDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ namespace PlayOfferService.Domain.Models;

public class CreatePlayOfferDto
{
public Guid ClubId { get; set; }
public Guid CreatorId { get; set; }
public DateTime ProposedStartTime { get; set; }
public DateTime ProposedEndTime { get; set; }
}
6 changes: 3 additions & 3 deletions Domain/Models/DTOs/ReservationDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ namespace PlayOfferService.Domain.Models;
public class ReservationDto
{
public Guid Id { get; set; }
public List<CourtDto> Courts { get; set; }
public CourtDto Court { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public bool IsCancelled { get; set; }

public ReservationDto(Reservation reservation, List<CourtDto> courts)
public ReservationDto(Reservation reservation, CourtDto court)
{
Id = reservation.Id;
Courts = courts.Where(c => reservation.CourtIds.Contains(c.Id)).ToList();
Court = court;
StartTime = reservation.StartTime;
EndTime = reservation.EndTime;
IsCancelled = reservation.IsCancelled;
Expand Down
Loading
Loading