Skip to content

Commit

Permalink
v3.22.1 (#507)
Browse files Browse the repository at this point in the history
* Fixed an issue that caused user roles and login info to fail to appear on the user list page in admin.

* Fixed an issue that could cause Gameboard to fail to align challenge end time with engine expiration.

* WIP

* Minor cleanup

* Fixed a bug that could cause incorrect resolution of user team membership
  • Loading branch information
sei-bstein authored Oct 8, 2024
1 parent a0c046a commit a029548
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public void ResolveCaptain_WhenMultiplePlayersFromSameTeam_ResolvesExpected()
var sut = new TeamService
(
A.Fake<IActingUserService>(),
A.Fake<ICacheService>(),
A.Fake<IGameEngineService>(),
A.Fake<IMapper>(),
A.Fake<IMediator>(),
Expand Down
32 changes: 19 additions & 13 deletions src/Gameboard.Api/Features/Challenge/Services/ChallengeService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@
using Gameboard.Api.Features.GameEngine;
using Gameboard.Api.Features.Teams;
using Gameboard.Api.Features.Scores;
using Gameboard.Api.Features.Users;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using ServiceStack;
using Gameboard.Api.Features.Users;

namespace Gameboard.Api.Services;

public partial class ChallengeService(
public partial class ChallengeService
(
IActingUserService actingUserService,
ConsoleActorMap actorMap,
CoreOptions coreOptions,
Expand All @@ -42,7 +43,7 @@ public partial class ChallengeService(
IUserRolePermissionsService permissionsService,
IStore store,
ITeamService teamService
) : _Service(logger, mapper, coreOptions)
) : _Service(logger, mapper, coreOptions)
{
private readonly IActingUserService _actingUserService = actingUserService;
private readonly ConsoleActorMap _actorMap = actorMap;
Expand Down Expand Up @@ -177,16 +178,16 @@ public async Task Delete(string id)
await _gameEngine.DeleteGamespace(entity);
}

public async Task<bool> UserIsPlayingChallenge(string id, string subjectId)
public async Task<bool> UserIsPlayingChallenge(string challengeId, string userId)
{
var challengeTeamId = await _store
.WithNoTracking<Data.Challenge>()
.Where(c => c.Id == id)
.Where(c => c.Id == challengeId)
.Select(c => c.TeamId)
.Distinct()
.SingleOrDefaultAsync();

var userTeamIds = await _teamService.GetUserTeamIds(subjectId);
var userTeamIds = await _teamService.GetUserTeamIds(userId);
return userTeamIds.Any(tId => tId == challengeTeamId);
}

Expand Down Expand Up @@ -735,14 +736,19 @@ int variant
challenge.StartTime = state.StartTime;
challenge.LastSyncTime = _now.Get();

// even if a specific end time isn't set, use the expiration time instead
if (state.EndTime.IsNotEmpty())
{
challenge.EndTime = state.EndTime;
}
else if (state.ExpirationTime.IsNotEmpty())
// if we haven't already resolved the endtime
if (challenge.EndTime.IsEmpty())
{
challenge.EndTime = state.ExpirationTime;
// prefer the state's end time
if (state.EndTime.IsNotEmpty())
{
challenge.EndTime = state.EndTime;
}
// but fall back on the expiration time
else if (state.ExpirationTime.IsNotEmpty())
{
challenge.EndTime = state.ExpirationTime;
}
}

challenge.Events.Add(new ChallengeEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ await _store
(
up => up
.SetProperty(c => c.LastSyncTime, now)
.SetProperty(c => c.EndTime, c => playerSessionEnds.ContainsKey(challenge.PlayerId) ? playerSessionEnds[challenge.PlayerId] : c.EndTime)
.SetProperty(c => c.EndTime, c => playerSessionEnds.ContainsKey(challenge.PlayerId) ? playerSessionEnds[challenge.PlayerId] : c.EndTime),
cancellationToken
);
}
catch (Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,14 +188,12 @@ public async Task<ConsoleSummary> GetConsole(Data.Challenge entity, ConsoleReque
}

public IEnumerable<GameEngineGamespaceVm> GetGamespaceVms(GameEngineGameState state)
{
return state.Vms.Select(vm => new GameEngineGamespaceVm
=> state.Vms.Select(vm => new GameEngineGamespaceVm
{
Id = vm.Id,
Name = vm.Name,
Url = _vmUrlResolver.ResolveUrl(vm)
});
}
}).ToArray();

public async Task<IEnumerable<GameEngineSectionSubmission>> AuditChallenge(Data.Challenge entity)
{
Expand Down
82 changes: 26 additions & 56 deletions src/Gameboard.Api/Features/Teams/Services/TeamService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,44 +42,26 @@ public interface ITeamService
Task SetSessionWindow(IEnumerable<string> teamIds, CalculatedSessionWindow sessionWindow, CancellationToken cancellationToken);
}

internal class TeamService : ITeamService, INotificationHandler<UserJoinedTeamNotification>
internal class TeamService
(
IActingUserService actingUserService,
IGameEngineService gameEngine,
IMapper mapper,
IMediator mediator,
INowService now,
IInternalHubBus teamHubService,
IPracticeService practiceService,
IStore store
) : ITeamService
{
private readonly IActingUserService _actingUserService;
private readonly ICacheService _cacheService;
private readonly IGameEngineService _gameEngine;
private readonly IMapper _mapper;
private readonly IMediator _mediator;
private readonly INowService _now;
private readonly IInternalHubBus _hubBus;
private readonly IPracticeService _practiceService;
private readonly IStore _store;

public TeamService
(
IActingUserService actingUserService,
ICacheService cacheService,
IGameEngineService gameEngine,
IMapper mapper,
IMediator mediator,
INowService now,
IInternalHubBus teamHubService,
IPracticeService practiceService,
IStore store
)
{
_actingUserService = actingUserService;
_cacheService = cacheService;
_gameEngine = gameEngine;
_mapper = mapper;
_mediator = mediator;
_now = now;
_practiceService = practiceService;
_store = store;
_hubBus = teamHubService;
}

public Task Handle(UserJoinedTeamNotification notification, CancellationToken cancellationToken)
=> Task.Run(() => _cacheService.Invalidate(GetUserTeamIdsCacheKey(notification.UserId)), cancellationToken);
private readonly IActingUserService _actingUserService = actingUserService;
private readonly IGameEngineService _gameEngine = gameEngine;
private readonly IMapper _mapper = mapper;
private readonly IMediator _mediator = mediator;
private readonly INowService _now = now;
private readonly IInternalHubBus _hubBus = teamHubService;
private readonly IPracticeService _practiceService = practiceService;
private readonly IStore _store = store;

public async Task<IEnumerable<Api.Player>> AddPlayers(string teamId, CancellationToken cancellationToken, params string[] playerIds)
{
Expand Down Expand Up @@ -399,22 +381,13 @@ public async Task<IEnumerable<Team>> GetTeams(IEnumerable<string> ids)
}

public Task<string[]> GetUserTeamIds(string userId)
=> _cacheService.GetOrCreateAsync
(
GetUserTeamIdsCacheKey(userId),
async entry =>
{
var userTeamIds = await _store
.WithNoTracking<Data.Player>()
.Where(p => p.UserId == userId)
.Select(p => p.TeamId)
.Distinct()
.ToArrayAsync();
entry.Value = userTeamIds;
return userTeamIds;
}
);
=> _store
.WithNoTracking<Data.Player>()
.Where(p => p.UserId == userId)
.Select(p => p.TeamId)
.Distinct()
.ToArrayAsync();


public async Task<bool> IsAtGamespaceLimit(string teamId, Data.Game game, CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -583,7 +556,4 @@ private async Task<TeamState> GetTeamState(string teamId, SimpleEntity actor, Ca
Actor = actor
};
}

private string GetUserTeamIdsCacheKey(string userId)
=> $"UserTeamIds:{userId}";
}
18 changes: 9 additions & 9 deletions src/Gameboard.Api/Features/User/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ public class UserSettings

public class UserOnly
{
public string Id { get; set; }
public string Name { get; set; }
public string NameStatus { get; set; }
public string ApprovedName { get; set; }
public SponsorWithParentSponsor Sponsor { get; set; }
public DateTimeOffset CreatedOn { get; set; }
public DateTimeOffset? LastLoginDate { get; set; }
public int LoginCount { get; set; }
public UserRoleKey Role { get; set; }
public required string Id { get; set; }
public required string Name { get; set; }
public required string NameStatus { get; set; }
public required string ApprovedName { get; set; }
public required SponsorWithParentSponsor Sponsor { get; set; }
public required DateTimeOffset CreatedOn { get; set; }
public required DateTimeOffset? LastLoginDate { get; set; }
public required int LoginCount { get; set; }
public required UserRoleKey Role { get; set; }
}

public class TryCreateUserResult
Expand Down
4 changes: 4 additions & 0 deletions src/Gameboard.Api/Features/User/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ public async Task<IEnumerable<UserOnly>> List<TProject>(UserSearch model) where
Name = u.Name,
NameStatus = u.NameStatus,
ApprovedName = u.ApprovedName,
CreatedOn = u.CreatedOn,
LastLoginDate = u.LastLoginDate,
LoginCount = u.LoginCount,
Role = u.Role,
Sponsor = new SponsorWithParentSponsor
{
Id = u.SponsorId,
Expand Down

0 comments on commit a029548

Please sign in to comment.