diff --git a/CodingEventsDemo/CodingEventsDemo.csproj b/CodingEventsDemo/CodingEventsDemo.csproj index f637a388..94a90a29 100644 --- a/CodingEventsDemo/CodingEventsDemo.csproj +++ b/CodingEventsDemo/CodingEventsDemo.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + net6.0 True @@ -12,17 +12,18 @@ + - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - + + + + - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/CodingEventsDemo/CodingEventsDemo.sln b/CodingEventsDemo/CodingEventsDemo.sln new file mode 100644 index 00000000..2acb6130 --- /dev/null +++ b/CodingEventsDemo/CodingEventsDemo.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 25.0.1703.6 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodingEventsDemo", "CodingEventsDemo.csproj", "{33BFA655-C28C-4D2C-AD92-7D9E1D909008}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {33BFA655-C28C-4D2C-AD92-7D9E1D909008}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33BFA655-C28C-4D2C-AD92-7D9E1D909008}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33BFA655-C28C-4D2C-AD92-7D9E1D909008}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33BFA655-C28C-4D2C-AD92-7D9E1D909008}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4099042F-0400-4C61-BBA5-6463A59889B8} + EndGlobalSection +EndGlobal diff --git a/CodingEventsDemo/Controllers/EventCategoryController.cs b/CodingEventsDemo/Controllers/EventCategoryController.cs index 4ee1e946..924ee974 100644 --- a/CodingEventsDemo/Controllers/EventCategoryController.cs +++ b/CodingEventsDemo/Controllers/EventCategoryController.cs @@ -4,8 +4,8 @@ using System.Threading.Tasks; using CodingEventsDemo.Data; using CodingEventsDemo.Models; -using Microsoft.AspNetCore.Mvc; using CodingEventsDemo.ViewModels; +using Microsoft.AspNetCore.Mvc; // For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 diff --git a/CodingEventsDemo/Controllers/EventsController.cs b/CodingEventsDemo/Controllers/EventsController.cs index 3fd6eb14..6e34e3bd 100644 --- a/CodingEventsDemo/Controllers/EventsController.cs +++ b/CodingEventsDemo/Controllers/EventsController.cs @@ -6,6 +6,7 @@ using CodingEventsDemo.Models; using CodingEventsDemo.ViewModels; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; // For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 @@ -13,7 +14,6 @@ namespace coding_events_practice.Controllers { public class EventsController : Controller { - private EventDbContext context; public EventsController(EventDbContext dbContext) @@ -24,14 +24,17 @@ public EventsController(EventDbContext dbContext) // GET: // public IActionResult Index() { - List events = context.Events.ToList(); + List events = context.Events + .Include(e => e.Category) + .ToList(); return View(events); } public IActionResult Add() { - AddEventViewModel addEventViewModel = new AddEventViewModel(); + List categories = context.Categories.ToList(); + AddEventViewModel addEventViewModel = new AddEventViewModel(categories); return View(addEventViewModel); } @@ -41,12 +44,13 @@ public IActionResult Add(AddEventViewModel addEventViewModel) { if (ModelState.IsValid) { + EventCategory category = context.Categories.Find(addEventViewModel.CategoryId); Event newEvent = new Event { Name = addEventViewModel.Name, Description = addEventViewModel.Description, ContactEmail = addEventViewModel.ContactEmail, - Type = addEventViewModel.Type + Category = category }; context.Events.Add(newEvent); @@ -78,5 +82,16 @@ public IActionResult Delete(int[] eventIds) return Redirect("/Events"); } + + // /Events/Detail/X + public IActionResult Detail(int id) + { + Event theEvent = context.Events + .Include(e => e.Category) + .Single(e => e.Id == id); + + EventDetailViewModel viewModel = new EventDetailViewModel(theEvent); + return View(viewModel); + } } } diff --git a/CodingEventsDemo/Controllers/TagController.cs b/CodingEventsDemo/Controllers/TagController.cs new file mode 100644 index 00000000..1fb4ef56 --- /dev/null +++ b/CodingEventsDemo/Controllers/TagController.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using CodingEventsDemo.Data; +using CodingEventsDemo.Models; +using CodingEventsDemo.ViewModels; +using Microsoft.AspNetCore.Mvc; + +namespace CodingEventsDemo.Controllers +{ + public class TagController : Controller + { + private EventDbContext context; + + public TagController(EventDbContext dbContext) + { + context = dbContext; + } + + // GET: // + public IActionResult Index() + { + List tags = context.Tags.ToList(); + return View(tags); + } + + public IActionResult Add() + { + Tag tag = new Tag(); + return View(tag); + } + + [HttpPost] + public IActionResult Add(Tag tag) + { + if (ModelState.IsValid) + { + context.Tags.Add(tag); + context.SaveChanges(); + return Redirect("/Tag/"); + } + + return View("Add", tag); + } + + public IActionResult AddEvent(int id) + { + Event theEvent = context.Events.Find(id); + List possibleTags = context.Tags.ToList(); + + AddEventTagViewModel viewModel = new AddEventTagViewModel(theEvent, possibleTags); + + return View(viewModel); + } + + [HttpPost] + public IActionResult AddEvent(AddEventTagViewModel viewModel) + { + if (ModelState.IsValid) + { + int eventId = viewModel.EventId; + int tagId = viewModel.TagId; + + EventTag eventTag = new EventTag + { + EventId = eventId, + TagId = tagId + }; + + context.EventTags.Add(eventTag); + context.SaveChanges(); + + return Redirect("/Events/Detail/" + eventId); + } + + return View(viewModel); + } + } +} + diff --git a/CodingEventsDemo/Data/EventDbContext.cs b/CodingEventsDemo/Data/EventDbContext.cs index f6f10043..686dd4bf 100644 --- a/CodingEventsDemo/Data/EventDbContext.cs +++ b/CodingEventsDemo/Data/EventDbContext.cs @@ -7,10 +7,17 @@ public class EventDbContext : DbContext { public DbSet Events { get; set; } public DbSet Categories { get; set; } + public DbSet Tags { get; set; } + public DbSet EventTags { get; set; } public EventDbContext(DbContextOptions options) : base(options) { } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasKey(et => new { et.EventId, et.TagId }); + } } } diff --git a/CodingEventsDemo/Migrations/20200622195148_InitialMigration.Designer.cs b/CodingEventsDemo/Migrations/20200622195148_InitialMigration.Designer.cs deleted file mode 100644 index 824d92dc..00000000 --- a/CodingEventsDemo/Migrations/20200622195148_InitialMigration.Designer.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -using CodingEventsDemo.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace CodingEventsDemo.Migrations -{ - [DbContext(typeof(EventDbContext))] - [Migration("20200622195148_InitialMigration")] - partial class InitialMigration - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "3.1.5") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - modelBuilder.Entity("CodingEventsDemo.Models.Event", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - b.Property("ContactEmail") - .HasColumnType("longtext CHARACTER SET utf8mb4"); - - b.Property("Description") - .HasColumnType("longtext CHARACTER SET utf8mb4"); - - b.Property("Name") - .HasColumnType("longtext CHARACTER SET utf8mb4"); - - b.Property("Type") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.ToTable("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/CodingEventsDemo/Migrations/20200622195148_InitialMigration.cs b/CodingEventsDemo/Migrations/20200622195148_InitialMigration.cs deleted file mode 100644 index ad1c4792..00000000 --- a/CodingEventsDemo/Migrations/20200622195148_InitialMigration.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace CodingEventsDemo.Migrations -{ - public partial class InitialMigration : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Events", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), - Name = table.Column(nullable: true), - Description = table.Column(nullable: true), - ContactEmail = table.Column(nullable: true), - Type = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Events", x => x.Id); - }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Events"); - } - } -} diff --git a/CodingEventsDemo/Migrations/20200625184338_MyInitialMigration.Designer.cs b/CodingEventsDemo/Migrations/20200625184338_MyInitialMigration.Designer.cs deleted file mode 100644 index 9571e202..00000000 --- a/CodingEventsDemo/Migrations/20200625184338_MyInitialMigration.Designer.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -using CodingEventsDemo.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace CodingEventsDemo.Migrations -{ - [DbContext(typeof(EventDbContext))] - [Migration("20200625184338_MyInitialMigration")] - partial class MyInitialMigration - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "3.1.5") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - modelBuilder.Entity("CodingEventsDemo.Models.Event", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - b.Property("ContactEmail") - .HasColumnType("longtext CHARACTER SET utf8mb4"); - - b.Property("Description") - .HasColumnType("longtext CHARACTER SET utf8mb4"); - - b.Property("Name") - .HasColumnType("longtext CHARACTER SET utf8mb4"); - - b.Property("Type") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.ToTable("Events"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/CodingEventsDemo/Migrations/20200625184338_MyInitialMigration.cs b/CodingEventsDemo/Migrations/20200625184338_MyInitialMigration.cs deleted file mode 100644 index 470e8717..00000000 --- a/CodingEventsDemo/Migrations/20200625184338_MyInitialMigration.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -namespace CodingEventsDemo.Migrations -{ - public partial class MyInitialMigration : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - - } - } -} diff --git a/CodingEventsDemo/Migrations/20200625205525_CategoryMigration.cs b/CodingEventsDemo/Migrations/20200625205525_CategoryMigration.cs deleted file mode 100644 index b0ff5016..00000000 --- a/CodingEventsDemo/Migrations/20200625205525_CategoryMigration.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace CodingEventsDemo.Migrations -{ - public partial class CategoryMigration : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Categories", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), - Name = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Categories", x => x.Id); - }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Categories"); - } - } -} diff --git a/CodingEventsDemo/Migrations/20200625205525_CategoryMigration.Designer.cs b/CodingEventsDemo/Migrations/20221121172651_MigrationsRedo.Designer.cs similarity index 58% rename from CodingEventsDemo/Migrations/20200625205525_CategoryMigration.Designer.cs rename to CodingEventsDemo/Migrations/20221121172651_MigrationsRedo.Designer.cs index 0001be8f..f3f556c7 100644 --- a/CodingEventsDemo/Migrations/20200625205525_CategoryMigration.Designer.cs +++ b/CodingEventsDemo/Migrations/20221121172651_MigrationsRedo.Designer.cs @@ -5,17 +5,19 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +#nullable disable + namespace CodingEventsDemo.Migrations { [DbContext(typeof(EventDbContext))] - [Migration("20200625205525_CategoryMigration")] - partial class CategoryMigration + [Migration("20221121172651_MigrationsRedo")] + partial class MigrationsRedo { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "6.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("CodingEventsDemo.Models.Event", b => @@ -24,20 +26,22 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("int"); + b.Property("CategoryId") + .HasColumnType("int"); + b.Property("ContactEmail") - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("Description") - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("Name") - .HasColumnType("longtext CHARACTER SET utf8mb4"); - - b.Property("Type") - .HasColumnType("int"); + .HasColumnType("longtext"); b.HasKey("Id"); + b.HasIndex("CategoryId"); + b.ToTable("Events"); }); @@ -48,12 +52,28 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("int"); b.Property("Name") - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("Categories"); }); + + modelBuilder.Entity("CodingEventsDemo.Models.Event", b => + { + b.HasOne("CodingEventsDemo.Models.EventCategory", "Category") + .WithMany("events") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.EventCategory", b => + { + b.Navigation("events"); + }); #pragma warning restore 612, 618 } } diff --git a/CodingEventsDemo/Migrations/20221121172651_MigrationsRedo.cs b/CodingEventsDemo/Migrations/20221121172651_MigrationsRedo.cs new file mode 100644 index 00000000..bea90c1a --- /dev/null +++ b/CodingEventsDemo/Migrations/20221121172651_MigrationsRedo.cs @@ -0,0 +1,71 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace CodingEventsDemo.Migrations +{ + public partial class MigrationsRedo : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterDatabase() + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Categories", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Name = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_Categories", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Events", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Name = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Description = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + ContactEmail = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + CategoryId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Events", x => x.Id); + table.ForeignKey( + name: "FK_Events_Categories_CategoryId", + column: x => x.CategoryId, + principalTable: "Categories", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_Events_CategoryId", + table: "Events", + column: "CategoryId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Events"); + + migrationBuilder.DropTable( + name: "Categories"); + } + } +} diff --git a/CodingEventsDemo/Migrations/20221122235334_AddsEventTag.Designer.cs b/CodingEventsDemo/Migrations/20221122235334_AddsEventTag.Designer.cs new file mode 100644 index 00000000..ccfc9569 --- /dev/null +++ b/CodingEventsDemo/Migrations/20221122235334_AddsEventTag.Designer.cs @@ -0,0 +1,130 @@ +// +using CodingEventsDemo.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CodingEventsDemo.Migrations +{ + [DbContext(typeof(EventDbContext))] + [Migration("20221122235334_AddsEventTag")] + partial class AddsEventTag + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("CodingEventsDemo.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("ContactEmail") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.EventCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.EventTag", b => + { + b.Property("EventId") + .HasColumnType("int"); + + b.Property("TagId") + .HasColumnType("int"); + + b.HasKey("EventId", "TagId"); + + b.HasIndex("TagId"); + + b.ToTable("EventTags"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.Event", b => + { + b.HasOne("CodingEventsDemo.Models.EventCategory", "Category") + .WithMany("events") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.EventTag", b => + { + b.HasOne("CodingEventsDemo.Models.Event", "Event") + .WithMany() + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodingEventsDemo.Models.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.EventCategory", b => + { + b.Navigation("events"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CodingEventsDemo/Migrations/20221122235334_AddsEventTag.cs b/CodingEventsDemo/Migrations/20221122235334_AddsEventTag.cs new file mode 100644 index 00000000..5e914e37 --- /dev/null +++ b/CodingEventsDemo/Migrations/20221122235334_AddsEventTag.cs @@ -0,0 +1,67 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace CodingEventsDemo.Migrations +{ + public partial class AddsEventTag : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Tags", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Name = table.Column(type: "varchar(50)", maxLength: 50, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_Tags", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "EventTags", + columns: table => new + { + EventId = table.Column(type: "int", nullable: false), + TagId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_EventTags", x => new { x.EventId, x.TagId }); + table.ForeignKey( + name: "FK_EventTags_Events_EventId", + column: x => x.EventId, + principalTable: "Events", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_EventTags_Tags_TagId", + column: x => x.TagId, + principalTable: "Tags", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_EventTags_TagId", + table: "EventTags", + column: "TagId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "EventTags"); + + migrationBuilder.DropTable( + name: "Tags"); + } + } +} diff --git a/CodingEventsDemo/Migrations/EventDbContextModelSnapshot.cs b/CodingEventsDemo/Migrations/EventDbContextModelSnapshot.cs index 87e3e7e4..f62063e9 100644 --- a/CodingEventsDemo/Migrations/EventDbContextModelSnapshot.cs +++ b/CodingEventsDemo/Migrations/EventDbContextModelSnapshot.cs @@ -4,6 +4,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +#nullable disable + namespace CodingEventsDemo.Migrations { [DbContext(typeof(EventDbContext))] @@ -13,7 +15,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "6.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("CodingEventsDemo.Models.Event", b => @@ -22,20 +24,22 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("int"); + b.Property("CategoryId") + .HasColumnType("int"); + b.Property("ContactEmail") - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("Description") - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.Property("Name") - .HasColumnType("longtext CHARACTER SET utf8mb4"); - - b.Property("Type") - .HasColumnType("int"); + .HasColumnType("longtext"); b.HasKey("Id"); + b.HasIndex("CategoryId"); + b.ToTable("Events"); }); @@ -46,12 +50,78 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("int"); b.Property("Name") - .HasColumnType("longtext CHARACTER SET utf8mb4"); + .HasColumnType("longtext"); b.HasKey("Id"); b.ToTable("Categories"); }); + + modelBuilder.Entity("CodingEventsDemo.Models.EventTag", b => + { + b.Property("EventId") + .HasColumnType("int"); + + b.Property("TagId") + .HasColumnType("int"); + + b.HasKey("EventId", "TagId"); + + b.HasIndex("TagId"); + + b.ToTable("EventTags"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.Event", b => + { + b.HasOne("CodingEventsDemo.Models.EventCategory", "Category") + .WithMany("events") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.EventTag", b => + { + b.HasOne("CodingEventsDemo.Models.Event", "Event") + .WithMany() + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodingEventsDemo.Models.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.EventCategory", b => + { + b.Navigation("events"); + }); #pragma warning restore 612, 618 } } diff --git a/CodingEventsDemo/Models/Event.cs b/CodingEventsDemo/Models/Event.cs index c0f181b0..4ee485dd 100644 --- a/CodingEventsDemo/Models/Event.cs +++ b/CodingEventsDemo/Models/Event.cs @@ -11,7 +11,9 @@ public class Event public string ContactEmail { get; set; } - public EventType Type { get; set; } + public EventCategory Category { get; set; } + + public int CategoryId { get; set; } public int Id { get; set; } diff --git a/CodingEventsDemo/Models/EventCategory.cs b/CodingEventsDemo/Models/EventCategory.cs index 97155526..57abe888 100644 --- a/CodingEventsDemo/Models/EventCategory.cs +++ b/CodingEventsDemo/Models/EventCategory.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; + namespace CodingEventsDemo.Models { public class EventCategory @@ -7,6 +9,8 @@ public class EventCategory public int Id { get; set; } + public List events { get; set; } + public EventCategory(string name) { Name = name; diff --git a/CodingEventsDemo/Models/EventTag.cs b/CodingEventsDemo/Models/EventTag.cs new file mode 100644 index 00000000..a39705e7 --- /dev/null +++ b/CodingEventsDemo/Models/EventTag.cs @@ -0,0 +1,17 @@ +using System; +namespace CodingEventsDemo.Models +{ + public class EventTag + { + public int EventId { get; set; } + public Event Event { get; set; } + + public int TagId { get; set; } + public Tag Tag { get; set; } + + public EventTag() + { + } + } +} + diff --git a/CodingEventsDemo/Models/EventType.cs b/CodingEventsDemo/Models/EventType.cs deleted file mode 100644 index 9de53d41..00000000 --- a/CodingEventsDemo/Models/EventType.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -namespace CodingEventsDemo.Models -{ - public enum EventType - { - Conference, - Meetup, - Workshop, - Social - } -} diff --git a/CodingEventsDemo/Models/Tag.cs b/CodingEventsDemo/Models/Tag.cs new file mode 100644 index 00000000..1f86c184 --- /dev/null +++ b/CodingEventsDemo/Models/Tag.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace CodingEventsDemo.Models +{ + public class Tag + { + public int Id { get; set; } + + [Required(ErrorMessage = "Name is required")] + [StringLength(50, MinimumLength = 3, ErrorMessage = "Name must be between 3 and 50 characters long")] + public string Name { get; set; } + + public Tag(string name) + { + Name = name; + } + + public Tag() + { + } + } +} + diff --git a/CodingEventsDemo/Properties/launchSettings.json b/CodingEventsDemo/Properties/launchSettings.json index 0b123df6..6049ed67 100644 --- a/CodingEventsDemo/Properties/launchSettings.json +++ b/CodingEventsDemo/Properties/launchSettings.json @@ -18,10 +18,10 @@ "CodingEventsDemo": { "commandName": "Project", "launchBrowser": true, + "applicationUrl": "http://localhost:23921", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001;http://localhost:5000" + } } } } \ No newline at end of file diff --git a/CodingEventsDemo/Startup.cs b/CodingEventsDemo/Startup.cs index 07282c05..74a73c98 100644 --- a/CodingEventsDemo/Startup.cs +++ b/CodingEventsDemo/Startup.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using static System.Net.Mime.MediaTypeNames; namespace CodingEventsDemo { @@ -27,7 +28,7 @@ public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddDbContext(options => - options.UseMySql(Configuration.GetConnectionString("DefaultConnection"))); + options.UseMySql(Configuration.GetConnectionString("DefaultConnection"), new MySqlServerVersion(new Version()))); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/CodingEventsDemo/ViewModels/AddEventCategoryViewModel.cs b/CodingEventsDemo/ViewModels/AddEventCategoryViewModel.cs index bf455328..0af3b0e2 100644 --- a/CodingEventsDemo/ViewModels/AddEventCategoryViewModel.cs +++ b/CodingEventsDemo/ViewModels/AddEventCategoryViewModel.cs @@ -5,8 +5,13 @@ namespace CodingEventsDemo.ViewModels { public class AddEventCategoryViewModel { - [Required(ErrorMessage = "Name is required!")] - [StringLength(20, MinimumLength = 3, ErrorMessage = "Name must be between 3 and 20 characters long")] + [Required(ErrorMessage = "Event name is required.")] + [StringLength(20, MinimumLength = 3, ErrorMessage = "Name must be between 3 and 20 characters long.")] public string Name { get; set; } + + public AddEventCategoryViewModel() + { + } } } + diff --git a/CodingEventsDemo/ViewModels/AddEventTagViewModel.cs b/CodingEventsDemo/ViewModels/AddEventTagViewModel.cs new file mode 100644 index 00000000..7c618198 --- /dev/null +++ b/CodingEventsDemo/ViewModels/AddEventTagViewModel.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using CodingEventsDemo.Models; +using Microsoft.AspNetCore.Mvc.Rendering; + +namespace CodingEventsDemo.ViewModels +{ + public class AddEventTagViewModel + { + public int EventId { get; set; } + public Event Event { get; set; } + + public List Tags { get; set; } + + public int TagId { get; set; } + + public AddEventTagViewModel(Event theEvent, List possibleTags) + { + Tags = new List(); + foreach (var tag in possibleTags) + { + Tags.Add(new SelectListItem + { + Value = tag.Id.ToString(), + Text = tag.Name + }); + } + + Event = theEvent; + } + + public AddEventTagViewModel() + { + } + } +} + diff --git a/CodingEventsDemo/ViewModels/AddEventViewModel.cs b/CodingEventsDemo/ViewModels/AddEventViewModel.cs index 9e933c00..33fe73a0 100644 --- a/CodingEventsDemo/ViewModels/AddEventViewModel.cs +++ b/CodingEventsDemo/ViewModels/AddEventViewModel.cs @@ -19,15 +19,29 @@ public class AddEventViewModel [EmailAddress] public string ContactEmail { get; set; } - public EventType Type { get; set; } + [Required(ErrorMessage ="Category is required.")] + public int CategoryId { get; set; } - public List EventTypes { get; set; } = new List + public List Categories { get; set; } + + public AddEventViewModel(List categories) + { + Categories = new List(); + + foreach (var category in categories) + { + Categories.Add( + new SelectListItem + { + Value = category.Id.ToString(), + Text = category.Name + } + ); + } + } + public AddEventViewModel() { - new SelectListItem(EventType.Conference.ToString(), ((int)EventType.Conference).ToString()), - new SelectListItem(EventType.Meetup.ToString(), ((int)EventType.Meetup).ToString()), - new SelectListItem(EventType.Social.ToString(), ((int)EventType.Social).ToString()), - new SelectListItem(EventType.Workshop.ToString(), ((int)EventType.Workshop).ToString()) - }; + } } } diff --git a/CodingEventsDemo/ViewModels/EventDetailViewModel.cs b/CodingEventsDemo/ViewModels/EventDetailViewModel.cs new file mode 100644 index 00000000..ba3a0d43 --- /dev/null +++ b/CodingEventsDemo/ViewModels/EventDetailViewModel.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using CodingEventsDemo.Models; + +namespace CodingEventsDemo.ViewModels +{ + public class EventDetailViewModel + { + public string Name { get; set; } + public string Description { get; set; } + public string ContactEmail { get; set; } + public string CategoryName { get; set; } + + public EventDetailViewModel(Event theEvent) + { + Name = theEvent.Name; + Description = theEvent.Description; + ContactEmail = theEvent.ContactEmail; + CategoryName = theEvent.Category.Name; + } + } +} \ No newline at end of file diff --git a/CodingEventsDemo/Views/EventCategory/Create.cshtml b/CodingEventsDemo/Views/EventCategory/Create.cshtml index abca1ce7..4a4ba489 100644 --- a/CodingEventsDemo/Views/EventCategory/Create.cshtml +++ b/CodingEventsDemo/Views/EventCategory/Create.cshtml @@ -2,11 +2,11 @@

