diff --git a/CodingEventsDemo/CodingEventsDemo.csproj b/CodingEventsDemo/CodingEventsDemo.csproj index 1992ad14..d0b92a8b 100644 --- a/CodingEventsDemo/CodingEventsDemo.csproj +++ b/CodingEventsDemo/CodingEventsDemo.csproj @@ -1,12 +1,28 @@ - netcoreapp3.1 + net6.0 + True + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + diff --git a/CodingEventsDemo/Controllers/EventCategoryController.cs b/CodingEventsDemo/Controllers/EventCategoryController.cs new file mode 100644 index 00000000..4ee1e946 --- /dev/null +++ b/CodingEventsDemo/Controllers/EventCategoryController.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using CodingEventsDemo.Data; +using CodingEventsDemo.Models; +using Microsoft.AspNetCore.Mvc; +using CodingEventsDemo.ViewModels; + +// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 + +namespace CodingEventsDemo.Controllers +{ + public class EventCategoryController : Controller + { + private EventDbContext context; + + public EventCategoryController(EventDbContext dbContext) + { + context = dbContext; + } + + // GET: // + [HttpGet] + public IActionResult Index() + { + List categories = context.Categories.ToList(); + return View(categories); + } + + [HttpGet] + public IActionResult Create() + { + AddEventCategoryViewModel addEventCategoryViewModel = new AddEventCategoryViewModel(); + return View(addEventCategoryViewModel); + } + + [HttpPost] + public IActionResult ProcessCreateEventCategoryForm(AddEventCategoryViewModel addEventCategoryViewModel) + { + if (ModelState.IsValid) + { + EventCategory newCategory = new EventCategory + { + Name = addEventCategoryViewModel.Name + }; + + context.Categories.Add(newCategory); + context.SaveChanges(); + + return Redirect("/EventCategory"); + } + + return View("Create", addEventCategoryViewModel); + } + } +} diff --git a/CodingEventsDemo/Controllers/EventsController.cs b/CodingEventsDemo/Controllers/EventsController.cs index 16edaf58..d3022d61 100644 --- a/CodingEventsDemo/Controllers/EventsController.cs +++ b/CodingEventsDemo/Controllers/EventsController.cs @@ -2,7 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using CodingEventsDemo.Data; +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 @@ -11,28 +15,88 @@ namespace coding_events_practice.Controllers public class EventsController : Controller { - static private List Events = new List(); + private EventDbContext context; + + public EventsController(EventDbContext dbContext) + { + context = dbContext; + } // GET: // public IActionResult Index() { - ViewBag.events = Events; + List events = context.Events + .Include(e => e.Category) + .ToList(); - return View(); + return View(events); } public IActionResult Add() { + List categories = context.Categories.ToList(); + AddEventViewModel addEventViewModel = new AddEventViewModel(categories); + + return View(addEventViewModel); + } + + [HttpPost] + public IActionResult Add(AddEventViewModel addEventViewModel) + { + if (ModelState.IsValid) + { + EventCategory theCategory = context.Categories.Find(addEventViewModel.CategoryId); + Event newEvent = new Event + { + Name = addEventViewModel.Name, + Description = addEventViewModel.Description, + ContactEmail = addEventViewModel.ContactEmail, + Category = theCategory + }; + + context.Events.Add(newEvent); + context.SaveChanges(); + + return Redirect("/Events"); + } + + return View(addEventViewModel); + } + + public IActionResult Delete() + { + ViewBag.events = context.Events.ToList(); + return View(); } [HttpPost] - [Route("Events/Add")] - public IActionResult NewEvent(string name) + public IActionResult Delete(int[] eventIds) { - Events.Add(name); + foreach (int eventId in eventIds) + { + Event theEvent = context.Events.Find(eventId); + context.Events.Remove(theEvent); + } + + context.SaveChanges(); return Redirect("/Events"); } + + public IActionResult Detail(int id) + { + Event theEvent = context.Events + .Include(e => e.Category) + .Single(e => e.Id == id); + + List eventTags = context.EventTags + .Where(et => et.EventId == id) + .Include(et => et.Tag) + .ToList(); + + EventDetailViewModel viewModel = new EventDetailViewModel(theEvent, eventTags); + return View(viewModel); + } } } diff --git a/CodingEventsDemo/Controllers/TagController.cs b/CodingEventsDemo/Controllers/TagController.cs new file mode 100644 index 00000000..cff5f179 --- /dev/null +++ b/CodingEventsDemo/Controllers/TagController.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using CodingEventsDemo.Data; +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 + +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; + + List existingItems = context.EventTags + .Where(et => et.EventId == eventId) + .Where(et => et.TagId == tagId) + .ToList(); + + if (existingItems.Count == 0) + { + + 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 new file mode 100644 index 00000000..686dd4bf --- /dev/null +++ b/CodingEventsDemo/Data/EventDbContext.cs @@ -0,0 +1,23 @@ +using CodingEventsDemo.Models; +using Microsoft.EntityFrameworkCore; + +namespace CodingEventsDemo.Data +{ + 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 new file mode 100644 index 00000000..824d92dc --- /dev/null +++ b/CodingEventsDemo/Migrations/20200622195148_InitialMigration.Designer.cs @@ -0,0 +1,46 @@ +// +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 new file mode 100644 index 00000000..ad1c4792 --- /dev/null +++ b/CodingEventsDemo/Migrations/20200622195148_InitialMigration.cs @@ -0,0 +1,33 @@ +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 new file mode 100644 index 00000000..9571e202 --- /dev/null +++ b/CodingEventsDemo/Migrations/20200625184338_MyInitialMigration.Designer.cs @@ -0,0 +1,46 @@ +// +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 new file mode 100644 index 00000000..470e8717 --- /dev/null +++ b/CodingEventsDemo/Migrations/20200625184338_MyInitialMigration.cs @@ -0,0 +1,17 @@ +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.Designer.cs b/CodingEventsDemo/Migrations/20200625205525_CategoryMigration.Designer.cs new file mode 100644 index 00000000..0001be8f --- /dev/null +++ b/CodingEventsDemo/Migrations/20200625205525_CategoryMigration.Designer.cs @@ -0,0 +1,60 @@ +// +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("20200625205525_CategoryMigration")] + partial class CategoryMigration + { + 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"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.EventCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CodingEventsDemo/Migrations/20200625205525_CategoryMigration.cs b/CodingEventsDemo/Migrations/20200625205525_CategoryMigration.cs new file mode 100644 index 00000000..b0ff5016 --- /dev/null +++ b/CodingEventsDemo/Migrations/20200625205525_CategoryMigration.cs @@ -0,0 +1,30 @@ +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/20200709002909_ReleateEventsAndCategories.Designer.cs b/CodingEventsDemo/Migrations/20200709002909_ReleateEventsAndCategories.Designer.cs new file mode 100644 index 00000000..0f111af1 --- /dev/null +++ b/CodingEventsDemo/Migrations/20200709002909_ReleateEventsAndCategories.Designer.cs @@ -0,0 +1,71 @@ +// +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("20200709002909_ReleateEventsAndCategories")] + partial class ReleateEventsAndCategories + { + 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("CategoryId") + .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.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 CHARACTER SET utf8mb4"); + + 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(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CodingEventsDemo/Migrations/20200709002909_ReleateEventsAndCategories.cs b/CodingEventsDemo/Migrations/20200709002909_ReleateEventsAndCategories.cs new file mode 100644 index 00000000..1c923300 --- /dev/null +++ b/CodingEventsDemo/Migrations/20200709002909_ReleateEventsAndCategories.cs @@ -0,0 +1,55 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodingEventsDemo.Migrations +{ + public partial class ReleateEventsAndCategories : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Type", + table: "Events"); + + migrationBuilder.AddColumn( + name: "CategoryId", + table: "Events", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateIndex( + name: "IX_Events_CategoryId", + table: "Events", + column: "CategoryId"); + + migrationBuilder.AddForeignKey( + name: "FK_Events_Categories_CategoryId", + table: "Events", + column: "CategoryId", + principalTable: "Categories", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Events_Categories_CategoryId", + table: "Events"); + + migrationBuilder.DropIndex( + name: "IX_Events_CategoryId", + table: "Events"); + + migrationBuilder.DropColumn( + name: "CategoryId", + table: "Events"); + + migrationBuilder.AddColumn( + name: "Type", + table: "Events", + type: "int", + nullable: false, + defaultValue: 0); + } + } +} diff --git a/CodingEventsDemo/Migrations/20200709015658_AddTagModel.Designer.cs b/CodingEventsDemo/Migrations/20200709015658_AddTagModel.Designer.cs new file mode 100644 index 00000000..85f72ef6 --- /dev/null +++ b/CodingEventsDemo/Migrations/20200709015658_AddTagModel.Designer.cs @@ -0,0 +1,87 @@ +// +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("20200709015658_AddTagModel")] + partial class AddTagModel + { + 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("CategoryId") + .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.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 CHARACTER SET utf8mb4"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodingEventsDemo.Models.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(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(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CodingEventsDemo/Migrations/20200709015658_AddTagModel.cs b/CodingEventsDemo/Migrations/20200709015658_AddTagModel.cs new file mode 100644 index 00000000..707596eb --- /dev/null +++ b/CodingEventsDemo/Migrations/20200709015658_AddTagModel.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodingEventsDemo.Migrations +{ + public partial class AddTagModel : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Tags", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Name = table.Column(maxLength: 50, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Tags", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Tags"); + } + } +} diff --git a/CodingEventsDemo/Migrations/20200709113546_AddsEventTag.Designer.cs b/CodingEventsDemo/Migrations/20200709113546_AddsEventTag.Designer.cs new file mode 100644 index 00000000..a851fedb --- /dev/null +++ b/CodingEventsDemo/Migrations/20200709113546_AddsEventTag.Designer.cs @@ -0,0 +1,117 @@ +// +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("20200709113546_AddsEventTag")] + partial class AddsEventTag + { + 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("CategoryId") + .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.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 CHARACTER SET utf8mb4"); + + 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() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(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(); + }); + + 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(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CodingEventsDemo/Migrations/20200709113546_AddsEventTag.cs b/CodingEventsDemo/Migrations/20200709113546_AddsEventTag.cs new file mode 100644 index 00000000..267084ce --- /dev/null +++ b/CodingEventsDemo/Migrations/20200709113546_AddsEventTag.cs @@ -0,0 +1,45 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodingEventsDemo.Migrations +{ + public partial class AddsEventTag : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "EventTags", + columns: table => new + { + EventId = table.Column(nullable: false), + TagId = table.Column(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); + }); + + migrationBuilder.CreateIndex( + name: "IX_EventTags_TagId", + table: "EventTags", + column: "TagId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "EventTags"); + } + } +} diff --git a/CodingEventsDemo/Migrations/EventDbContextModelSnapshot.cs b/CodingEventsDemo/Migrations/EventDbContextModelSnapshot.cs new file mode 100644 index 00000000..c7604baa --- /dev/null +++ b/CodingEventsDemo/Migrations/EventDbContextModelSnapshot.cs @@ -0,0 +1,115 @@ +// +using CodingEventsDemo.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodingEventsDemo.Migrations +{ + [DbContext(typeof(EventDbContext))] + partial class EventDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(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("CategoryId") + .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.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 CHARACTER SET utf8mb4"); + + 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() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(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(); + }); + + 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(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CodingEventsDemo/Models/Event.cs b/CodingEventsDemo/Models/Event.cs new file mode 100644 index 00000000..4ee485dd --- /dev/null +++ b/CodingEventsDemo/Models/Event.cs @@ -0,0 +1,47 @@ +using System; +using Microsoft.AspNetCore.Mvc; + +namespace CodingEventsDemo.Models +{ + public class Event + { + public string Name { get; set; } + + public string Description { get; set; } + + public string ContactEmail { get; set; } + + public EventCategory Category { get; set; } + + public int CategoryId { get; set; } + + public int Id { get; set; } + + public Event(string name, string description, string contactEmail) + { + Name = name; + Description = description; + ContactEmail = contactEmail; + } + + public Event() + { + } + + public override string ToString() + { + return Name; + } + + public override bool Equals(object obj) + { + return obj is Event @event && + Id == @event.Id; + } + + public override int GetHashCode() + { + return HashCode.Combine(Id); + } + } +} diff --git a/CodingEventsDemo/Models/EventCategory.cs b/CodingEventsDemo/Models/EventCategory.cs new file mode 100644 index 00000000..57abe888 --- /dev/null +++ b/CodingEventsDemo/Models/EventCategory.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace CodingEventsDemo.Models +{ + public class EventCategory + { + public string Name { get; set; } + + public int Id { get; set; } + + public List events { get; set; } + + public EventCategory(string name) + { + Name = name; + } + + public EventCategory() + { + } + } +} diff --git a/CodingEventsDemo/Models/EventTag.cs b/CodingEventsDemo/Models/EventTag.cs new file mode 100644 index 00000000..21429806 --- /dev/null +++ b/CodingEventsDemo/Models/EventTag.cs @@ -0,0 +1,16 @@ +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/Tag.cs b/CodingEventsDemo/Models/Tag.cs new file mode 100644 index 00000000..05ae0252 --- /dev/null +++ b/CodingEventsDemo/Models/Tag.cs @@ -0,0 +1,24 @@ +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")] + 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 292641b9..20161c50 100644 --- a/CodingEventsDemo/Properties/launchSettings.json +++ b/CodingEventsDemo/Properties/launchSettings.json @@ -1,7 +1,7 @@ -{ +{ "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, + "windowsAuthentication": false, + "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:45981", "sslPort": 44368 @@ -24,4 +24,4 @@ } } } -} +} \ No newline at end of file diff --git a/CodingEventsDemo/Startup.cs b/CodingEventsDemo/Startup.cs index 342d7328..d81da98c 100644 --- a/CodingEventsDemo/Startup.cs +++ b/CodingEventsDemo/Startup.cs @@ -2,9 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using CodingEventsDemo.Data; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -24,6 +26,13 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); + + //updated syntax (used with NuGet package: Pomelo v6.0.2) + var connectionString = "server=localhost;userid=coding_events;password=Learn2code!;database=coding_events;"; + var serverVersion = new MySqlServerVersion(new Version(8, 0, 29)); + services.AddDbContext( + dbContextOptions => dbContextOptions + .UseMySql(connectionString, serverVersion)); } // 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 new file mode 100644 index 00000000..bf455328 --- /dev/null +++ b/CodingEventsDemo/ViewModels/AddEventCategoryViewModel.cs @@ -0,0 +1,12 @@ +using System; +using System.ComponentModel.DataAnnotations; + +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")] + public string Name { get; set; } + } +} diff --git a/CodingEventsDemo/ViewModels/AddEventTagViewModel.cs b/CodingEventsDemo/ViewModels/AddEventTagViewModel.cs new file mode 100644 index 00000000..e1a146a0 --- /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 new file mode 100644 index 00000000..3a89898e --- /dev/null +++ b/CodingEventsDemo/ViewModels/AddEventViewModel.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using CodingEventsDemo.Models; +using Microsoft.AspNetCore.Mvc.Rendering; + +namespace CodingEventsDemo.ViewModels +{ + public class AddEventViewModel + { + [Required(ErrorMessage = "Name is required.")] + [StringLength(50, MinimumLength = 3, ErrorMessage = "Name must be between 3 and 50 characters")] + public string Name { get; set; } + + [Required(ErrorMessage = "Description is required")] + [StringLength(500, ErrorMessage = "Description too long!")] + public string Description { get; set; } + + [EmailAddress] + public string ContactEmail { get; set; } + + [Required(ErrorMessage = "Category is required")] + public int CategoryId { get; set; } + + 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() { } + + } +} diff --git a/CodingEventsDemo/ViewModels/EventDetailViewModel.cs b/CodingEventsDemo/ViewModels/EventDetailViewModel.cs new file mode 100644 index 00000000..6daf98f6 --- /dev/null +++ b/CodingEventsDemo/ViewModels/EventDetailViewModel.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using CodingEventsDemo.Models; + +namespace CodingEventsDemo.ViewModels +{ + public class EventDetailViewModel + { + public int EventId { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string ContactEmail { get; set; } + public string CategoryName { get; set; } + public string TagText { get; set; } + + public EventDetailViewModel(Event theEvent, List eventTags) + { + EventId = theEvent.Id; + Name = theEvent.Name; + Description = theEvent.Description; + ContactEmail = theEvent.ContactEmail; + CategoryName = theEvent.Category.Name; + + TagText = ""; + + for (var i = 0; i < eventTags.Count; i++) + { + TagText += "#" + eventTags[i].Tag.Name; + + if (i < eventTags.Count - 1) + { + TagText += ", "; + } + } + } + } +} \ No newline at end of file diff --git a/CodingEventsDemo/Views/EventCategory/Create.cshtml b/CodingEventsDemo/Views/EventCategory/Create.cshtml new file mode 100644 index 00000000..abca1ce7 --- /dev/null +++ b/CodingEventsDemo/Views/EventCategory/Create.cshtml @@ -0,0 +1,12 @@ +@model CodingEventsDemo.ViewModels.AddEventCategoryViewModel + +

