Restrict results-close rollback to players with suggestions
This commit is contained in:
@@ -21,7 +21,12 @@ internal sealed class AdminWorkflowService(AppDbContext db)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await db.Players.ExecuteUpdateAsync(p => p.SetProperty(x => x.CurrentPhase, Phase.Vote).SetProperty(x => x.VotesFinal, false));
|
await db.Players
|
||||||
|
.Where(p => p.Suggestions.Any())
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(x => x.CurrentPhase, Phase.Vote).SetProperty(x => x.VotesFinal, false));
|
||||||
|
await db.Players
|
||||||
|
.Where(p => !p.Suggestions.Any())
|
||||||
|
.ExecuteUpdateAsync(p => p.SetProperty(x => x.CurrentPhase, Phase.Suggest).SetProperty(x => x.VotesFinal, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ public class AdminTests
|
|||||||
await admin.RegisterAsync("admin", admin: true);
|
await admin.RegisterAsync("admin", admin: true);
|
||||||
var player = factory.CreateClientWithCookies();
|
var player = factory.CreateClientWithCookies();
|
||||||
await player.RegisterAsync("player");
|
await player.RegisterAsync("player");
|
||||||
|
await player.CreateSuggestionAsync("Player game");
|
||||||
|
|
||||||
var open = await admin.PostAsJsonAsync("/api/admin/results", new { resultsOpen = true });
|
var open = await admin.PostAsJsonAsync("/api/admin/results", new { resultsOpen = true });
|
||||||
open.EnsureSuccessStatusCode();
|
open.EnsureSuccessStatusCode();
|
||||||
@@ -263,6 +264,37 @@ public class AdminTests
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Admin_results_closing_sends_players_without_suggestions_to_suggest_phase()
|
||||||
|
{
|
||||||
|
await using var factory = new TestWebApplicationFactory();
|
||||||
|
var admin = factory.CreateClientWithCookies();
|
||||||
|
await admin.RegisterAsync("admin", admin: true);
|
||||||
|
|
||||||
|
var voter = factory.CreateClientWithCookies();
|
||||||
|
await voter.RegisterAsync("voter");
|
||||||
|
await voter.CreateSuggestionAsync("Voter game");
|
||||||
|
|
||||||
|
var open = await admin.PostAsJsonAsync("/api/admin/results", new { resultsOpen = true });
|
||||||
|
open.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var lateJoiner = factory.CreateClientWithCookies();
|
||||||
|
await lateJoiner.RegisterAsync("late");
|
||||||
|
|
||||||
|
var close = await admin.PostAsJsonAsync("/api/admin/results", new { resultsOpen = false });
|
||||||
|
close.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
await factory.WithDbContextAsync(async db =>
|
||||||
|
{
|
||||||
|
var voterPlayer = await db.Players.SingleAsync(p => p.Username == "voter");
|
||||||
|
var latePlayer = await db.Players.SingleAsync(p => p.Username == "late");
|
||||||
|
Assert.Equal(Phase.Vote, voterPlayer.CurrentPhase);
|
||||||
|
Assert.Equal(Phase.Suggest, latePlayer.CurrentPhase);
|
||||||
|
Assert.False(voterPlayer.VotesFinal);
|
||||||
|
Assert.False(latePlayer.VotesFinal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Vote_status_lists_waiting_players()
|
public async Task Vote_status_lists_waiting_players()
|
||||||
{
|
{
|
||||||
|
|||||||
1
SPEC.md
1
SPEC.md
@@ -30,6 +30,7 @@ Help a small Discord group (4–8 players) pick a co-op game via phased flow:
|
|||||||
## Results Phase
|
## Results Phase
|
||||||
- Visible only after admin enables results; players auto-advance when opened
|
- Visible only after admin enables results; players auto-advance when opened
|
||||||
- Leaderboard sorted by average score; shows totals, counts, player’s own vote, and links/media
|
- Leaderboard sorted by average score; shows totals, counts, player’s own vote, and links/media
|
||||||
|
- When results are closed again, only accounts with at least one suggestion return to Vote; accounts without suggestions return to Suggest
|
||||||
|
|
||||||
## Non-functional
|
## Non-functional
|
||||||
- Desktop + mobile friendly
|
- Desktop + mobile friendly
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ Admins können bei Bedarf zusätzliche Joker vergeben.
|
|||||||
|
|
||||||
### Wann sind die Ergebnisse sichtbar?
|
### Wann sind die Ergebnisse sichtbar?
|
||||||
|
|
||||||
Die Ergebnisse bleiben verborgen, bis ein Admin sie freigibt. Danach werden alle Spieler automatisch in die **Ergebnisphase** verschoben. Falls nötig, kann ein Admin die Ergebnisse wieder schließen: Alle kehren in die Abstimmungsphase zurück und alle Abstimmungen werden zur Anpassung zurückgesetzt.
|
Die Ergebnisse bleiben verborgen, bis ein Admin sie freigibt. Danach werden alle Spieler automatisch in die **Ergebnisphase** verschoben. Falls nötig, kann ein Admin die Ergebnisse wieder schließen: Konten mit mindestens einem eigenen Vorschlag kehren in die Abstimmungsphase zurück, Konten ohne Vorschläge in die Vorschlagsphase, und alle Abstimmungen werden zur Anpassung zurückgesetzt.
|
||||||
|
|
||||||
### Kann ich in der Ergebnisphase etwas bearbeiten?
|
### Kann ich in der Ergebnisphase etwas bearbeiten?
|
||||||
|
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ Review your list and rescore before finalizing again.
|
|||||||
### When are results visible?
|
### When are results visible?
|
||||||
|
|
||||||
Results are hidden until an admin opens them. When opened, all players are automatically moved to the **Results phase**.
|
Results are hidden until an admin opens them. When opened, all players are automatically moved to the **Results phase**.
|
||||||
If needed, an admin can close the Results: everyone returns to the Vote phase, and all ballots are unfinalized for adjustments.
|
If needed, an admin can close the Results: players with at least one own suggestion return to the Vote phase, accounts without suggestions return to Suggest, and all ballots are unfinalized for adjustments.
|
||||||
|
|
||||||
### Can I edit anything in Results?
|
### Can I edit anything in Results?
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user