-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add domain logic for event management * add event management endpoint tests * fix registering query consumers * refactoring
- Loading branch information
1 parent
5c59487
commit fa1ad47
Showing
40 changed files
with
2,763 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System.Collections; | ||
|
||
namespace TeamUp.Common.Contracts; | ||
|
||
public sealed class Collection<T> : IEnumerable<T> | ||
{ | ||
public IReadOnlyCollection<T> Values { get; } | ||
|
||
public Collection(IReadOnlyCollection<T> values) | ||
{ | ||
Values = values; | ||
} | ||
|
||
public IEnumerator<T> GetEnumerator() => Values.GetEnumerator(); | ||
|
||
IEnumerator IEnumerable.GetEnumerator() => Values.GetEnumerator(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
src/Common/TeamUp.Common.Infrastructure/Processing/Queries/QueryConsumerDefinition.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using MassTransit; | ||
|
||
using TeamUp.Common.Contracts; | ||
using TeamUp.Common.Infrastructure.Extensions; | ||
|
||
namespace TeamUp.Common.Infrastructure.Processing.Queries; | ||
|
||
internal sealed class QueryConsumerDefinition<TQuery, TResponse> : ConsumerDefinition<QueryConsumerFacade<TQuery, TResponse>> where TQuery : class, IQuery<TResponse> | ||
{ | ||
public QueryConsumerDefinition() | ||
{ | ||
EndpointName = typeof(TQuery).ToKebabCase()!; | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
...ules/TeamManagement/TeamUp.TeamManagement.Application/Events/CreateEventCommandHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using RailwayResult; | ||
|
||
using TeamUp.Common.Application; | ||
using TeamUp.TeamManagement.Contracts; | ||
using TeamUp.TeamManagement.Contracts.Events; | ||
using TeamUp.TeamManagement.Contracts.Events.CreateEvent; | ||
using TeamUp.TeamManagement.Domain.Aggregates.Events; | ||
|
||
namespace TeamUp.TeamManagement.Application.Events; | ||
|
||
internal sealed class CreateEventCommandHandler : ICommandHandler<CreateEventCommand, EventId> | ||
{ | ||
private readonly IEventDomainService _eventDomainService; | ||
private readonly IUnitOfWork<TeamManagementModuleId> _unitOfWork; | ||
|
||
public CreateEventCommandHandler(IEventDomainService eventDomainService, IUnitOfWork<TeamManagementModuleId> unitOfWork) | ||
{ | ||
_eventDomainService = eventDomainService; | ||
_unitOfWork = unitOfWork; | ||
} | ||
|
||
public async Task<Result<EventId>> Handle(CreateEventCommand command, CancellationToken ct) | ||
{ | ||
return await _eventDomainService | ||
.CreateEventAsync( | ||
initiatorId: command.InitiatorId, | ||
teamId: command.TeamId, | ||
eventTypeId: command.EventTypeId, | ||
fromUtc: command.FromUtc, | ||
toUtc: command.ToUtc, | ||
description: command.Description, | ||
meetTime: command.MeetTime, | ||
replyClosingTimeBeforeMeetTime: command.ReplyClosingTimeBeforeMeetTime, | ||
ct: ct) | ||
.TapAsync(_ => _unitOfWork.SaveChangesAsync(ct)); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
src/Modules/TeamManagement/TeamUp.TeamManagement.Application/Events/GetEventQueryHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
using RailwayResult; | ||
using RailwayResult.FunctionalExtensions; | ||
|
||
using TeamUp.Common.Application; | ||
using TeamUp.TeamManagement.Contracts.Events; | ||
using TeamUp.TeamManagement.Contracts.Events.GetEvent; | ||
using TeamUp.TeamManagement.Domain.Aggregates.Events; | ||
using TeamUp.TeamManagement.Domain.Aggregates.Teams; | ||
|
||
using EventResponse = TeamUp.TeamManagement.Contracts.Events.EventResponse; | ||
|
||
namespace TeamUp.TeamManagement.Application.Events; | ||
|
||
internal sealed class GetEventQueryHandler : IQueryHandler<GetEventQuery, EventResponse> | ||
{ | ||
private readonly ITeamManagementQueryContext _appQueryContext; | ||
|
||
public GetEventQueryHandler(ITeamManagementQueryContext appQueryContext) | ||
{ | ||
_appQueryContext = appQueryContext; | ||
} | ||
|
||
public async Task<Result<EventResponse>> Handle(GetEventQuery query, CancellationToken ct) | ||
{ | ||
var team = await _appQueryContext.Teams | ||
.AsSplitQuery() | ||
.Include(team => team.Members) | ||
.Select(team => new | ||
{ | ||
team.Id, | ||
Event = _appQueryContext.Events | ||
.AsSplitQuery() | ||
.Where(e => e.Id == query.EventId && e.TeamId == team.Id) | ||
.Select(e => new EventResponse | ||
{ | ||
Description = e.Description, | ||
EventTypeId = e.EventTypeId, | ||
EventType = team.EventTypes.First(et => et.Id == e.EventTypeId).Name, | ||
FromUtc = e.FromUtc, | ||
ToUtc = e.ToUtc, | ||
MeetTime = e.MeetTime, | ||
ReplyClosingTimeBeforeMeetTime = e.ReplyClosingTimeBeforeMeetTime, | ||
Status = e.Status, | ||
EventResponses = e.EventResponses.Select(er => new EventResponseResponse | ||
{ | ||
Message = er.Message, | ||
TeamMemberId = er.TeamMemberId, | ||
TeamMemberNickname = team.Members.First(member => member.Id == er.TeamMemberId).Nickname, | ||
TimeStampUtc = er.TimeStampUtc, | ||
Type = er.ReplyType | ||
}).ToList() | ||
}) | ||
.FirstOrDefault(), | ||
Initiator = team.Members | ||
.Select(member => member.UserId) | ||
.FirstOrDefault(id => id == query.InitiatorId) | ||
}) | ||
.FirstOrDefaultAsync(team => team.Id == query.TeamId, ct); | ||
|
||
return team | ||
.EnsureNotNull(TeamErrors.TeamNotFound) | ||
.EnsureNotNull(team => team.Initiator, TeamErrors.NotMemberOfTeam) | ||
.EnsureNotNull(team => team.Event, EventErrors.EventNotFound) | ||
.Then(team => team.Event!); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
...Modules/TeamManagement/TeamUp.TeamManagement.Application/Events/GetEvetnsQueryHandlers.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
using RailwayResult; | ||
using RailwayResult.FunctionalExtensions; | ||
|
||
using TeamUp.Common.Application; | ||
using TeamUp.Common.Contracts; | ||
using TeamUp.TeamManagement.Contracts.Events; | ||
using TeamUp.TeamManagement.Contracts.Events.GetEvents; | ||
using TeamUp.TeamManagement.Domain.Aggregates.Teams; | ||
|
||
namespace TeamUp.TeamManagement.Application.Events; | ||
|
||
internal sealed class GetEventsQueryHandlers : IQueryHandler<GetEventsQuery, Collection<EventSlimResponse>> | ||
{ | ||
private readonly ITeamManagementQueryContext _appQueryContext; | ||
private readonly IDateTimeProvider _dateTimeProvider; | ||
|
||
public GetEventsQueryHandlers(ITeamManagementQueryContext appQueryContext, IDateTimeProvider dateTimeProvider) | ||
{ | ||
_appQueryContext = appQueryContext; | ||
_dateTimeProvider = dateTimeProvider; | ||
} | ||
|
||
public async Task<Result<Collection<EventSlimResponse>>> Handle(GetEventsQuery query, CancellationToken ct) | ||
{ | ||
var from = query.FromUtc ?? _dateTimeProvider.UtcNow; | ||
var team = await _appQueryContext.Teams | ||
.Select(team => new | ||
{ | ||
team.Id, | ||
Events = _appQueryContext.Events | ||
.AsSplitQuery() | ||
.Where(e => e.TeamId == team.Id && e.ToUtc > from) | ||
.Include(e => e.EventResponses) | ||
.Select(e => new EventSlimResponse | ||
{ | ||
Id = e.Id, | ||
Description = e.Description, | ||
FromUtc = e.FromUtc, | ||
ToUtc = e.ToUtc, | ||
Status = e.Status, | ||
MeetTime = e.MeetTime, | ||
ReplyClosingTimeBeforeMeetTime = e.ReplyClosingTimeBeforeMeetTime, | ||
ReplyCount = e.EventResponses | ||
.GroupBy(er => er.ReplyType) | ||
.Select(x => new ReplyCountResponse | ||
{ | ||
Type = x.Key, | ||
Count = x.Count() | ||
}) | ||
.ToList(), | ||
EventType = team.EventTypes.First(et => et.Id == e.EventTypeId).Name | ||
}) | ||
.OrderBy(e => e.FromUtc) | ||
.ToList(), | ||
Initiator = team.Members | ||
.Select(member => member.UserId) | ||
.FirstOrDefault(id => id == query.InitiatorId) | ||
}) | ||
.FirstOrDefaultAsync(team => team.Id == query.TeamId, ct); | ||
|
||
return team | ||
.EnsureNotNull(TeamErrors.TeamNotFound) | ||
.EnsureNotNull(team => team.Initiator, TeamErrors.NotMemberOfTeam) | ||
.Then(team => new Collection<EventSlimResponse>(team.Events)); | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
...ules/TeamManagement/TeamUp.TeamManagement.Application/Events/RemoveEventCommandHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using RailwayResult; | ||
|
||
using TeamUp.Common.Application; | ||
using TeamUp.TeamManagement.Contracts; | ||
using TeamUp.TeamManagement.Contracts.Events.RemoveEvent; | ||
using TeamUp.TeamManagement.Domain.Aggregates.Events; | ||
|
||
namespace TeamUp.TeamManagement.Application.Events; | ||
|
||
internal sealed class RemoveEventCommandHandler : ICommandHandler<RemoveEventCommand> | ||
{ | ||
private readonly IEventDomainService _eventDomainService; | ||
private readonly IUnitOfWork<TeamManagementModuleId> _unitOfWork; | ||
|
||
public RemoveEventCommandHandler(IEventDomainService eventDomainService, IUnitOfWork<TeamManagementModuleId> unitOfWork) | ||
{ | ||
_eventDomainService = eventDomainService; | ||
_unitOfWork = unitOfWork; | ||
} | ||
|
||
public async Task<Result> Handle(RemoveEventCommand command, CancellationToken ct) | ||
{ | ||
return await _eventDomainService | ||
.DeleteEventAsync(command.InitiatorId, command.TeamId, command.EventId, ct) | ||
.TapAsync(() => _unitOfWork.SaveChangesAsync(ct)); | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
...TeamManagement/TeamUp.TeamManagement.Application/Events/UpsertEventReplyCommandHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using RailwayResult; | ||
using RailwayResult.Errors; | ||
using RailwayResult.FunctionalExtensions; | ||
|
||
using TeamUp.Common.Application; | ||
using TeamUp.Common.Contracts; | ||
using TeamUp.TeamManagement.Contracts; | ||
using TeamUp.TeamManagement.Contracts.Events; | ||
using TeamUp.TeamManagement.Contracts.Events.UpsertEventReply; | ||
using TeamUp.TeamManagement.Domain.Aggregates.Events; | ||
using TeamUp.TeamManagement.Domain.Aggregates.Teams; | ||
|
||
namespace TeamUp.TeamManagement.Application.Events; | ||
|
||
internal sealed class UpsertEventReplyCommandHandler : ICommandHandler<UpsertEventReplyCommand> | ||
{ | ||
private readonly IEventRepository _eventRepository; | ||
private readonly ITeamRepository _teamRepository; | ||
private readonly IUnitOfWork<TeamManagementModuleId> _unitOfWork; | ||
private readonly IDateTimeProvider _dateTimeProvider; | ||
|
||
public UpsertEventReplyCommandHandler( | ||
IEventRepository eventRepository, | ||
ITeamRepository teamRepository, | ||
IUnitOfWork<TeamManagementModuleId> unitOfWork, | ||
IDateTimeProvider dateTimeProvider) | ||
{ | ||
_eventRepository = eventRepository; | ||
_teamRepository = teamRepository; | ||
_unitOfWork = unitOfWork; | ||
_dateTimeProvider = dateTimeProvider; | ||
} | ||
|
||
public async Task<Result> Handle(UpsertEventReplyCommand command, CancellationToken ct) | ||
{ | ||
var team = await _teamRepository.GetTeamByIdAsync(command.TeamId, ct); | ||
return await team | ||
.EnsureNotNull(TeamErrors.TeamNotFound) | ||
.Then(team => team.GetTeamMemberByUserId(command.InitiatorId)) | ||
.AndAsync(_ => _eventRepository.GetEventByIdAsync(command.EventId, ct)) | ||
.EnsureSecondNotNull(EventErrors.EventNotFound) | ||
.Ensure((_, @event) => @event.TeamId == command.TeamId, EventErrors.EventNotFound) | ||
.And((_, _) => MapRequestToReply(command)) | ||
.Then((member, @event, reply) => @event.SetMemberResponse(_dateTimeProvider, member.Id, reply)) | ||
.TapAsync(() => _unitOfWork.SaveChangesAsync(ct)); | ||
} | ||
|
||
private static Result<EventReply> MapRequestToReply(UpsertEventReplyCommand command) => command.ReplyType switch | ||
{ | ||
ReplyType.Yes => EventReply.Yes(), | ||
ReplyType.Maybe => EventReply.Maybe(command.Message), | ||
ReplyType.Delay => EventReply.Delay(command.Message), | ||
ReplyType.No => EventReply.No(command.Message), | ||
_ => new InternalError("InternalErrors.MissingSwitchCase", $"{nameof(MapRequestToReply)} does not implement case for type [{command.ReplyType}]") | ||
}; | ||
} |
Oops, something went wrong.