From 4aee847d5d4e3adeb56bed3098258f9e5044f496 Mon Sep 17 00:00:00 2001 From: Jenna Netland Date: Wed, 10 Oct 2018 11:50:27 -0700 Subject: [PATCH 1/7] Added add / remove member functionality for teams Also added temp function to generate a random user for testing Current bug: Teams can only have one player. Will address this in the next commit --- ServerCore/Pages/Teams/AddMember.cshtml | 55 ++++++++++++++ ServerCore/Pages/Teams/AddMember.cshtml.cs | 85 ++++++++++++++++++++++ ServerCore/Pages/Teams/Index.cshtml | 3 +- ServerCore/Pages/Teams/Members.cshtml | 54 ++++++++++++++ ServerCore/Pages/Teams/Members.cshtml.cs | 56 ++++++++++++++ 5 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 ServerCore/Pages/Teams/AddMember.cshtml create mode 100644 ServerCore/Pages/Teams/AddMember.cshtml.cs create mode 100644 ServerCore/Pages/Teams/Members.cshtml create mode 100644 ServerCore/Pages/Teams/Members.cshtml.cs diff --git a/ServerCore/Pages/Teams/AddMember.cshtml b/ServerCore/Pages/Teams/AddMember.cshtml new file mode 100644 index 00000000..62a420ee --- /dev/null +++ b/ServerCore/Pages/Teams/AddMember.cshtml @@ -0,0 +1,55 @@ +@page "/{eventId}/Teams/AddMember" +@model ServerCore.Pages.Teams.AddMemberModel + +@{ + ViewData["Title"] = "AddMember"; +} + +

Add a team member

+ +

Select a user to add to team "@Model.MyTeam.Name"

