Skip to content

Commit

Permalink
v3.28.0 (#596)
Browse files Browse the repository at this point in the history
* Resolves #522

* WIP export

* Fix an issue that caused the game name to be null in ticket markdown export

* Fixed an issue where challenges from games with no end date wouldn't appear in the ticket challenge picker

* Add cancellation tokens to report endpoints, fix denorm bug for new scoring teams.

* Cleanup

* Minor cleanup

* WIP import/export

* Fix flailing test and more defense for session time stuff

* WIP import/export

* MVP import/export endpoints

* Fix 'top performance' for #594

* Add 'completed teams' to game center for #594

* Remove old cert stuff. Rename RequirePermissions to Require. Fix tests

* Remove version endpoint since we no longer support it anyway.

* Resolve #572

* Fixed autotagging bug and minor cleanup

* Fix autotagging bugs, add observe to practice tab, fix import/export stuff

* Fix bug that prevented feedback from loading for support personnel

* Fix enrollment report unstarted teams calc. Fix challenge launch failure after an attempt that is canceled

* Align calculation of 'team has started' logic

* Minor cleanup

* Add export download endpoint

* Add missing export field

* Add missing field

* Hide test in dev
  • Loading branch information
sei-bstein authored Jan 16, 2025
1 parent 38c11b2 commit cbe2bd2
Show file tree
Hide file tree
Showing 136 changed files with 6,367 additions and 877 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ Thumbs.db
# git-kept
src/Gameboard.Api/wwwroot/temp/*
!.gitkeep

# stuff that gameboard makes as part of being itself
src/Gameboard.Api/wwwroot/export/*
src/Gameboard.Api/wwwroot/import/*
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
namespace Gameboard.Api.Tests.Integration;

public class CertificatesControllerTests_GetCertificatesTests(GameboardTestContext testContext) : IClassFixture<GameboardTestContext>
{
private readonly GameboardTestContext _testContext = testContext;

// [Theory, GbIntegrationAutoData]
// public async Task GetCertificates_WhenScoreConstrained_ReturnsExpectedCount
// (
// int score,
// string scoringUserId,
// string scoringPlayerId,
// string nonScoringUserId,
// string nonScoringPlayerId,
// IFixture fixture
// )
// {
// // given
// var now = DateTimeOffset.UtcNow;

// await _testContext.WithDataState(state =>
// {
// state.Add<Data.Game>(fixture, g =>
// {
// g.GameEnd = now - TimeSpan.FromDays(1);
// g.CertificateTemplateLegacy = "This is a template with a {{player_count}}.";
// g.Players =
// [
// // i almost broke my brain trying to get GbIntegrationAutoData to work with
// // inline autodata, so I'm just doing two checks here
// state.Build<Data.Player>(fixture, p =>
// {
// p.Id = scoringPlayerId;
// p.User = state.Build<Data.User>(fixture, u => u.Id = scoringUserId);
// p.UserId = scoringUserId;
// p.SessionEnd = now - TimeSpan.FromDays(-2);
// p.TeamId = "teamId";
// p.Score = score;
// }),
// state.Build<Data.Player>(fixture, p =>
// {
// p.Id = nonScoringPlayerId;
// p.User = state.Build<Data.User>(fixture, u => u.Id = nonScoringUserId);
// p.UserId = nonScoringUserId;
// p.SessionEnd = now - TimeSpan.FromDays(-2);
// p.TeamId = "teamId";
// p.Score = score;
// })
// ];
// });
// });

// var httpClient = _testContext.CreateHttpClientWithActingUser(u => u.Id = scoringUserId);

// // when
// var certs = await httpClient
// .GetAsync("/api/certificates")
// .DeserializeResponseAs<IEnumerable<PlayerCertificate>>();

// // then
// certs?.Count().ShouldBe(1);
// certs?.First().Player.Id.ShouldBe(scoringPlayerId);
// }

// [Theory, GbIntegrationAutoData]
// public async Task GetCertificates_WithTeamsAndNonScorers_ReturnsExpected(string teamId, string userId, IFixture fixture)
// {
// // given
// var now = DateTimeOffset.UtcNow;
// var recentDate = DateTime.UtcNow.AddDays(-1);

// await _testContext.WithDataState(state =>
// {
// state.Add<Data.Game>(fixture, g =>
// {
// g.CertificateTemplateLegacy = "This is a template with a {{player_count}} and a {{team_count}}.";
// g.GameEnd = now - TimeSpan.FromDays(1);
// g.Players = new List<Data.Player>
// {
// // three players with nonzero score (2 on the same team)
// state.Build<Data.Player>(fixture, p =>
// {
// p.SessionEnd = recentDate;
// p.Score = 20;
// p.User = state.Build<Data.User>(fixture, u => u.Id = userId);
// }),
// state.Build<Data.Player>(fixture, p =>
// {
// p.SessionEnd = recentDate;
// p.Score = 30;
// p.TeamId = teamId;
// }),
// state.Build<Data.Player>(fixture, p =>
// {
// p.SessionEnd = recentDate;
// p.Score = 30;
// p.TeamId = teamId;
// }),
// // one player with zero score
// state.Build<Data.Player>(fixture, p =>
// {
// p.SessionEnd = recentDate;
// p.Score = 0;
// }),
// };
// });
// });

// var httpClient = _testContext.CreateHttpClientWithActingUser(u => u.Id = userId);

// // when
// var certsResponse = await httpClient
// .GetAsync("/api/certificates")
// .DeserializeResponseAs<IEnumerable<PlayerCertificate>>();

// // then
// var certs = certsResponse.ToArray();
// certs.ShouldNotBeNull();
// certs.Count().ShouldBe(1);
// certs.First().Html.ShouldBe("This is a template with a 3 and a 2.");
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,120 +50,4 @@ await _testContext
// assert
updatedPlayer?.NameStatus.ShouldBe(AppConstants.NameStatusNotUnique);
}

[Theory, GbIntegrationAutoData]
public async Task GetCertificates_WhenScoreConstrained_ReturnsExpectedCount
(
int score,
string scoringUserId,
string scoringPlayerId,
string nonScoringUserId,
string nonScoringPlayerId,
IFixture fixture
)
{
// given
var now = DateTimeOffset.UtcNow;

await _testContext.WithDataState(state =>
{
state.Add<Data.Game>(fixture, g =>
{
g.GameEnd = now - TimeSpan.FromDays(1);
g.CertificateTemplateLegacy = "This is a template with a {{player_count}}.";
g.Players =
[
// i almost broke my brain trying to get GbIntegrationAutoData to work with
// inline autodata, so I'm just doing two checks here
state.Build<Data.Player>(fixture, p =>
{
p.Id = scoringPlayerId;
p.User = state.Build<Data.User>(fixture, u => u.Id = scoringUserId);
p.UserId = scoringUserId;
p.SessionEnd = now - TimeSpan.FromDays(-2);
p.TeamId = "teamId";
p.Score = score;
}),
state.Build<Data.Player>(fixture, p =>
{
p.Id = nonScoringPlayerId;
p.User = state.Build<Data.User>(fixture, u => u.Id = nonScoringUserId);
p.UserId = nonScoringUserId;
p.SessionEnd = now - TimeSpan.FromDays(-2);
p.TeamId = "teamId";
p.Score = score;
})
];
});
});

var httpClient = _testContext.CreateHttpClientWithActingUser(u => u.Id = scoringUserId);

// when
var certs = await httpClient
.GetAsync("/api/certificates")
.DeserializeResponseAs<IEnumerable<PlayerCertificate>>();

// then
certs?.Count().ShouldBe(1);
certs?.First().Player.Id.ShouldBe(scoringPlayerId);
}

[Theory, GbIntegrationAutoData]
public async Task GetCertificates_WithTeamsAndNonScorers_ReturnsExpected(string teamId, string userId, IFixture fixture)
{
// given
var now = DateTimeOffset.UtcNow;
var recentDate = DateTime.UtcNow.AddDays(-1);

await _testContext.WithDataState(state =>
{
state.Add<Data.Game>(fixture, g =>
{
g.CertificateTemplateLegacy = "This is a template with a {{player_count}} and a {{team_count}}.";
g.GameEnd = now - TimeSpan.FromDays(1);
g.Players = new List<Data.Player>
{
// three players with nonzero score (2 on the same team)
state.Build<Data.Player>(fixture, p =>
{
p.SessionEnd = recentDate;
p.Score = 20;
p.User = state.Build<Data.User>(fixture, u => u.Id = userId);
}),
state.Build<Data.Player>(fixture, p =>
{
p.SessionEnd = recentDate;
p.Score = 30;
p.TeamId = teamId;
}),
state.Build<Data.Player>(fixture, p =>
{
p.SessionEnd = recentDate;
p.Score = 30;
p.TeamId = teamId;
}),
// one player with zero score
state.Build<Data.Player>(fixture, p =>
{
p.SessionEnd = recentDate;
p.Score = 0;
}),
};
});
});

var httpClient = _testContext.CreateHttpClientWithActingUser(u => u.Id = userId);

// when
var certsResponse = await httpClient
.GetAsync("/api/certificates")
.DeserializeResponseAs<IEnumerable<PlayerCertificate>>();

// then
var certs = certsResponse.ToArray();
certs.ShouldNotBeNull();
certs.Count().ShouldBe(1);
certs.First().Html.ShouldBe("This is a template with a 3 and a 2.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,50 +8,50 @@ public class SupportControllerTests(GameboardTestContext testContext) : IClassFi
{
private readonly GameboardTestContext _testContext = testContext;

[Theory, GbIntegrationAutoData]
public async Task Ticket_WhenCreatedWithAutoTagTrigger_AutoTags
(
IFixture fixture,
string gameId,
string tag,
string sponsorId,
string userId
)
{
// given an autotag which triggers on sponsor and a player with that sponsor
await _testContext.WithDataState(state =>
{
state.Add<Data.Game>(fixture, g =>
{
g.Id = gameId;
g.Players = new Data.Player
{
Id = fixture.Create<string>(),
Sponsor = state.Build<Data.Sponsor>(fixture, s => s.Id = sponsorId),
User = new Data.User { Id = userId, SponsorId = sponsorId }
}.ToCollection();
});
// [Theory, GbIntegrationAutoData]
// public async Task Ticket_WhenCreatedWithAutoTagTrigger_AutoTags
// (
// IFixture fixture,
// string gameId,
// string tag,
// string sponsorId,
// string userId
// )
// {
// // given an autotag which triggers on sponsor and a player with that sponsor
// await _testContext.WithDataState(state =>
// {
// state.Add<Data.Game>(fixture, g =>
// {
// g.Id = gameId;
// g.Players = new Data.Player
// {
// Id = fixture.Create<string>(),
// Sponsor = state.Build<Data.Sponsor>(fixture, s => s.Id = sponsorId),
// User = new Data.User { Id = userId, SponsorId = sponsorId }
// }.ToCollection();
// });

state.Add<SupportSettingsAutoTag>(fixture, t =>
{
t.ConditionType = SupportSettingsAutoTagConditionType.SponsorId;
t.ConditionValue = sponsorId;
t.IsEnabled = true;
t.Tag = tag;
});
});
// state.Add<SupportSettingsAutoTag>(fixture, t =>
// {
// t.ConditionType = SupportSettingsAutoTagConditionType.SponsorId;
// t.ConditionValue = sponsorId;
// t.IsEnabled = true;
// t.Tag = tag;
// });
// });

// var result = await _testContext
// .CreateHttpClientWithAuthRole(UserRoleKey.Support)
// .PostAsync("api/ticket", new NewTicket
// {
// AssigneeId = userId,
// Description = fixture.Create<string>(),
// Summary = fixture.Create<string>(),
// RequesterId = userId,
// // var result = await _testContext
// // .CreateHttpClientWithAuthRole(UserRoleKey.Support)
// // .PostAsync("api/ticket", new NewTicket
// // {
// // AssigneeId = userId,
// // Description = fixture.Create<string>(),
// // Summary = fixture.Create<string>(),
// // RequesterId = userId,

// }
// .ToJsonBody())
// .DeserializeResponseAs<Ticket>();
}
// // }
// // .ToJsonBody())
// // .DeserializeResponseAs<Ticket>();
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,8 @@ private void RegisterDefaultEntityModels(IFixture fixture)
fixture.Register(() => new PracticeModeSettings
{
Id = fixture.Create<string>(),
CertificateHtmlTemplate = null,
DefaultPracticeSessionLengthMinutes = 60,
IntroTextMarkdown = null,
SuggestedSearches = ""
SuggestedSearches = string.Empty
});

fixture.Register<Data.Sponsor>(() => new()
Expand Down
Loading

0 comments on commit cbe2bd2

Please sign in to comment.