-
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.
* added change nickname endpoint, contract, command and command handler * added change nickname endpoint tests * fixed variable naming in team endpoints (query to command)
- Loading branch information
1 parent
2d42f1c
commit 5066cda
Showing
6 changed files
with
296 additions
and
10 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
8 changes: 8 additions & 0 deletions
8
src/TeamUp.Application/Teams/ChangeNickname/ChangeNicknameCommand.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,8 @@ | ||
using TeamUp.Application.Abstractions; | ||
using TeamUp.Common; | ||
using TeamUp.Domain.Aggregates.Teams; | ||
using TeamUp.Domain.Aggregates.Users; | ||
|
||
namespace TeamUp.Application.Teams.SetMemberNickname; | ||
|
||
public sealed record ChangeNicknameCommand(UserId InitiatorId, TeamId TeamId, string Nickname) : ICommand<Result>; |
27 changes: 27 additions & 0 deletions
27
src/TeamUp.Application/Teams/ChangeNickname/ChangeNicknameCommandHandler.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 TeamUp.Application.Abstractions; | ||
using TeamUp.Common; | ||
using TeamUp.Domain.Abstractions; | ||
using TeamUp.Domain.Aggregates.Teams; | ||
|
||
namespace TeamUp.Application.Teams.SetMemberNickname; | ||
|
||
internal sealed class ChangeNicknameCommandHandler : ICommandHandler<ChangeNicknameCommand, Result> | ||
{ | ||
private readonly ITeamRepository _teamRepository; | ||
private readonly IUnitOfWork _unitOfWork; | ||
|
||
public ChangeNicknameCommandHandler(ITeamRepository teamRepository, IUnitOfWork unitOfWork) | ||
{ | ||
_teamRepository = teamRepository; | ||
_unitOfWork = unitOfWork; | ||
} | ||
|
||
public async Task<Result> Handle(ChangeNicknameCommand request, CancellationToken ct) | ||
{ | ||
var team = await _teamRepository.GetTeamByIdAsync(request.TeamId, ct); | ||
return await team | ||
.EnsureNotNull(TeamErrors.TeamNotFound) | ||
.Then(team => team.ChangeNickname(request.InitiatorId, request.Nickname)) | ||
.TapAsync(() => _unitOfWork.SaveChangesAsync(ct)); | ||
} | ||
} |
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,24 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
|
||
using FluentValidation; | ||
|
||
using TeamUp.Domain.Aggregates.Teams; | ||
|
||
namespace TeamUp.Contracts.Teams; | ||
|
||
public sealed class ChangeNicknameRequest : IRequestBody | ||
{ | ||
[DataType(DataType.Text)] | ||
public required string Nickname { get; init; } | ||
|
||
public sealed class Validator : AbstractValidator<ChangeNicknameRequest> | ||
{ | ||
public Validator() | ||
{ | ||
RuleFor(x => x.Nickname) | ||
.NotEmpty() | ||
.MinimumLength(Team.NICKNAME_MIN_SIZE) | ||
.MaximumLength(Team.NICKNAME_MAX_SIZE); | ||
} | ||
} | ||
} |
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
199 changes: 199 additions & 0 deletions
199
tests/TeamUp.EndToEndTests/EndpointTests/Teams/ChangeNicknameTests.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,199 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
using TeamUp.Contracts.Teams; | ||
using TeamUp.Domain.Aggregates.Teams; | ||
|
||
namespace TeamUp.EndToEndTests.EndpointTests.Teams; | ||
|
||
public sealed class ChangeNicknameTests : BaseTeamTests | ||
{ | ||
public ChangeNicknameTests(TeamApiWebApplicationFactory appFactory) : base(appFactory) { } | ||
|
||
[Fact] | ||
public async Task ChangeNickname_ToValidNickname_AsOwner_Should_UpdateNicknameInDatabase() | ||
{ | ||
//arrange | ||
var owner = UserGenerator.ActivatedUser.Generate(); | ||
var members = UserGenerator.ActivatedUser.Generate(19); | ||
var team = TeamGenerator.GenerateTeamWith(owner, members); | ||
|
||
await UseDbContextAsync(dbContext => | ||
{ | ||
dbContext.Users.Add(owner); | ||
dbContext.Users.AddRange(members); | ||
dbContext.Teams.Add(team); | ||
return dbContext.SaveChangesAsync(); | ||
}); | ||
|
||
Authenticate(owner); | ||
|
||
var targetMemberId = team.Members.FirstOrDefault(member => member.UserId == owner.Id)!.Id; | ||
var request = new ChangeNicknameRequest | ||
{ | ||
Nickname = TeamGenerator.GenerateValidNickname() | ||
}; | ||
|
||
//act | ||
var response = await Client.PutAsJsonAsync($"/api/v1/teams/{team.Id.Value}/nickname", request); | ||
|
||
//assert | ||
response.Should().Be200Ok(); | ||
|
||
var member = await UseDbContextAsync(dbContext => | ||
{ | ||
return dbContext | ||
.Set<TeamMember>() | ||
.SingleOrDefaultAsync(member => member.Id == targetMemberId); | ||
}); | ||
|
||
member.ShouldNotBeNull(); | ||
member.Nickname.Should().Be(request.Nickname); | ||
} | ||
|
||
[Theory] | ||
[InlineData(TeamRole.Member)] | ||
[InlineData(TeamRole.Coordinator)] | ||
[InlineData(TeamRole.Admin)] | ||
public async Task ChangeNickname_ToValidNickname_AsAdminOrLower_Should_UpdateNicknameInDatabase(TeamRole teamRole) | ||
{ | ||
//arrange | ||
var owner = UserGenerator.ActivatedUser.Generate(); | ||
var initiatorUser = UserGenerator.ActivatedUser.Generate(); | ||
var members = UserGenerator.ActivatedUser.Generate(18); | ||
var team = TeamGenerator.GenerateTeamWith(owner, members, (initiatorUser, teamRole)); | ||
|
||
await UseDbContextAsync(dbContext => | ||
{ | ||
dbContext.Users.AddRange([owner, initiatorUser]); | ||
dbContext.Users.AddRange(members); | ||
dbContext.Teams.Add(team); | ||
return dbContext.SaveChangesAsync(); | ||
}); | ||
|
||
Authenticate(initiatorUser); | ||
|
||
var targetMemberId = team.Members.FirstOrDefault(member => member.UserId == initiatorUser.Id)!.Id; | ||
var request = new ChangeNicknameRequest | ||
{ | ||
Nickname = TeamGenerator.GenerateValidNickname() | ||
}; | ||
|
||
//act | ||
var response = await Client.PutAsJsonAsync($"/api/v1/teams/{team.Id.Value}/nickname", request); | ||
|
||
//assert | ||
response.Should().Be200Ok(); | ||
|
||
var member = await UseDbContextAsync(dbContext => | ||
{ | ||
return dbContext | ||
.Set<TeamMember>() | ||
.SingleOrDefaultAsync(member => member.Id == targetMemberId); | ||
}); | ||
|
||
member.ShouldNotBeNull(); | ||
member.Nickname.Should().Be(request.Nickname); | ||
} | ||
|
||
[Fact] | ||
public async Task ChangeNickname_WhenNotMemberOfTeam_Should_ResultInForbidden() | ||
{ | ||
//arrange | ||
var owner = UserGenerator.ActivatedUser.Generate(); | ||
var initiatorUser = UserGenerator.ActivatedUser.Generate(); | ||
var members = UserGenerator.ActivatedUser.Generate(19); | ||
var team = TeamGenerator.GenerateTeamWith(owner, members); | ||
|
||
await UseDbContextAsync(dbContext => | ||
{ | ||
dbContext.Users.AddRange([owner, initiatorUser]); | ||
dbContext.Users.AddRange(members); | ||
dbContext.Teams.Add(team); | ||
return dbContext.SaveChangesAsync(); | ||
}); | ||
|
||
Authenticate(initiatorUser); | ||
|
||
var request = new ChangeNicknameRequest | ||
{ | ||
Nickname = TeamGenerator.GenerateValidNickname() | ||
}; | ||
|
||
//act | ||
var response = await Client.PutAsJsonAsync($"/api/v1/teams/{team.Id.Value}/nickname", request); | ||
|
||
//assert | ||
response.Should().Be403Forbidden(); | ||
|
||
var problemDetails = await response.Content.ReadFromJsonAsync<ProblemDetails>(); | ||
problemDetails.ShouldContainError(TeamErrors.NotMemberOfTeam); | ||
} | ||
|
||
[Fact] | ||
public async Task ChangeNickname_InTeamThatDoesNotExist_Should_ResultInNotFound() | ||
{ | ||
//arrange | ||
var user = UserGenerator.ActivatedUser.Generate(); | ||
|
||
await UseDbContextAsync(dbContext => | ||
{ | ||
dbContext.Users.Add(user); | ||
return dbContext.SaveChangesAsync(); | ||
}); | ||
|
||
Authenticate(user); | ||
|
||
var teamId = F.Random.Guid(); | ||
var request = new ChangeNicknameRequest | ||
{ | ||
Nickname = TeamGenerator.GenerateValidNickname() | ||
}; | ||
|
||
//act | ||
var response = await Client.PutAsJsonAsync($"/api/v1/teams/{teamId}/nickname", request); | ||
|
||
//assert | ||
response.Should().Be404NotFound(); | ||
|
||
var problemDetails = await response.Content.ReadFromJsonAsync<ProblemDetails>(); | ||
problemDetails.ShouldContainError(TeamErrors.TeamNotFound); | ||
} | ||
|
||
[Theory] | ||
[InlineData("")] | ||
[InlineData("x")] | ||
[InlineData("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")] | ||
public async Task ChangeNickname_ToInvalidName_Should_ResultInBadRequest(string invalidName) | ||
{ | ||
//arrange | ||
var owner = UserGenerator.ActivatedUser.Generate(); | ||
var initiatorUser = UserGenerator.ActivatedUser.Generate(); | ||
var members = UserGenerator.ActivatedUser.Generate(18); | ||
var team = TeamGenerator.GenerateTeamWith(owner, members, (initiatorUser, TeamRole.Member)); | ||
|
||
await UseDbContextAsync(dbContext => | ||
{ | ||
dbContext.Users.AddRange([owner, initiatorUser]); | ||
dbContext.Users.AddRange(members); | ||
dbContext.Teams.Add(team); | ||
return dbContext.SaveChangesAsync(); | ||
}); | ||
|
||
Authenticate(initiatorUser); | ||
|
||
var targetMemberId = team.Members.FirstOrDefault(member => member.UserId == initiatorUser.Id)!.Id; | ||
var request = new ChangeNicknameRequest | ||
{ | ||
Nickname = invalidName | ||
}; | ||
|
||
//act | ||
var response = await Client.PutAsJsonAsync($"/api/v1/teams/{team.Id.Value}/nickname", request); | ||
|
||
//assert | ||
response.Should().Be400BadRequest(); | ||
|
||
var problemDetails = await response.Content.ReadFromJsonAsync<ValidationProblemDetails>(); | ||
problemDetails.ShouldContainValidationErrorFor(nameof(ChangeNicknameRequest.Nickname)); | ||
} | ||
} |