Add New Category

+ +
+
+ + + +
+ +
diff --git a/CodingEventsDemo/Views/EventCategory/Index.cshtml b/CodingEventsDemo/Views/EventCategory/Index.cshtml new file mode 100644 index 00000000..0a984a6a --- /dev/null +++ b/CodingEventsDemo/Views/EventCategory/Index.cshtml @@ -0,0 +1,24 @@ +@model List + +

All Event Categories

+ +@if (Model.Count == 0) +{ +

No Event Categories yet!

+} +else +{ + + + + + @foreach (EventCategory category in Model) + { + + + + + } +
Id + Category Name
@category.Id@category.Name
+} \ No newline at end of file diff --git a/CodingEventsDemo/Views/Events/Add.cshtml b/CodingEventsDemo/Views/Events/Add.cshtml index 0010854d..a04fe957 100644 --- a/CodingEventsDemo/Views/Events/Add.cshtml +++ b/CodingEventsDemo/Views/Events/Add.cshtml @@ -1,6 +1,25 @@ -

Add Event

+@model CodingEventsDemo.ViewModels.AddEventViewModel; -
- +

Add Event

+ + +
+ + + +
+
+ + + +
+
+ + +
+
+ + +
diff --git a/CodingEventsDemo/Views/Events/Delete.cshtml b/CodingEventsDemo/Views/Events/Delete.cshtml new file mode 100644 index 00000000..1bd32e97 --- /dev/null +++ b/CodingEventsDemo/Views/Events/Delete.cshtml @@ -0,0 +1,22 @@ +@* + For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 +*@ +@{ +} + +

