diff --git a/ServerCore/Pages/Events/Create.cshtml.cs b/ServerCore/Pages/Events/Create.cshtml.cs index 0683fc77..cbdd5a50 100644 --- a/ServerCore/Pages/Events/Create.cshtml.cs +++ b/ServerCore/Pages/Events/Create.cshtml.cs @@ -41,6 +41,9 @@ public IActionResult OnGet() Event.LockoutIncorrectGuessPeriod = 1; Event.LockoutDurationMultiplier = 2; Event.MaxSubmissionCount = 50; + Event.MaxNumberOfTeams = 120; + Event.MaxExternalsPerTeam = 9; + Event.MaxTeamSize = 12; return Page(); } diff --git a/ServerCore/Pages/Events/CreateDemo.cshtml.cs b/ServerCore/Pages/Events/CreateDemo.cshtml.cs index c4e346c0..00c940ff 100644 --- a/ServerCore/Pages/Events/CreateDemo.cshtml.cs +++ b/ServerCore/Pages/Events/CreateDemo.cshtml.cs @@ -72,6 +72,9 @@ public async Task OnPostAsync() Event.LockoutIncorrectGuessPeriod = 1; Event.LockoutDurationMultiplier = 2; Event.MaxSubmissionCount = 50; + Event.MaxNumberOfTeams = 120; + Event.MaxExternalsPerTeam = 9; + Event.MaxTeamSize = 12; _context.Events.Add(Event); await _context.SaveChangesAsync(); diff --git a/ServerCore/Pages/Teams/AddMember.cshtml.cs b/ServerCore/Pages/Teams/AddMember.cshtml.cs index 8d0cadd2..bc724858 100644 --- a/ServerCore/Pages/Teams/AddMember.cshtml.cs +++ b/ServerCore/Pages/Teams/AddMember.cshtml.cs @@ -76,30 +76,41 @@ public async Task OnGetAddMemberAsync(int teamId, int userId, int return NotFound("Team membership change is not currently active."); } - TeamMembers Member = new TeamMembers(); - Team team = await _context.Teams.FirstOrDefaultAsync(m => m.ID == teamId); if (team == null) { - return NotFound("Could not find team with ID '" + teamId + "'. Check to make sure the team hasn't been removed."); + return NotFound($"Could not find team with ID '{teamId}'. Check to make sure the team hasn't been removed."); + } + + var currentTeamMembers = await _context.TeamMembers.Where(members => members.Team.ID == team.ID).ToListAsync(); + if (currentTeamMembers.Count >= Event.MaxTeamSize && EventRole != EventRole.admin) + { + return NotFound($"The team '{team.Name}' is full."); } - Member.Team = team; PuzzleUser user = await _context.PuzzleUsers.FirstOrDefaultAsync(m => m.ID == userId); if (user == null) { - return NotFound("Could not find user with ID '" + userId + "'. Check to make sure the user hasn't been removed."); + return NotFound($"Could not find user with ID '{userId}'. Check to make sure the user hasn't been removed."); + } + + if (user.EmployeeAlias == null && currentTeamMembers.Where((m) => m.Member.EmployeeAlias == null).Count() >= Event.MaxExternalsPerTeam) + { + return NotFound($"The team '{team.Name}' is already at its maximum count of non-employee players, and '{user.Email}' has no registered alias."); } - Member.Member = user; if (await (from teamMember in _context.TeamMembers where teamMember.Member == user && teamMember.Team.Event == Event select teamMember).AnyAsync()) { - return NotFound("User is already on a team in this event."); + return NotFound($"'{user.Email}' is already on a team in this event."); } + TeamMembers Member = new TeamMembers(); + Member.Team = team; + Member.Member = user; + if (applicationId != -1) { TeamApplication application = await (from app in _context.TeamApplications diff --git a/ServerCore/Pages/Teams/Create.cshtml.cs b/ServerCore/Pages/Teams/Create.cshtml.cs index b6bacee3..ce6f599e 100644 --- a/ServerCore/Pages/Teams/Create.cshtml.cs +++ b/ServerCore/Pages/Teams/Create.cshtml.cs @@ -78,6 +78,11 @@ public async Task OnPostAsync() using (IDbContextTransaction transaction = _context.Database.BeginTransaction(System.Data.IsolationLevel.Serializable)) { + if (await _context.Teams.Where((t) => t.Event == Event).CountAsync() >= Event.MaxNumberOfTeams) + { + return NotFound("Registration is full. No further teams may be created at the present time."); + } + _context.Teams.Add(Team); if (EventRole == EventRole.play) diff --git a/ServerCore/Pages/Teams/Index.cshtml b/ServerCore/Pages/Teams/Index.cshtml index 45c97df0..a5d9ae61 100644 --- a/ServerCore/Pages/Teams/Index.cshtml +++ b/ServerCore/Pages/Teams/Index.cshtml @@ -11,77 +11,90 @@

All Teams

- @if (Model.Event.IsTeamRegistrationActive && Model.EventRole == ModelBases.EventRole.admin) + @if (Model.EventRole == ModelBases.EventRole.admin) { + if (!Model.Event.IsTeamRegistrationActive) + { +

+ } + else if (Model.Event.MaxNumberOfTeams <= Model.Teams.Count) + { + + } + Create New } - else - { - - }

+

Registered Teams: @Model.Teams.Count/@Model.Event.MaxNumberOfTeams, Registered Players: @Model.PlayerCount/@(Model.Event.MaxNumberOfTeams * Model.Event.MaxTeamSize)

+ -@foreach (var item in Model.Teams) { - - - - - - - - - - -} + @foreach (var item in Model.Teams) + { + + + + + + + + + + + + }
- @Html.DisplayNameFor(model => model.Teams[0].Name) + @Html.DisplayNameFor(model => model.Teams.FirstOrDefault().Key.Name) + + Size - @Html.DisplayNameFor(model => model.Teams[0].RoomID) + @Html.DisplayNameFor(model => model.Teams.FirstOrDefault().Key.RoomID) - @Html.DisplayNameFor(model => model.Teams[0].CustomRoom) + @Html.DisplayNameFor(model => model.Teams.FirstOrDefault().Key.CustomRoom) - @Html.DisplayNameFor(model => model.Teams[0].PrimaryContactEmail) + @Html.DisplayNameFor(model => model.Teams.FirstOrDefault().Key.PrimaryContactEmail) - @Html.DisplayNameFor(model => model.Teams[0].PrimaryPhoneNumber) + @Html.DisplayNameFor(model => model.Teams.FirstOrDefault().Key.PrimaryPhoneNumber) - @Html.DisplayNameFor(model => model.Teams[0].SecondaryPhoneNumber) + @Html.DisplayNameFor(model => model.Teams.FirstOrDefault().Key.SecondaryPhoneNumber)
- @Html.DisplayFor(modelItem => item.Name) - - @Html.DisplayFor(modelItem => item.RoomID) - - @Html.DisplayFor(modelItem => item.CustomRoom) - - @Html.DisplayFor(modelItem => item.PrimaryContactEmail) - - @Html.DisplayFor(modelItem => item.PrimaryPhoneNumber) - - @Html.DisplayFor(modelItem => item.SecondaryPhoneNumber) - - - - Status - @if (Model.EventRole == ModelBases.EventRole.admin) - { -
- | - View | - Members -
- } -
+ @Html.DisplayFor(modelItem => item.Key.Name) + + @Html.DisplayFor(modelItem => item.Value) + + @Html.DisplayFor(modelItem => item.Key.RoomID) + + @Html.DisplayFor(modelItem => item.Key.CustomRoom) + + @Html.DisplayFor(modelItem => item.Key.PrimaryContactEmail) + + @Html.DisplayFor(modelItem => item.Key.PrimaryPhoneNumber) + + @Html.DisplayFor(modelItem => item.Key.SecondaryPhoneNumber) + + Status + @if (Model.EventRole == ModelBases.EventRole.admin) + { +
+ | + View | + Members +
+ } +
diff --git a/ServerCore/Pages/Teams/Index.cshtml.cs b/ServerCore/Pages/Teams/Index.cshtml.cs index 446e4fb3..e6bd7f07 100644 --- a/ServerCore/Pages/Teams/Index.cshtml.cs +++ b/ServerCore/Pages/Teams/Index.cshtml.cs @@ -1,27 +1,21 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using ServerCore.DataModel; -using ServerCore.ModelBases; namespace ServerCore.Pages.Teams { [Authorize(Policy = "IsEventAdminOrEventAuthor")] - public class IndexModel : EventSpecificPageModel + public class IndexModel : TeamListBase { public IndexModel(PuzzleServerContext serverContext, UserManager userManager) : base(serverContext, userManager) { } - public IList Teams { get;set; } - public async Task OnGetAsync() { - Teams = await _context.Teams.Where(team => team.Event == Event).ToListAsync(); + await LoadTeamDataAsync(); return Page(); } } diff --git a/ServerCore/Pages/Teams/List.cshtml b/ServerCore/Pages/Teams/List.cshtml index d331d512..e7c837cd 100644 --- a/ServerCore/Pages/Teams/List.cshtml +++ b/ServerCore/Pages/Teams/List.cshtml @@ -9,22 +9,30 @@ }

- @if (Model.Event.IsTeamRegistrationActive) + @if (!Model.Event.IsTeamRegistrationActive) { -

Register for @Model.Event.Name

+

Registration closed

- You are not yet part of a team for this event. Create a new team or request to join one below! + You are not part of a team for this event, and unfortuantely we're no longer accepting new teams into the event. :(
- Create a new team } - else + else if (Model.Event.MaxNumberOfTeams <= Model.Teams.Count) { -

Registration closed

+

Registration full

You are not part of a team for this event, and unfortuantely we're no longer accepting new teams into the event. :(
} + else + { +

Register for @Model.Event.Name

+
+ You are not yet part of a team for this event. Create a new team or request to join one below! +
+ Create a new team + }

+

Registered Teams: @Model.Teams.Count/@Model.Event.MaxNumberOfTeams, Registered Players: @Model.PlayerCount/@(Model.Event.MaxNumberOfTeams * Model.Event.MaxTeamSize)

@if (Model.Event.IsTeamRegistrationActive) { diff --git a/ServerCore/Pages/Teams/List.cshtml.cs b/ServerCore/Pages/Teams/List.cshtml.cs index 432846e9..0464fefa 100644 --- a/ServerCore/Pages/Teams/List.cshtml.cs +++ b/ServerCore/Pages/Teams/List.cshtml.cs @@ -1,14 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.EntityFrameworkCore; using ServerCore.DataModel; -using ServerCore.ModelBases; namespace ServerCore.Pages.Teams { @@ -16,17 +10,12 @@ namespace ServerCore.Pages.Teams /// Player-facing list of all teams /// [AllowAnonymous] - public class ListModel : EventSpecificPageModel + public class ListModel : TeamListBase { public ListModel(PuzzleServerContext serverContext, UserManager userManager) : base(serverContext, userManager) { } - /// - /// All teams - /// - public Dictionary Teams { get;set; } - /// /// True if the current user is on a team /// @@ -48,24 +37,7 @@ public async Task OnGetAsync() UserOnTeam = false; } - //Teams = await _context.Teams.ToListAsync(); - List allTeams = await (from team in _context.Teams - where team.Event == Event - select team).ToListAsync(); - - Teams = await (from team in _context.Teams - where team.Event == Event - join teamMember in _context.TeamMembers on team equals teamMember.Team - group teamMember by teamMember.Team into teamCounts - select new { Team = teamCounts.Key, Count = teamCounts.Count() }).ToDictionaryAsync(x => x.Team, x => x.Count); - - foreach (Team team in allTeams) - { - if (!Teams.ContainsKey(team)) - { - Teams[team] = 0; - } - } + await LoadTeamDataAsync(); return Page(); } diff --git a/ServerCore/Pages/Teams/Members.cshtml b/ServerCore/Pages/Teams/Members.cshtml index f27237c3..bbb8e5db 100644 --- a/ServerCore/Pages/Teams/Members.cshtml +++ b/ServerCore/Pages/Teams/Members.cshtml @@ -8,20 +8,32 @@ Layout = "_teamLayout.cshtml"; } -

@Html.DisplayFor(model => model.Team.Name): Members

+

@Html.DisplayFor(model => model.Team.Name): @(Model.Members.Count) Members

- @if (Model.Event.IsTeamMembershipChangeActive || Model.EventRole == ModelBases.EventRole.admin) + @{ bool canAdd = Model.EventRole == ModelBases.EventRole.admin; } + + @if (!Model.Event.IsTeamMembershipChangeActive) { -

- Add a member + - } - else + else if (Model.Members.Count >= Model.Event.MaxTeamSize) { + } + else + { + canAdd = true; + } + + @if (canAdd) + { + }

@@ -35,6 +47,9 @@
+ @@ -48,6 +63,9 @@ + @if (Model.EventRole == ModelBases.EventRole.play && Model.Members.Count == 1) { diff --git a/ServerCore/Pages/Teams/TeamListBase.cs b/ServerCore/Pages/Teams/TeamListBase.cs new file mode 100644 index 00000000..69f57080 --- /dev/null +++ b/ServerCore/Pages/Teams/TeamListBase.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using ServerCore.DataModel; +using ServerCore.ModelBases; + +namespace ServerCore.Pages.Teams +{ + public class TeamListBase : EventSpecificPageModel + { + public TeamListBase(PuzzleServerContext serverContext, UserManager userManager) : base(serverContext, userManager) + { + } + + /// + /// All teams + /// + public Dictionary Teams { get; set; } + + public int PlayerCount { get; set; } + + protected async Task LoadTeamDataAsync() + { + List allTeams = await (from team in _context.Teams + where team.Event == Event + select team).ToListAsync(); + + Teams = await (from team in _context.Teams + where team.Event == Event + join teamMember in _context.TeamMembers on team equals teamMember.Team + group teamMember by teamMember.Team into teamCounts + select new { Team = teamCounts.Key, Count = teamCounts.Count() }).ToDictionaryAsync(x => x.Team, x => x.Count); + + foreach (Team team in allTeams) + { + if (!Teams.ContainsKey(team)) + { + Teams[team] = 0; + } + else + { + PlayerCount += Teams[team]; + } + } + } + } +}
@Html.DisplayNameFor(model => model.Members[0].Member.Email) + @Html.DisplayNameFor(model => model.Members[0].Member.EmployeeAlias) + Remove
@Html.DisplayFor(modelItem => item.Member.Email) + @Html.DisplayFor(modelItem => item.Member.EmployeeAlias) +