+ + + + + + + + + + + + @foreach (var item in Model.Users) + { + + + + + + + } + +
+ @Html.DisplayNameFor(model => model.Users[0].ID) + + @Html.DisplayNameFor(model => model.Users[0].Name) + + @Html.DisplayNameFor(model => model.Users[0].EmailAddress) +
+ @Html.DisplayFor(modelItem => item.ID) + + @Html.DisplayFor(modelItem => item.Name) + + @Html.DisplayFor(modelItem => item.EmailAddress) + + Add +
+ +
+ TEMPORARY - use this to add a random user so you can use this page. TODO: Remove once users have their own add page + TEMP add user +
+ +
+ Back to team member list +
\ No newline at end of file diff --git a/ServerCore/Pages/Teams/AddMember.cshtml.cs b/ServerCore/Pages/Teams/AddMember.cshtml.cs new file mode 100644 index 00000000..c6b55695 --- /dev/null +++ b/ServerCore/Pages/Teams/AddMember.cshtml.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.EntityFrameworkCore; +using ServerCore.DataModel; +using ServerCore.Models; +using ServerCore.ModelBases; + +namespace ServerCore.Pages.Teams +{ + public class AddMemberModel : EventSpecificPageModel + { + private readonly ServerCore.Models.PuzzleServerContext _context; + + public Team MyTeam { get; set; } + + public IList Users { get; set; } + + public AddMemberModel(ServerCore.Models.PuzzleServerContext context) + { + _context = context; + } + + public async Task OnGetAsync(int teamId) + { + MyTeam = await _context.Teams.FirstOrDefaultAsync(m => m.ID == teamId); + if (MyTeam == null) + { + return NotFound("Could not find team with ID '" + teamId + "'. Check to make sure you're accessing this page in the context of a team."); + } + + Users = await _context.Users.ToListAsync(); + return Page(); + } + + [BindProperty] + public TeamMembers Member { get; set; } + + public async Task OnGetAddMemberAsync(int teamId, int userId) + { + 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."); + } + Member.Team = team; + + User user = await _context.Users.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."); + } + Member.Member = user; + + _context.TeamMembers.Add(Member); + await _context.SaveChangesAsync(); + return RedirectToPage("./Members", new { id = teamId }); + + //SqlException: Cannot insert duplicate key row in object 'dbo.TeamMembers' with unique index 'IX_TeamMembers_Team.ID'. The duplicate key value is (2). + } + + // TEMPORARY - can't test member add without this function + // TODO - delete once users have an add page + public async Task OnGetAddUserAsync(int teamId) + { + User User = new User(); + User.Name = "MyName" + new Random().Next(1, 99); + User.EmployeeAlias = "null"; + User.EmailAddress = User.Name + "@domain.com"; + User.PhoneNumber = "null"; + User.TShirtSize = "null"; + User.VisibleToOthers = true; + _context.Users.Add(User); + + await _context.SaveChangesAsync(); + return RedirectToPage("./AddMember", new { teamId }); + } + } +} \ No newline at end of file diff --git a/ServerCore/Pages/Teams/Index.cshtml b/ServerCore/Pages/Teams/Index.cshtml index 18f09aaf..acc8ddc4 100644 --- a/ServerCore/Pages/Teams/Index.cshtml +++ b/ServerCore/Pages/Teams/Index.cshtml @@ -60,7 +60,8 @@ Details | Delete | Play | - Status + Status | + Members } diff --git a/ServerCore/Pages/Teams/Members.cshtml b/ServerCore/Pages/Teams/Members.cshtml new file mode 100644 index 00000000..373d5a22 --- /dev/null +++ b/ServerCore/Pages/Teams/Members.cshtml @@ -0,0 +1,54 @@ +@page "/{eventId}/Teams/Members" +@model ServerCore.Pages.Teams.MembersModel +@{ + ViewData["Title"] = "Members"; +} + +

Team Members

+ +

Team: @Model.Team.Name

+

ID: @Model.Team.ID

+ + + + + + + + + + + + @foreach (var item in Model.Members) + { + + + + + + + } + +
+ @Html.DisplayNameFor(model => model.Members[0].ID) + + @Html.DisplayNameFor(model => model.Members[0].Member.Name) + + @Html.DisplayNameFor(model => model.Members[0].Member.EmailAddress) +
+ @Html.DisplayFor(modelItem => item.ID) + + @Html.DisplayFor(modelItem => item.Member.Name) + + @Html.DisplayFor(modelItem => item.Member.EmailAddress) + + Remove +
+ + + + \ No newline at end of file diff --git a/ServerCore/Pages/Teams/Members.cshtml.cs b/ServerCore/Pages/Teams/Members.cshtml.cs new file mode 100644 index 00000000..150daf9c --- /dev/null +++ b/ServerCore/Pages/Teams/Members.cshtml.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using ServerCore.DataModel; +using ServerCore.ModelBases; + +namespace ServerCore.Pages.Teams +{ + public class MembersModel : EventSpecificPageModel + { + private readonly ServerCore.Models.PuzzleServerContext _context; + + public MembersModel(ServerCore.Models.PuzzleServerContext context) + { + _context = context; + } + + //[BindProperty] + public Team Team { get; set; } + + public IList Users { get; set; } + + public IList Members { get; set; } + + public async Task OnGetAsync(int id) + { + Team = await _context.Teams.FirstOrDefaultAsync(m => m.ID == id); + + if (Team == null) + { + return NotFound("Could not find team with ID '" + id + "'. Check to make sure you're accessing this page in the context of a team."); + } + + Members = await _context.TeamMembers.Where(members => members.Team == Team).ToListAsync(); + + Users = await _context.Users.ToListAsync(); + + return Page(); + } + + public async Task OnGetRemoveMemberAsync(int teamId, int teamMemberId) + { + TeamMembers member = await _context.TeamMembers.FirstOrDefaultAsync(m => m.ID == teamMemberId); + if (member == null) + { + return NotFound("Could not find team member with ID '" + teamMemberId + "'. They may have already been removed from the team."); + } + + _context.TeamMembers.Remove(member); + await _context.SaveChangesAsync(); + return RedirectToPage("./Members", new { id = teamId }); + } + } +} \ No newline at end of file From 625966dfe3028d5561cab5798c52ab90d3aaa198 Mon Sep 17 00:00:00 2001 From: Jenna Netland Date: Wed, 10 Oct 2018 19:52:08 -0700 Subject: [PATCH 2/7] Fixed bug where only one user could be added per team (removed TeamMembers singular reference from Team) --- Data/DataModel/Team.cs | 1 - ...4611_RemoveTeamMembersFromTeam.Designer.cs | 623 ++++++++++++++++++ ...0181011024611_RemoveTeamMembersFromTeam.cs | 33 + .../PuzzleServerContextModelSnapshot.cs | 12 +- 4 files changed, 662 insertions(+), 7 deletions(-) create mode 100644 Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs create mode 100644 Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.cs diff --git a/Data/DataModel/Team.cs b/Data/DataModel/Team.cs index 1a9ea72f..17764c63 100644 --- a/Data/DataModel/Team.cs +++ b/Data/DataModel/Team.cs @@ -22,7 +22,6 @@ public class Team /// String formatted rooms for events that don't pre-reserve rooms /// public string CustomRoom { get; set; } - public virtual TeamMembers Members { get; set; } public virtual List Invitations { get; set; } diff --git a/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs b/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs new file mode 100644 index 00000000..669490ff --- /dev/null +++ b/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs @@ -0,0 +1,623 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using ServerCore.Models; + +namespace Data.Migrations +{ + [DbContext(typeof(PuzzleServerContext))] + [Migration("20181011024611_RemoveTeamMembersFromTeam")] + partial class RemoveTeamMembersFromTeam + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.3-rtm-32065") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("ServerCore.DataModel.ContentFile", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("EventID"); + + b.Property("FileType"); + + b.Property("PuzzleID") + .IsRequired(); + + b.Property("ShortName") + .IsRequired(); + + b.Property("UrlString") + .IsRequired(); + + b.HasKey("ID"); + + b.HasIndex("PuzzleID"); + + b.HasIndex("EventID", "ShortName") + .IsUnique(); + + b.ToTable("ContentFiles"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Event", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("AdminsID"); + + b.Property("AllowFeedback"); + + b.Property("AnswerSubmissionEnd"); + + b.Property("AnswersAvailableBegin"); + + b.Property("ContactEmail"); + + b.Property("EventBegin"); + + b.Property("IsInternEvent"); + + b.Property("MaxExternalsPerTeam"); + + b.Property("MaxNumberOfTeams"); + + b.Property("MaxTeamSize"); + + b.Property("Name"); + + b.Property("ShowFastestSolves"); + + b.Property("StandingsAvailableBegin"); + + b.Property("StandingsOverride"); + + b.Property("TeamDeleteEnd"); + + b.Property("TeamMembershipChangeEnd"); + + b.Property("TeamMiscDataChangeEnd"); + + b.Property("TeamNameChangeEnd"); + + b.Property("TeamRegistrationBegin"); + + b.Property("TeamRegistrationEnd"); + + b.Property("UrlString"); + + b.HasKey("ID"); + + b.HasIndex("AdminsID"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventAdmins", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Event.ID"); + + b.Property("User.ID"); + + b.HasKey("ID"); + + b.HasIndex("Event.ID"); + + b.HasIndex("User.ID"); + + b.ToTable("EventAdmins"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventAuthors", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Event.ID"); + + b.Property("User.ID"); + + b.HasKey("ID"); + + b.HasIndex("Event.ID") + .IsUnique() + .HasFilter("[Event.ID] IS NOT NULL"); + + b.HasIndex("User.ID"); + + b.ToTable("EventAuthors"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventOwners", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Event.ID"); + + b.Property("User.ID"); + + b.HasKey("ID"); + + b.HasIndex("Event.ID"); + + b.HasIndex("User.ID"); + + b.ToTable("EventOwners"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventTeams", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Event.ID"); + + b.Property("Teams.ID"); + + b.HasKey("ID"); + + b.HasIndex("Event.ID") + .IsUnique() + .HasFilter("[Event.ID] IS NOT NULL"); + + b.HasIndex("Teams.ID"); + + b.ToTable("EventTeams"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Feedback", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Difficulty"); + + b.Property("Fun"); + + b.Property("PuzzleID"); + + b.Property("SubmissionTime"); + + b.Property("SubmitterID"); + + b.Property("WrittenFeedback"); + + b.HasKey("ID"); + + b.HasIndex("PuzzleID"); + + b.HasIndex("SubmitterID"); + + b.ToTable("Feedback"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Invitation", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("EmailAddress"); + + b.Property("Expiration"); + + b.Property("InvitationCode"); + + b.Property("InvitationType"); + + b.Property("TeamID"); + + b.HasKey("ID"); + + b.HasIndex("TeamID"); + + b.ToTable("Invitations"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Prerequisites", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("PrerequisiteID"); + + b.Property("PuzzleID"); + + b.HasKey("ID"); + + b.HasIndex("PrerequisiteID"); + + b.HasIndex("PuzzleID"); + + b.ToTable("Prerequisites"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Puzzle", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("EventID"); + + b.Property("Group"); + + b.Property("IsFinalPuzzle"); + + b.Property("IsGloballyVisiblePrerequisite"); + + b.Property("IsMetaPuzzle"); + + b.Property("IsPuzzle"); + + b.Property("MinPrerequisiteCount"); + + b.Property("Name"); + + b.Property("OrderInGroup"); + + b.Property("SolveValue"); + + b.Property("Token"); + + b.HasKey("ID"); + + b.HasIndex("EventID"); + + b.ToTable("Puzzles"); + }); + + modelBuilder.Entity("ServerCore.DataModel.PuzzleAuthors", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Puzzle.ID"); + + b.Property("User.ID"); + + b.HasKey("ID"); + + b.HasIndex("Puzzle.ID"); + + b.HasIndex("User.ID"); + + b.ToTable("PuzzleAuthors"); + }); + + modelBuilder.Entity("ServerCore.DataModel.PuzzleStatePerTeam", b => + { + b.Property("PuzzleID"); + + b.Property("TeamID"); + + b.Property("Notes"); + + b.Property("Printed"); + + b.Property("SolvedTime"); + + b.Property("UnlockedTime"); + + b.HasKey("PuzzleID", "TeamID"); + + b.HasIndex("TeamID"); + + b.ToTable("PuzzleStatePerTeam"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Response", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("IsSolution"); + + b.Property("Note"); + + b.Property("PuzzleID"); + + b.Property("SubmittedText"); + + b.HasKey("ID"); + + b.HasIndex("PuzzleID"); + + b.ToTable("Responses"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Submission", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("PuzzleID"); + + b.Property("ResponseID"); + + b.Property("SubmissionText"); + + b.Property("SubmitterID"); + + b.Property("TeamID"); + + b.Property("TimeSubmitted"); + + b.HasKey("ID"); + + b.HasIndex("PuzzleID"); + + b.HasIndex("ResponseID"); + + b.HasIndex("SubmitterID"); + + b.HasIndex("TeamID"); + + b.ToTable("Submissions"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Team", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CustomRoom"); + + b.Property("EventID"); + + b.Property("Name"); + + b.Property("PrimaryContactEmail"); + + b.Property("PrimaryPhoneNumber"); + + b.Property("RoomID"); + + b.Property("SecondaryPhoneNumber"); + + b.HasKey("ID"); + + b.HasIndex("EventID"); + + b.ToTable("Teams"); + }); + + modelBuilder.Entity("ServerCore.DataModel.TeamMembers", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Team.ID"); + + b.Property("User.ID"); + + b.HasKey("ID"); + + b.HasIndex("Team.ID"); + + b.HasIndex("User.ID"); + + b.ToTable("TeamMembers"); + }); + + modelBuilder.Entity("ServerCore.DataModel.User", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("EmailAddress"); + + b.Property("EmployeeAlias"); + + b.Property("Name"); + + b.Property("PhoneNumber"); + + b.Property("TShirtSize"); + + b.Property("VisibleToOthers"); + + b.HasKey("ID"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("ServerCore.DataModel.ContentFile", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithMany() + .HasForeignKey("EventID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany("Contents") + .HasForeignKey("PuzzleID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ServerCore.DataModel.Event", b => + { + b.HasOne("ServerCore.DataModel.EventAdmins", "Admins") + .WithMany() + .HasForeignKey("AdminsID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventAdmins", b => + { + b.HasOne("ServerCore.DataModel.EventOwners", "Event") + .WithMany() + .HasForeignKey("Event.ID"); + + b.HasOne("ServerCore.DataModel.User", "Admin") + .WithMany() + .HasForeignKey("User.ID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventAuthors", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithOne("Authors") + .HasForeignKey("ServerCore.DataModel.EventAuthors", "Event.ID"); + + b.HasOne("ServerCore.DataModel.User", "Author") + .WithMany() + .HasForeignKey("User.ID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventOwners", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithMany() + .HasForeignKey("Event.ID"); + + b.HasOne("ServerCore.DataModel.User", "Owner") + .WithMany() + .HasForeignKey("User.ID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventTeams", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithOne("Teams") + .HasForeignKey("ServerCore.DataModel.EventTeams", "Event.ID"); + + b.HasOne("ServerCore.DataModel.Team", "Team") + .WithMany() + .HasForeignKey("Teams.ID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Feedback", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("PuzzleID"); + + b.HasOne("ServerCore.DataModel.User", "Submitter") + .WithMany() + .HasForeignKey("SubmitterID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Invitation", b => + { + b.HasOne("ServerCore.DataModel.Team") + .WithMany("Invitations") + .HasForeignKey("TeamID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Prerequisites", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Prerequisite") + .WithMany() + .HasForeignKey("PrerequisiteID"); + + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("PuzzleID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Puzzle", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithMany() + .HasForeignKey("EventID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.PuzzleAuthors", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("Puzzle.ID"); + + b.HasOne("ServerCore.DataModel.User", "Author") + .WithMany() + .HasForeignKey("User.ID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.PuzzleStatePerTeam", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("PuzzleID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ServerCore.DataModel.Team", "Team") + .WithMany() + .HasForeignKey("TeamID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ServerCore.DataModel.Response", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("PuzzleID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Submission", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("PuzzleID"); + + b.HasOne("ServerCore.DataModel.Response", "Response") + .WithMany() + .HasForeignKey("ResponseID"); + + b.HasOne("ServerCore.DataModel.User", "Submitter") + .WithMany() + .HasForeignKey("SubmitterID"); + + b.HasOne("ServerCore.DataModel.Team", "Team") + .WithMany() + .HasForeignKey("TeamID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Team", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithMany() + .HasForeignKey("EventID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.TeamMembers", b => + { + b.HasOne("ServerCore.DataModel.Team", "Team") + .WithMany() + .HasForeignKey("Team.ID"); + + b.HasOne("ServerCore.DataModel.User", "Member") + .WithMany() + .HasForeignKey("User.ID"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.cs b/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.cs new file mode 100644 index 00000000..2a172322 --- /dev/null +++ b/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.cs @@ -0,0 +1,33 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Data.Migrations +{ + public partial class RemoveTeamMembersFromTeam : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_TeamMembers_Team.ID", + table: "TeamMembers"); + + migrationBuilder.CreateIndex( + name: "IX_TeamMembers_Team.ID", + table: "TeamMembers", + column: "Team.ID"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_TeamMembers_Team.ID", + table: "TeamMembers"); + + migrationBuilder.CreateIndex( + name: "IX_TeamMembers_Team.ID", + table: "TeamMembers", + column: "Team.ID", + unique: true, + filter: "[Team.ID] IS NOT NULL"); + } + } +} diff --git a/Data/Migrations/PuzzleServerContextModelSnapshot.cs b/Data/Migrations/PuzzleServerContextModelSnapshot.cs index 1b1dcec8..21965bd9 100644 --- a/Data/Migrations/PuzzleServerContextModelSnapshot.cs +++ b/Data/Migrations/PuzzleServerContextModelSnapshot.cs @@ -15,7 +15,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.1.1-rtm-30846") + .HasAnnotation("ProductVersion", "2.1.3-rtm-32065") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -62,6 +62,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("AnswersAvailableBegin"); + b.Property("ContactEmail"); + b.Property("EventBegin"); b.Property("IsInternEvent"); @@ -416,9 +418,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("ID"); - b.HasIndex("Team.ID") - .IsUnique() - .HasFilter("[Team.ID] IS NOT NULL"); + b.HasIndex("Team.ID"); b.HasIndex("User.ID"); @@ -608,8 +608,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("ServerCore.DataModel.TeamMembers", b => { b.HasOne("ServerCore.DataModel.Team", "Team") - .WithOne("Members") - .HasForeignKey("ServerCore.DataModel.TeamMembers", "Team.ID"); + .WithMany() + .HasForeignKey("Team.ID"); b.HasOne("ServerCore.DataModel.User", "Member") .WithMany() From f53fb2ef4f86389ad67d4016e011f3b656257702 Mon Sep 17 00:00:00 2001 From: Jenna Netland Date: Wed, 10 Oct 2018 20:40:50 -0700 Subject: [PATCH 3/7] Filtered available list of users to add to only users who are not already on a team for this event --- ServerCore/Pages/Teams/AddMember.cshtml.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ServerCore/Pages/Teams/AddMember.cshtml.cs b/ServerCore/Pages/Teams/AddMember.cshtml.cs index c6b55695..2d5c2ccf 100644 --- a/ServerCore/Pages/Teams/AddMember.cshtml.cs +++ b/ServerCore/Pages/Teams/AddMember.cshtml.cs @@ -33,7 +33,13 @@ public async Task OnGetAsync(int teamId) return NotFound("Could not find team with ID '" + teamId + "'. Check to make sure you're accessing this page in the context of a team."); } - Users = await _context.Users.ToListAsync(); + // Get all users that are not already on a team in this event + Users = await _context.Users + .Except(_context.TeamMembers + .Where(member => member.Team.Event == Event) + .Select(model => model.Member)) + .ToListAsync(); + return Page(); } @@ -61,12 +67,10 @@ public async Task OnGetAddMemberAsync(int teamId, int userId) _context.TeamMembers.Add(Member); await _context.SaveChangesAsync(); return RedirectToPage("./Members", new { id = teamId }); - - //SqlException: Cannot insert duplicate key row in object 'dbo.TeamMembers' with unique index 'IX_TeamMembers_Team.ID'. The duplicate key value is (2). } - // TEMPORARY - can't test member add without this function - // TODO - delete once users have an add page + // TEMPORARY - can't test member add without this function to add random users + // TODO (@Jenna) - delete once users have an add page public async Task OnGetAddUserAsync(int teamId) { User User = new User(); From e0ba29a6b187d0672a8fa4fd4ff74ed95a795875 Mon Sep 17 00:00:00 2001 From: Jenna Netland Date: Wed, 10 Oct 2018 11:50:27 -0700 Subject: [PATCH 4/7] Added add / remove member functionality for teams Also added temp function to generate a random user for testing Current bug: Teams can only have one player. Will address this in the next commit --- ServerCore/Pages/Teams/AddMember.cshtml | 55 ++++++++++++++ ServerCore/Pages/Teams/AddMember.cshtml.cs | 85 ++++++++++++++++++++++ ServerCore/Pages/Teams/Index.cshtml | 3 +- ServerCore/Pages/Teams/Members.cshtml | 54 ++++++++++++++ ServerCore/Pages/Teams/Members.cshtml.cs | 56 ++++++++++++++ 5 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 ServerCore/Pages/Teams/AddMember.cshtml create mode 100644 ServerCore/Pages/Teams/AddMember.cshtml.cs create mode 100644 ServerCore/Pages/Teams/Members.cshtml create mode 100644 ServerCore/Pages/Teams/Members.cshtml.cs diff --git a/ServerCore/Pages/Teams/AddMember.cshtml b/ServerCore/Pages/Teams/AddMember.cshtml new file mode 100644 index 00000000..62a420ee --- /dev/null +++ b/ServerCore/Pages/Teams/AddMember.cshtml @@ -0,0 +1,55 @@ +@page "/{eventId}/Teams/AddMember" +@model ServerCore.Pages.Teams.AddMemberModel + +@{ + ViewData["Title"] = "AddMember"; +} + +

Add a team member

+ +

Select a user to add to team "@Model.MyTeam.Name"

+ + + + + + + + + + + + @foreach (var item in Model.Users) + { + + + + + + + } + +
+ @Html.DisplayNameFor(model => model.Users[0].ID) + + @Html.DisplayNameFor(model => model.Users[0].Name) + + @Html.DisplayNameFor(model => model.Users[0].EmailAddress) +
+ @Html.DisplayFor(modelItem => item.ID) + + @Html.DisplayFor(modelItem => item.Name) + + @Html.DisplayFor(modelItem => item.EmailAddress) + + Add +
+ +
+ TEMPORARY - use this to add a random user so you can use this page. TODO: Remove once users have their own add page + TEMP add user +
+ + \ No newline at end of file diff --git a/ServerCore/Pages/Teams/AddMember.cshtml.cs b/ServerCore/Pages/Teams/AddMember.cshtml.cs new file mode 100644 index 00000000..c6b55695 --- /dev/null +++ b/ServerCore/Pages/Teams/AddMember.cshtml.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.EntityFrameworkCore; +using ServerCore.DataModel; +using ServerCore.Models; +using ServerCore.ModelBases; + +namespace ServerCore.Pages.Teams +{ + public class AddMemberModel : EventSpecificPageModel + { + private readonly ServerCore.Models.PuzzleServerContext _context; + + public Team MyTeam { get; set; } + + public IList Users { get; set; } + + public AddMemberModel(ServerCore.Models.PuzzleServerContext context) + { + _context = context; + } + + public async Task OnGetAsync(int teamId) + { + MyTeam = await _context.Teams.FirstOrDefaultAsync(m => m.ID == teamId); + if (MyTeam == null) + { + return NotFound("Could not find team with ID '" + teamId + "'. Check to make sure you're accessing this page in the context of a team."); + } + + Users = await _context.Users.ToListAsync(); + return Page(); + } + + [BindProperty] + public TeamMembers Member { get; set; } + + public async Task OnGetAddMemberAsync(int teamId, int userId) + { + 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."); + } + Member.Team = team; + + User user = await _context.Users.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."); + } + Member.Member = user; + + _context.TeamMembers.Add(Member); + await _context.SaveChangesAsync(); + return RedirectToPage("./Members", new { id = teamId }); + + //SqlException: Cannot insert duplicate key row in object 'dbo.TeamMembers' with unique index 'IX_TeamMembers_Team.ID'. The duplicate key value is (2). + } + + // TEMPORARY - can't test member add without this function + // TODO - delete once users have an add page + public async Task OnGetAddUserAsync(int teamId) + { + User User = new User(); + User.Name = "MyName" + new Random().Next(1, 99); + User.EmployeeAlias = "null"; + User.EmailAddress = User.Name + "@domain.com"; + User.PhoneNumber = "null"; + User.TShirtSize = "null"; + User.VisibleToOthers = true; + _context.Users.Add(User); + + await _context.SaveChangesAsync(); + return RedirectToPage("./AddMember", new { teamId }); + } + } +} \ No newline at end of file diff --git a/ServerCore/Pages/Teams/Index.cshtml b/ServerCore/Pages/Teams/Index.cshtml index 18f09aaf..acc8ddc4 100644 --- a/ServerCore/Pages/Teams/Index.cshtml +++ b/ServerCore/Pages/Teams/Index.cshtml @@ -60,7 +60,8 @@ Details | Delete | Play | - Status + Status | + Members } diff --git a/ServerCore/Pages/Teams/Members.cshtml b/ServerCore/Pages/Teams/Members.cshtml new file mode 100644 index 00000000..373d5a22 --- /dev/null +++ b/ServerCore/Pages/Teams/Members.cshtml @@ -0,0 +1,54 @@ +@page "/{eventId}/Teams/Members" +@model ServerCore.Pages.Teams.MembersModel +@{ + ViewData["Title"] = "Members"; +} + +

Team Members

+ +

Team: @Model.Team.Name

+

ID: @Model.Team.ID

+ + + + + + + + + + + + @foreach (var item in Model.Members) + { + + + + + + + } + +
+ @Html.DisplayNameFor(model => model.Members[0].ID) + + @Html.DisplayNameFor(model => model.Members[0].Member.Name) + + @Html.DisplayNameFor(model => model.Members[0].Member.EmailAddress) +
+ @Html.DisplayFor(modelItem => item.ID) + + @Html.DisplayFor(modelItem => item.Member.Name) + + @Html.DisplayFor(modelItem => item.Member.EmailAddress) + + Remove +
+ + + + \ No newline at end of file diff --git a/ServerCore/Pages/Teams/Members.cshtml.cs b/ServerCore/Pages/Teams/Members.cshtml.cs new file mode 100644 index 00000000..150daf9c --- /dev/null +++ b/ServerCore/Pages/Teams/Members.cshtml.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using ServerCore.DataModel; +using ServerCore.ModelBases; + +namespace ServerCore.Pages.Teams +{ + public class MembersModel : EventSpecificPageModel + { + private readonly ServerCore.Models.PuzzleServerContext _context; + + public MembersModel(ServerCore.Models.PuzzleServerContext context) + { + _context = context; + } + + //[BindProperty] + public Team Team { get; set; } + + public IList Users { get; set; } + + public IList Members { get; set; } + + public async Task OnGetAsync(int id) + { + Team = await _context.Teams.FirstOrDefaultAsync(m => m.ID == id); + + if (Team == null) + { + return NotFound("Could not find team with ID '" + id + "'. Check to make sure you're accessing this page in the context of a team."); + } + + Members = await _context.TeamMembers.Where(members => members.Team == Team).ToListAsync(); + + Users = await _context.Users.ToListAsync(); + + return Page(); + } + + public async Task OnGetRemoveMemberAsync(int teamId, int teamMemberId) + { + TeamMembers member = await _context.TeamMembers.FirstOrDefaultAsync(m => m.ID == teamMemberId); + if (member == null) + { + return NotFound("Could not find team member with ID '" + teamMemberId + "'. They may have already been removed from the team."); + } + + _context.TeamMembers.Remove(member); + await _context.SaveChangesAsync(); + return RedirectToPage("./Members", new { id = teamId }); + } + } +} \ No newline at end of file From 20b29e165b0928bffd7e9e54c306d37317c06ace Mon Sep 17 00:00:00 2001 From: Jenna Netland Date: Wed, 10 Oct 2018 19:52:08 -0700 Subject: [PATCH 5/7] Fixed bug where only one user could be added per team (removed TeamMembers singular reference from Team) --- Data/DataModel/Team.cs | 1 - ...4611_RemoveTeamMembersFromTeam.Designer.cs | 623 ++++++++++++++++++ ...0181011024611_RemoveTeamMembersFromTeam.cs | 33 + .../PuzzleServerContextModelSnapshot.cs | 12 +- 4 files changed, 662 insertions(+), 7 deletions(-) create mode 100644 Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs create mode 100644 Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.cs diff --git a/Data/DataModel/Team.cs b/Data/DataModel/Team.cs index 724c723f..d3b0510a 100644 --- a/Data/DataModel/Team.cs +++ b/Data/DataModel/Team.cs @@ -20,7 +20,6 @@ public class Team /// String formatted rooms for events that don't pre-reserve rooms /// public string CustomRoom { get; set; } - public virtual TeamMembers Members { get; set; } public virtual List Invitations { get; set; } diff --git a/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs b/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs new file mode 100644 index 00000000..669490ff --- /dev/null +++ b/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs @@ -0,0 +1,623 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using ServerCore.Models; + +namespace Data.Migrations +{ + [DbContext(typeof(PuzzleServerContext))] + [Migration("20181011024611_RemoveTeamMembersFromTeam")] + partial class RemoveTeamMembersFromTeam + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.3-rtm-32065") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("ServerCore.DataModel.ContentFile", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("EventID"); + + b.Property("FileType"); + + b.Property("PuzzleID") + .IsRequired(); + + b.Property("ShortName") + .IsRequired(); + + b.Property("UrlString") + .IsRequired(); + + b.HasKey("ID"); + + b.HasIndex("PuzzleID"); + + b.HasIndex("EventID", "ShortName") + .IsUnique(); + + b.ToTable("ContentFiles"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Event", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("AdminsID"); + + b.Property("AllowFeedback"); + + b.Property("AnswerSubmissionEnd"); + + b.Property("AnswersAvailableBegin"); + + b.Property("ContactEmail"); + + b.Property("EventBegin"); + + b.Property("IsInternEvent"); + + b.Property("MaxExternalsPerTeam"); + + b.Property("MaxNumberOfTeams"); + + b.Property("MaxTeamSize"); + + b.Property("Name"); + + b.Property("ShowFastestSolves"); + + b.Property("StandingsAvailableBegin"); + + b.Property("StandingsOverride"); + + b.Property("TeamDeleteEnd"); + + b.Property("TeamMembershipChangeEnd"); + + b.Property("TeamMiscDataChangeEnd"); + + b.Property("TeamNameChangeEnd"); + + b.Property("TeamRegistrationBegin"); + + b.Property("TeamRegistrationEnd"); + + b.Property("UrlString"); + + b.HasKey("ID"); + + b.HasIndex("AdminsID"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventAdmins", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Event.ID"); + + b.Property("User.ID"); + + b.HasKey("ID"); + + b.HasIndex("Event.ID"); + + b.HasIndex("User.ID"); + + b.ToTable("EventAdmins"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventAuthors", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Event.ID"); + + b.Property("User.ID"); + + b.HasKey("ID"); + + b.HasIndex("Event.ID") + .IsUnique() + .HasFilter("[Event.ID] IS NOT NULL"); + + b.HasIndex("User.ID"); + + b.ToTable("EventAuthors"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventOwners", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Event.ID"); + + b.Property("User.ID"); + + b.HasKey("ID"); + + b.HasIndex("Event.ID"); + + b.HasIndex("User.ID"); + + b.ToTable("EventOwners"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventTeams", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Event.ID"); + + b.Property("Teams.ID"); + + b.HasKey("ID"); + + b.HasIndex("Event.ID") + .IsUnique() + .HasFilter("[Event.ID] IS NOT NULL"); + + b.HasIndex("Teams.ID"); + + b.ToTable("EventTeams"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Feedback", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Difficulty"); + + b.Property("Fun"); + + b.Property("PuzzleID"); + + b.Property("SubmissionTime"); + + b.Property("SubmitterID"); + + b.Property("WrittenFeedback"); + + b.HasKey("ID"); + + b.HasIndex("PuzzleID"); + + b.HasIndex("SubmitterID"); + + b.ToTable("Feedback"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Invitation", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("EmailAddress"); + + b.Property("Expiration"); + + b.Property("InvitationCode"); + + b.Property("InvitationType"); + + b.Property("TeamID"); + + b.HasKey("ID"); + + b.HasIndex("TeamID"); + + b.ToTable("Invitations"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Prerequisites", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("PrerequisiteID"); + + b.Property("PuzzleID"); + + b.HasKey("ID"); + + b.HasIndex("PrerequisiteID"); + + b.HasIndex("PuzzleID"); + + b.ToTable("Prerequisites"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Puzzle", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("EventID"); + + b.Property("Group"); + + b.Property("IsFinalPuzzle"); + + b.Property("IsGloballyVisiblePrerequisite"); + + b.Property("IsMetaPuzzle"); + + b.Property("IsPuzzle"); + + b.Property("MinPrerequisiteCount"); + + b.Property("Name"); + + b.Property("OrderInGroup"); + + b.Property("SolveValue"); + + b.Property("Token"); + + b.HasKey("ID"); + + b.HasIndex("EventID"); + + b.ToTable("Puzzles"); + }); + + modelBuilder.Entity("ServerCore.DataModel.PuzzleAuthors", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Puzzle.ID"); + + b.Property("User.ID"); + + b.HasKey("ID"); + + b.HasIndex("Puzzle.ID"); + + b.HasIndex("User.ID"); + + b.ToTable("PuzzleAuthors"); + }); + + modelBuilder.Entity("ServerCore.DataModel.PuzzleStatePerTeam", b => + { + b.Property("PuzzleID"); + + b.Property("TeamID"); + + b.Property("Notes"); + + b.Property("Printed"); + + b.Property("SolvedTime"); + + b.Property("UnlockedTime"); + + b.HasKey("PuzzleID", "TeamID"); + + b.HasIndex("TeamID"); + + b.ToTable("PuzzleStatePerTeam"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Response", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("IsSolution"); + + b.Property("Note"); + + b.Property("PuzzleID"); + + b.Property("SubmittedText"); + + b.HasKey("ID"); + + b.HasIndex("PuzzleID"); + + b.ToTable("Responses"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Submission", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("PuzzleID"); + + b.Property("ResponseID"); + + b.Property("SubmissionText"); + + b.Property("SubmitterID"); + + b.Property("TeamID"); + + b.Property("TimeSubmitted"); + + b.HasKey("ID"); + + b.HasIndex("PuzzleID"); + + b.HasIndex("ResponseID"); + + b.HasIndex("SubmitterID"); + + b.HasIndex("TeamID"); + + b.ToTable("Submissions"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Team", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CustomRoom"); + + b.Property("EventID"); + + b.Property("Name"); + + b.Property("PrimaryContactEmail"); + + b.Property("PrimaryPhoneNumber"); + + b.Property("RoomID"); + + b.Property("SecondaryPhoneNumber"); + + b.HasKey("ID"); + + b.HasIndex("EventID"); + + b.ToTable("Teams"); + }); + + modelBuilder.Entity("ServerCore.DataModel.TeamMembers", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Team.ID"); + + b.Property("User.ID"); + + b.HasKey("ID"); + + b.HasIndex("Team.ID"); + + b.HasIndex("User.ID"); + + b.ToTable("TeamMembers"); + }); + + modelBuilder.Entity("ServerCore.DataModel.User", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("EmailAddress"); + + b.Property("EmployeeAlias"); + + b.Property("Name"); + + b.Property("PhoneNumber"); + + b.Property("TShirtSize"); + + b.Property("VisibleToOthers"); + + b.HasKey("ID"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("ServerCore.DataModel.ContentFile", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithMany() + .HasForeignKey("EventID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany("Contents") + .HasForeignKey("PuzzleID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ServerCore.DataModel.Event", b => + { + b.HasOne("ServerCore.DataModel.EventAdmins", "Admins") + .WithMany() + .HasForeignKey("AdminsID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventAdmins", b => + { + b.HasOne("ServerCore.DataModel.EventOwners", "Event") + .WithMany() + .HasForeignKey("Event.ID"); + + b.HasOne("ServerCore.DataModel.User", "Admin") + .WithMany() + .HasForeignKey("User.ID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventAuthors", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithOne("Authors") + .HasForeignKey("ServerCore.DataModel.EventAuthors", "Event.ID"); + + b.HasOne("ServerCore.DataModel.User", "Author") + .WithMany() + .HasForeignKey("User.ID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventOwners", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithMany() + .HasForeignKey("Event.ID"); + + b.HasOne("ServerCore.DataModel.User", "Owner") + .WithMany() + .HasForeignKey("User.ID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.EventTeams", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithOne("Teams") + .HasForeignKey("ServerCore.DataModel.EventTeams", "Event.ID"); + + b.HasOne("ServerCore.DataModel.Team", "Team") + .WithMany() + .HasForeignKey("Teams.ID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Feedback", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("PuzzleID"); + + b.HasOne("ServerCore.DataModel.User", "Submitter") + .WithMany() + .HasForeignKey("SubmitterID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Invitation", b => + { + b.HasOne("ServerCore.DataModel.Team") + .WithMany("Invitations") + .HasForeignKey("TeamID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Prerequisites", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Prerequisite") + .WithMany() + .HasForeignKey("PrerequisiteID"); + + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("PuzzleID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Puzzle", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithMany() + .HasForeignKey("EventID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.PuzzleAuthors", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("Puzzle.ID"); + + b.HasOne("ServerCore.DataModel.User", "Author") + .WithMany() + .HasForeignKey("User.ID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.PuzzleStatePerTeam", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("PuzzleID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("ServerCore.DataModel.Team", "Team") + .WithMany() + .HasForeignKey("TeamID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("ServerCore.DataModel.Response", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("PuzzleID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Submission", b => + { + b.HasOne("ServerCore.DataModel.Puzzle", "Puzzle") + .WithMany() + .HasForeignKey("PuzzleID"); + + b.HasOne("ServerCore.DataModel.Response", "Response") + .WithMany() + .HasForeignKey("ResponseID"); + + b.HasOne("ServerCore.DataModel.User", "Submitter") + .WithMany() + .HasForeignKey("SubmitterID"); + + b.HasOne("ServerCore.DataModel.Team", "Team") + .WithMany() + .HasForeignKey("TeamID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.Team", b => + { + b.HasOne("ServerCore.DataModel.Event", "Event") + .WithMany() + .HasForeignKey("EventID"); + }); + + modelBuilder.Entity("ServerCore.DataModel.TeamMembers", b => + { + b.HasOne("ServerCore.DataModel.Team", "Team") + .WithMany() + .HasForeignKey("Team.ID"); + + b.HasOne("ServerCore.DataModel.User", "Member") + .WithMany() + .HasForeignKey("User.ID"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.cs b/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.cs new file mode 100644 index 00000000..2a172322 --- /dev/null +++ b/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.cs @@ -0,0 +1,33 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Data.Migrations +{ + public partial class RemoveTeamMembersFromTeam : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_TeamMembers_Team.ID", + table: "TeamMembers"); + + migrationBuilder.CreateIndex( + name: "IX_TeamMembers_Team.ID", + table: "TeamMembers", + column: "Team.ID"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_TeamMembers_Team.ID", + table: "TeamMembers"); + + migrationBuilder.CreateIndex( + name: "IX_TeamMembers_Team.ID", + table: "TeamMembers", + column: "Team.ID", + unique: true, + filter: "[Team.ID] IS NOT NULL"); + } + } +} diff --git a/Data/Migrations/PuzzleServerContextModelSnapshot.cs b/Data/Migrations/PuzzleServerContextModelSnapshot.cs index d4cc270c..299b75b6 100644 --- a/Data/Migrations/PuzzleServerContextModelSnapshot.cs +++ b/Data/Migrations/PuzzleServerContextModelSnapshot.cs @@ -15,7 +15,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.1.1-rtm-30846") + .HasAnnotation("ProductVersion", "2.1.3-rtm-32065") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -62,6 +62,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("AnswersAvailableBegin"); + b.Property("ContactEmail"); + b.Property("EventBegin"); b.Property("IsInternEvent"); @@ -416,9 +418,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("ID"); - b.HasIndex("Team.ID") - .IsUnique() - .HasFilter("[Team.ID] IS NOT NULL"); + b.HasIndex("Team.ID"); b.HasIndex("User.ID"); @@ -608,8 +608,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("ServerCore.DataModel.TeamMembers", b => { b.HasOne("ServerCore.DataModel.Team", "Team") - .WithOne("Members") - .HasForeignKey("ServerCore.DataModel.TeamMembers", "Team.ID"); + .WithMany() + .HasForeignKey("Team.ID"); b.HasOne("ServerCore.DataModel.User", "Member") .WithMany() From 285cfbda8cdc96714307db62eacc6eb9dc7170e6 Mon Sep 17 00:00:00 2001 From: Jenna Netland Date: Wed, 10 Oct 2018 20:40:50 -0700 Subject: [PATCH 6/7] Filtered available list of users to add to only users who are not already on a team for this event --- ServerCore/Pages/Teams/AddMember.cshtml.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ServerCore/Pages/Teams/AddMember.cshtml.cs b/ServerCore/Pages/Teams/AddMember.cshtml.cs index c6b55695..2d5c2ccf 100644 --- a/ServerCore/Pages/Teams/AddMember.cshtml.cs +++ b/ServerCore/Pages/Teams/AddMember.cshtml.cs @@ -33,7 +33,13 @@ public async Task OnGetAsync(int teamId) return NotFound("Could not find team with ID '" + teamId + "'. Check to make sure you're accessing this page in the context of a team."); } - Users = await _context.Users.ToListAsync(); + // Get all users that are not already on a team in this event + Users = await _context.Users + .Except(_context.TeamMembers + .Where(member => member.Team.Event == Event) + .Select(model => model.Member)) + .ToListAsync(); + return Page(); } @@ -61,12 +67,10 @@ public async Task OnGetAddMemberAsync(int teamId, int userId) _context.TeamMembers.Add(Member); await _context.SaveChangesAsync(); return RedirectToPage("./Members", new { id = teamId }); - - //SqlException: Cannot insert duplicate key row in object 'dbo.TeamMembers' with unique index 'IX_TeamMembers_Team.ID'. The duplicate key value is (2). } - // TEMPORARY - can't test member add without this function - // TODO - delete once users have an add page + // TEMPORARY - can't test member add without this function to add random users + // TODO (@Jenna) - delete once users have an add page public async Task OnGetAddUserAsync(int teamId) { User User = new User(); From 67056f5495a8429eae64d80c0f7f56857d8a0ba5 Mon Sep 17 00:00:00 2001 From: Jenna Netland Date: Wed, 10 Oct 2018 21:02:12 -0700 Subject: [PATCH 7/7] Un-breaking build (changing ServerCore.Models to ServerCore.DataModels) --- .../20181011024611_RemoveTeamMembersFromTeam.Designer.cs | 2 +- ServerCore/Pages/Teams/AddMember.cshtml.cs | 5 ++--- ServerCore/Pages/Teams/Members.cshtml.cs | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs b/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs index 669490ff..c7d89bfe 100644 --- a/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs +++ b/Data/Migrations/20181011024611_RemoveTeamMembersFromTeam.Designer.cs @@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ServerCore.Models; +using ServerCore.DataModel; namespace Data.Migrations { diff --git a/ServerCore/Pages/Teams/AddMember.cshtml.cs b/ServerCore/Pages/Teams/AddMember.cshtml.cs index 2d5c2ccf..abb7a7f9 100644 --- a/ServerCore/Pages/Teams/AddMember.cshtml.cs +++ b/ServerCore/Pages/Teams/AddMember.cshtml.cs @@ -7,20 +7,19 @@ using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.EntityFrameworkCore; using ServerCore.DataModel; -using ServerCore.Models; using ServerCore.ModelBases; namespace ServerCore.Pages.Teams { public class AddMemberModel : EventSpecificPageModel { - private readonly ServerCore.Models.PuzzleServerContext _context; + private readonly ServerCore.DataModel.PuzzleServerContext _context; public Team MyTeam { get; set; } public IList Users { get; set; } - public AddMemberModel(ServerCore.Models.PuzzleServerContext context) + public AddMemberModel(ServerCore.DataModel.PuzzleServerContext context) { _context = context; } diff --git a/ServerCore/Pages/Teams/Members.cshtml.cs b/ServerCore/Pages/Teams/Members.cshtml.cs index 150daf9c..e7c43e98 100644 --- a/ServerCore/Pages/Teams/Members.cshtml.cs +++ b/ServerCore/Pages/Teams/Members.cshtml.cs @@ -10,9 +10,9 @@ namespace ServerCore.Pages.Teams { public class MembersModel : EventSpecificPageModel { - private readonly ServerCore.Models.PuzzleServerContext _context; + private readonly ServerCore.DataModel.PuzzleServerContext _context; - public MembersModel(ServerCore.Models.PuzzleServerContext context) + public MembersModel(ServerCore.DataModel.PuzzleServerContext context) { _context = context; }