Skip to content

Commit

Permalink
Get User Teams (#9)
Browse files Browse the repository at this point in the history
* add missing get user teams endpoint, query and query handler
* add `TeamSlimResponse`
* add get user teams endpoint tests
  • Loading branch information
skrasekmichael committed May 3, 2024
1 parent e418827 commit 5e094a1
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore;

using RailwayResult;

using TeamUp.Common.Application;
using TeamUp.Common.Contracts;
using TeamUp.TeamManagement.Application;
using TeamUp.TeamManagement.Contracts.Teams;
using TeamUp.TeamManagement.Contracts.Teams.GetUserTeams;

namespace TeamUp.Application.Teams.GetUserTeams;

internal sealed class GetUserTeamsQueryHandler : IQueryHandler<GetUserTeamsQuery, Collection<TeamSlimResponse>>
{
private readonly ITeamManagementQueryContext _appQueryContext;

public GetUserTeamsQueryHandler(ITeamManagementQueryContext appQueryContext)
{
_appQueryContext = appQueryContext;
}

public async Task<Result<Collection<TeamSlimResponse>>> Handle(GetUserTeamsQuery query, CancellationToken ct)
{
var teams = await _appQueryContext.Teams
.Where(team => team.Members.Any(member => member.UserId == query.InitiatorId))
.Select(team => new TeamSlimResponse
{
TeamId = team.Id,
Name = team.Name,
})
.ToListAsync(ct);

return new Collection<TeamSlimResponse>(teams);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using FluentValidation;

using TeamUp.Common.Contracts;
using TeamUp.UserAccess.Contracts;

namespace TeamUp.TeamManagement.Contracts.Teams.GetUserTeams;

public sealed record GetUserTeamsQuery : IQuery<Collection<TeamSlimResponse>>
{
public required UserId InitiatorId { get; init; }

public sealed class Validator : AbstractValidator<GetUserTeamsQuery>
{
public Validator()
{
RuleFor(x => x.InitiatorId).NotEmpty();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TeamUp.TeamManagement.Contracts.Teams;

public sealed class TeamSlimResponse
{
public required TeamId TeamId { get; init; }
public required string Name { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public EndpointGroupBuilder MapEndpoints(EndpointGroupBuilder group)
group
.AddEndpoint<CreateTeamEndpoint>()
.AddEndpoint<GetTeamEndpoint>()
.AddEndpoint<GetUserTeamsEndpoint>()
.AddEndpoint<DeleteTeamEndpoint>()
.AddEndpoint<ChangeOwnershipEndpoint>()
.AddEndpoint<RemoveTeamMemberEndpoint>()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using MediatR;

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;

using TeamUp.Common.Endpoints;
using TeamUp.TeamManagement.Contracts.Teams;
using TeamUp.TeamManagement.Contracts.Teams.GetUserTeams;
using TeamUp.UserAccess.Contracts;

namespace TeamUp.TeamManagement.Endpoints.Teams;

public sealed class GetUserTeamsEndpoint : IEndpoint
{
public void MapEndpoint(RouteGroupBuilder group)
{
group.MapGet("/", GetTeamAsync)
.Produces<List<TeamSlimResponse>>(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status401Unauthorized)
.ProducesProblem(StatusCodes.Status403Forbidden)
.ProducesProblem(StatusCodes.Status404NotFound)
.WithName(nameof(GetUserTeamsEndpoint))
.MapToApiVersion(1);
}

private async Task<IResult> GetTeamAsync([FromServices] ISender sender, HttpContext httpContext, CancellationToken ct)
{
var query = new GetUserTeamsQuery
{
InitiatorId = httpContext.GetCurrentUserId()
};

var result = await sender.Send(query, ct);
return result.ToResponse(TypedResults.Ok);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using TeamUp.TeamManagement.Contracts.Teams;
using TeamUp.TeamManagement.Infrastructure;
using TeamUp.Tests.Common.DataGenerators.TeamManagement;
using TeamUp.Tests.Common.DataGenerators.UserAccess;
using TeamUp.UserAccess.Infrastructure.Persistence;

namespace TeamUp.Tests.EndToEnd.EndpointTests.TeamManagement.Teams;

public sealed class GetUserTeamsTests(AppFixture app) : TeamTests(app)
{
public const string URL = "/api/v1/teams";

[Fact]
public async Task GetUserTeams_WhenNotMemberOfTeam_Should_ReturnEmptyList()
{
//arrange
var userUA = UserGenerators.User.Generate();
var user = userUA.ToUserTM();

await UseDbContextAsync<UserAccessDbContext>(dbContext =>
{
dbContext.Users.Add(userUA);
return dbContext.SaveChangesAsync();
});

await UseDbContextAsync<TeamManagementDbContext>(dbContext =>
{
dbContext.Users.Add(user);
return dbContext.SaveChangesAsync();
});

Authenticate(userUA);

//act
var response = await Client.GetAsync(URL);

//assert
response.Should().Be200Ok();

var teams = await response.ReadFromJsonAsync<List<TeamSlimResponse>>();
teams.Should().BeEmpty();
}

[Fact]
public async Task GetUserTeams_Should_ReturnTeams_ThatUserIsMemberOf()
{
//arrange
var initiatorUserUA = UserGenerators.User.Generate();
var initiatorUser = initiatorUserUA.ToUserTM();

var membersUA = UserGenerators.User.Generate(19);
var members = membersUA.ToUsersTM();

var memberTeams = new TeamRole[] { TeamRole.Owner, TeamRole.Admin, TeamRole.Coordinator, TeamRole.Member }
.Select(role => TeamGenerators.Team.WithMembers(initiatorUser, role, members).Generate())
.ToList();
var expectedTeams = memberTeams.Select(team => new TeamSlimResponse
{
TeamId = team.Id,
Name = team.Name,
});

var otherTeam = TeamGenerators.Team.WithOneOwner(members.First());

await UseDbContextAsync<UserAccessDbContext>(dbContext =>
{
dbContext.Users.Add(initiatorUserUA);
dbContext.Users.AddRange(membersUA);
return dbContext.SaveChangesAsync();
});

await UseDbContextAsync<TeamManagementDbContext>(dbContext =>
{
dbContext.Users.Add(initiatorUser);
dbContext.Users.AddRange(members);
dbContext.Teams.Add(otherTeam);
dbContext.Teams.AddRange(memberTeams);
return dbContext.SaveChangesAsync();
});

Authenticate(initiatorUserUA);

//act
var response = await Client.GetAsync(URL);

//assert
response.Should().Be200Ok();

var teams = await response.ReadFromJsonAsync<List<TeamSlimResponse>>();
teams.Should().BeEquivalentTo(expectedTeams);
}
}

0 comments on commit 5e094a1

Please sign in to comment.