Delete Event

+ +
+ @foreach (var evt in ViewBag.events) + { +
+ +
+ } + + + +
diff --git a/CodingEventsDemo/Views/Events/Detail.cshtml b/CodingEventsDemo/Views/Events/Detail.cshtml new file mode 100644 index 00000000..a5af1317 --- /dev/null +++ b/CodingEventsDemo/Views/Events/Detail.cshtml @@ -0,0 +1,25 @@ +@model CodingEventsDemo.ViewModels.EventDetailViewModel + +

@Model.Name

+ + + + + + + + + + + + + + + + + + + +
Description@Model.Description
Contact Email@Model.ContactEmail
Category@Model.CategoryName
Tags@Model.TagText
+ +Add Tag \ No newline at end of file diff --git a/CodingEventsDemo/Views/Events/Index.cshtml b/CodingEventsDemo/Views/Events/Index.cshtml index 7278447c..4d99091c 100644 --- a/CodingEventsDemo/Views/Events/Index.cshtml +++ b/CodingEventsDemo/Views/Events/Index.cshtml @@ -1,17 +1,50 @@ -

Coding Events

+@model List + +

Coding Events

Add Event

-@if (ViewBag.events.Count == 0) + +

+ Delete Event +

+ +@if (Model.Count == 0) {

No events yet!

} +else +{ + + + + + + + + + @foreach (var evt in Model) + { + + + + + + + + } +
+ Id + + Name + + Description + + Contact Email + + Category +
@evt.Id@evt.Name@evt.Description@evt.ContactEmail@evt.Category.Name
+} -
    - @foreach (string meeting in ViewBag.events) - { -
  • @meeting
  • - } -
diff --git a/CodingEventsDemo/Views/Shared/_Layout.cshtml b/CodingEventsDemo/Views/Shared/_Layout.cshtml index 36ea09b8..02fdc0cd 100644 --- a/CodingEventsDemo/Views/Shared/_Layout.cshtml +++ b/CodingEventsDemo/Views/Shared/_Layout.cshtml @@ -3,7 +3,7 @@ - @ViewData["Title"] - CodingEventsDemo + @ViewData["Title"] - Coding Events @@ -11,7 +11,7 @@