Skip to content

Commit

Permalink
Fix Communications Between Modules (#8)
Browse files Browse the repository at this point in the history
fix communications between modules to be asynchronous:
change `GenerateUserCommand` to `GenerateUserRequestCreatedIntegrationEvent`
  • Loading branch information
skrasekmichael authored May 2, 2024
1 parent dd4c976 commit e418827
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ public CreateInvitationRequestCreatedEventHandler(IUserRepository userRepository

public async Task<Result> Handle(CreateInvitationRequestCreatedIntegrationEvent integrationEvent, CancellationToken ct)
{
var user = await _userRepository.GetUserByIdAsync(integrationEvent.UserId, ct);
var user = await _userRepository.GetUserByEmailAsync(integrationEvent.Email, ct);
if (user is null)
{
_logger.LogWarning("User {userId} is not yet created for inviting to team {teamId}.", integrationEvent.UserId, integrationEvent.TeamId);
_logger.LogWarning("User {userEmail} is not yet created for inviting to team {teamId}.", integrationEvent.Email, integrationEvent.TeamId);
return new EventualConsistencyError("TeamManagement.Users.NotFound", "User not found when inviting.");
}

Expand All @@ -60,7 +60,7 @@ public async Task<Result> Handle(CreateInvitationRequestCreatedIntegrationEvent
{
if (result.Error is ConflictError error)
{
_logger.LogWarning("Invitation of user {userId} to team {teamId} probably already exist. {error}", integrationEvent.UserId, integrationEvent.TeamId, error);
_logger.LogWarning("Invitation of user {userEmail} to team {teamId} probably already exist. {error}", integrationEvent.Email, integrationEvent.TeamId, error);
return Result.Success;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using TeamUp.Common.Contracts;
using TeamUp.TeamManagement.Contracts.Teams;
using TeamUp.UserAccess.Contracts;

namespace TeamUp.TeamManagement.Domain.Aggregates.Invitations.IntegrationEvents;

public sealed record CreateInvitationRequestCreatedIntegrationEvent : IIntegrationEvent
{
public required UserId UserId { get; init; }
public required string Email { get; init; }
public required TeamId TeamId { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,19 @@ internal sealed class InvitationDomainService : IInvitationDomainService
private readonly ITeamRepository _teamRepository;
private readonly IInvitationRepository _invitationRepository;
private readonly IIntegrationEventPublisher<TeamManagementModuleId> _publisher;
private readonly IRequestClient<GenerateUserCommand> _client;
private readonly IDateTimeProvider _dateTimeProvider;

public InvitationDomainService(
IUserRepository userRepository,
ITeamRepository teamRepository,
IInvitationRepository invitationRepository,
IIntegrationEventPublisher<TeamManagementModuleId> publisher,
IRequestClient<GenerateUserCommand> client,
IDateTimeProvider dateTimeProvider)
{
_userRepository = userRepository;
_teamRepository = teamRepository;
_invitationRepository = invitationRepository;
_publisher = publisher;
_client = client;
_dateTimeProvider = dateTimeProvider;
}

Expand Down Expand Up @@ -65,6 +62,7 @@ public async Task<Result> AcceptInvitationAsync(UserId initiatorId, InvitationId
.ToResultAsync();
}


public async Task<Result> InviteUserAsync(UserId initiatorId, TeamId teamId, string email, CancellationToken ct = default)
{
var team = await _teamRepository.GetTeamByIdAsync(teamId, ct);
Expand All @@ -76,49 +74,43 @@ public async Task<Result> InviteUserAsync(UserId initiatorId, TeamId teamId, str
.Then((team, _) => team)
.AndAsync(team => _userRepository.GetUserByEmailAsync(email, ct))
.Ensure(TeamRules.InvitedUserIsNotTeamMember)
.ThenAsync(async (team, user) =>
.ThenAsync<Team, User?, (Team, string)>(async (team, user) =>
{
//generate user if user doesn't exist
if (user is null)
{
return await GenerateUserAsync(email, ct)
.Then(userId => (team, userId));
var message = new GenerateUserRequestCreatedIntegrationEvent
{
Email = email,
Name = email
};

_publisher.Publish(message);
return (team, email);
}

//check for whether user is already invited to the same team
//check whether user is already invited to the same team
var conflictingInvitationExists = await _invitationRepository.ExistsInvitationForUserToTeamAsync(user.Id, teamId, ct);
if (conflictingInvitationExists)
{
return InvitationErrors.UserIsAlreadyInvited;
}

return (team, user.Id);
return (team, user.Email);
})
.Tap((team, userId) =>
.Tap((team, email) =>
{
var message = new CreateInvitationRequestCreatedIntegrationEvent
{
TeamId = team.Id,
UserId = userId
Email = email
};

_publisher.Publish(message);
})
.ToResultAsync();
}

private async Task<Result<UserId>> GenerateUserAsync(string email, CancellationToken ct)
{
var message = new GenerateUserCommand
{
Email = email,
Name = email
};

var response = await _client.GetResponse<Result<UserId>>(message, ct);
return response.Message;
}

public async Task<Result> RemoveInvitationAsync(UserId initiatorId, InvitationId invitationId, CancellationToken ct = default)
{
var invitation = await _invitationRepository.GetInvitationByIdAsync(invitationId, ct);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,23 @@

namespace TeamUp.UserAccess.Application;

internal sealed class GenerateUserCommandHandler : ICommandHandler<GenerateUserCommand, UserId>
internal sealed class GenerateUserRequestCreatedEventHandler : IIntegrationEventHandler<GenerateUserRequestCreatedIntegrationEvent>
{
private readonly UserFactory _userFactory;
private readonly IUnitOfWork<UserAccessModuleId> _unitOfWork;

public GenerateUserCommandHandler(
public GenerateUserRequestCreatedEventHandler(
UserFactory userFactory,
IUnitOfWork<UserAccessModuleId> unitOfWork)
{
_userFactory = userFactory;
_unitOfWork = unitOfWork;
}

public async Task<Result<UserId>> Handle(GenerateUserCommand command, CancellationToken ct)
public async Task<Result> Handle(GenerateUserRequestCreatedIntegrationEvent command, CancellationToken ct)
{
return await _userFactory
.GenerateAndAddUserAsync(command.Name, command.Email, ct)
.Then(user => user.Id)
.TapAsync(_ => _unitOfWork.SaveChangesAsync(ct));
.ThenAsync(_ => _unitOfWork.SaveChangesAsync(ct));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

namespace TeamUp.UserAccess.Contracts.CreateUser;

public sealed record GenerateUserCommand : ICommand<UserId>
public sealed record GenerateUserRequestCreatedIntegrationEvent : IIntegrationEvent
{
public required string Name { get; init; }
public required string Email { get; init; }

public sealed class Validator : AbstractValidator<GenerateUserCommand>
public sealed class Validator : AbstractValidator<GenerateUserRequestCreatedIntegrationEvent>
{
public Validator()
{
Expand Down

0 comments on commit e418827

Please sign in to comment.