Add New Category

-
-
- - - -
- -
+
+
+ + + +
+ +
\ No newline at end of file diff --git a/CodingEventsDemo/Views/Events/Add.cshtml b/CodingEventsDemo/Views/Events/Add.cshtml index 23c4b4fe..a04fe957 100644 --- a/CodingEventsDemo/Views/Events/Add.cshtml +++ b/CodingEventsDemo/Views/Events/Add.cshtml @@ -18,8 +18,8 @@
- - + +
diff --git a/CodingEventsDemo/Views/Events/Detail.cshtml b/CodingEventsDemo/Views/Events/Detail.cshtml new file mode 100644 index 00000000..e5acbbba --- /dev/null +++ b/CodingEventsDemo/Views/Events/Detail.cshtml @@ -0,0 +1,18 @@ +@model CodingEventsDemo.ViewModels.EventDetailViewModel + +

@Model.Name

+ + + + + + + + + + + + + + +
Description@Model.Description
Contact Email@Model.ContactEmail
Category@Model.CategoryName
\ No newline at end of file diff --git a/CodingEventsDemo/Views/Events/Index.cshtml b/CodingEventsDemo/Views/Events/Index.cshtml index 4dc26085..4d99091c 100644 --- a/CodingEventsDemo/Views/Events/Index.cshtml +++ b/CodingEventsDemo/Views/Events/Index.cshtml @@ -32,17 +32,17 @@ else Contact Email - Event Type + Category @foreach (var evt in Model) { @evt.Id - @evt.Name + @evt.Name @evt.Description @evt.ContactEmail - @evt.Type + @evt.Category.Name } diff --git a/CodingEventsDemo/Views/Shared/_Layout.cshtml b/CodingEventsDemo/Views/Shared/_Layout.cshtml index bd93997b..d7a3d7b7 100644 --- a/CodingEventsDemo/Views/Shared/_Layout.cshtml +++ b/CodingEventsDemo/Views/Shared/_Layout.cshtml @@ -19,6 +19,7 @@