From 19217b18adb08c4b98c5658181e3434e0f33a246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?So=C5=88a=20Neme=C4=8Dkayov=C3=A1?= <xnemeck@fi.muni.cz> Date: Sun, 20 Oct 2024 16:32:38 +0200 Subject: [PATCH] Create Event, EventParticipant, EventComment tables --- Api/Api.csproj | 4 - Api/Controllers/EventCommentController.cs | 138 +++++++++++++++++ Api/Controllers/EventController.cs | 129 ++++++++++++++++ Api/Controllers/EventParticipantController.cs | 139 ++++++++++++++++++ Api/Models/Converter.cs | 77 +++++++++- Api/Models/Event/EventCreateModel.cs | 21 +++ Api/Models/Event/EventFilter.cs | 13 ++ Api/Models/Event/EventModel.cs | 17 +++ Api/Models/Event/EventUpdateModel.cs | 14 ++ .../EventComment/EventCommentCreateModel.cs | 19 +++ Api/Models/EventComment/EventCommentFilter.cs | 12 ++ Api/Models/EventComment/EventCommentModel.cs | 15 ++ .../EventComment/EventCommentUpdateModel.cs | 10 ++ .../EventParticipantCreateModel.cs | 17 +++ .../EventParticipantFilter.cs | 11 ++ .../EventParticipant/EventParticipantModel.cs | 16 ++ .../EventParticipantUpdateModel.cs | 9 ++ DAL/Constants/SeedingValues.cs | 19 +++ DAL/Data/DataInitializer.cs | 87 +++++++++++ DAL/Data/RestaurantDBContext.cs | 3 + DAL/Enums/ParticipantType.cs | 11 ++ DAL/Models/Event.cs | 31 ++++ DAL/Models/EventComment.cs | 26 ++++ DAL/Models/EventParticipant .cs | 24 +++ DAL/Models/Restaurant.cs | 7 + 25 files changed, 864 insertions(+), 5 deletions(-) create mode 100644 Api/Controllers/EventCommentController.cs create mode 100644 Api/Controllers/EventController.cs create mode 100644 Api/Controllers/EventParticipantController.cs create mode 100644 Api/Models/Event/EventCreateModel.cs create mode 100644 Api/Models/Event/EventFilter.cs create mode 100644 Api/Models/Event/EventModel.cs create mode 100644 Api/Models/Event/EventUpdateModel.cs create mode 100644 Api/Models/EventComment/EventCommentCreateModel.cs create mode 100644 Api/Models/EventComment/EventCommentFilter.cs create mode 100644 Api/Models/EventComment/EventCommentModel.cs create mode 100644 Api/Models/EventComment/EventCommentUpdateModel.cs create mode 100644 Api/Models/EventParticipant/EventParticipantCreateModel.cs create mode 100644 Api/Models/EventParticipant/EventParticipantFilter.cs create mode 100644 Api/Models/EventParticipant/EventParticipantModel.cs create mode 100644 Api/Models/EventParticipant/EventParticipantUpdateModel.cs create mode 100644 DAL/Enums/ParticipantType.cs create mode 100644 DAL/Models/Event.cs create mode 100644 DAL/Models/EventComment.cs create mode 100644 DAL/Models/EventParticipant .cs create mode 100644 DAL/Models/Restaurant.cs diff --git a/Api/Api.csproj b/Api/Api.csproj index 606a5b3..90b3202 100644 --- a/Api/Api.csproj +++ b/Api/Api.csproj @@ -18,8 +18,4 @@ <ProjectReference Include="..\DAL\DAL.csproj" /> </ItemGroup> - <ItemGroup> - <Folder Include="Models\" /> - </ItemGroup> - </Project> diff --git a/Api/Controllers/EventCommentController.cs b/Api/Controllers/EventCommentController.cs new file mode 100644 index 0000000..5cf5008 --- /dev/null +++ b/Api/Controllers/EventCommentController.cs @@ -0,0 +1,138 @@ +using Api.Models; +using Api.Models.EventComment; +using DAL.Data; +using DAL.Models; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace Api.Controllers +{ + [Route("/[controller]")] + [ApiController] + public class EventCommentController : Controller + { + private readonly RestaurantDBContext _context; + + public EventCommentController(RestaurantDBContext context) + { + _context = context; + } + + [HttpGet] + [Route("{commentId:guid}")] + public async Task<IActionResult> GetEventCommentById([FromRoute] Guid commentId) + { + var comment = await _context.EventComments + .Include(c => c.Poster) + .FirstOrDefaultAsync(c => c.Id == commentId); + + if (comment is null || comment.DeletedAt is not null) + { + return NotFound(); + } + + return Ok(Converter.ToEventCommentModel(comment)); + } + + [HttpGet] + public async Task<IActionResult> GetEventComments([FromQuery] EventCommentFilter filter, + [FromQuery] int limit = 0, [FromQuery] int offset = 0) + { + var filterFunc = Converter.ToEventCommentFilterFunc(filter); + + var commentsQuery = _context.EventComments + .Include(c => c.Poster) + .Where(filterFunc) + .OrderByDescending(c => c.CreatedAt) + .Skip(offset); + + var comments = limit > 0 + ? await commentsQuery.Take(limit).ToListAsync() + : await commentsQuery.ToListAsync(); + + return Ok(comments.Select(Converter.ToEventCommentModel).ToList()); + } + + [HttpPost] + public async Task<IActionResult> CreateEventComment([FromBody] EventCommentCreateModel data) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var poster = await _context.Users.FindAsync(data.PosterId); + if (poster is null || poster.DeletedAt is not null) + { + return NotFound("Poster not found."); + } + + var eventEntity = await _context.Events.FindAsync(data.EventId); + if (eventEntity is null || eventEntity.DeletedAt is not null) + { + return NotFound("Event not found."); + } + + var comment = new EventComment + { + Id = Guid.NewGuid(), + PosterId = data.PosterId, + EventId = data.EventId, + Content = data.Content, + ParentCommentId = data.ParentCommentId, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }; + + await _context.EventComments.AddAsync(comment); + await _context.SaveChangesAsync(); + + return CreatedAtAction(nameof(CreateEventComment), Converter.ToEventCommentModel(comment)); + } + + [HttpPatch] + [Route("{commentId:guid}")] + public async Task<IActionResult> UpdateEventComment([FromRoute] Guid commentId, [FromBody] EventCommentUpdateModel data) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var comment = await _context.EventComments.FindAsync(commentId); + + if (comment is null || comment.DeletedAt is not null) + { + return NotFound(); + } + + comment.Content = data.Content ?? comment.Content; + comment.UpdatedAt = DateTime.UtcNow; + + _context.EventComments.Update(comment); + await _context.SaveChangesAsync(); + + return Ok(Converter.ToEventCommentModel(comment)); + } + + [HttpDelete] + [Route("{commentId:guid}")] + public async Task<IActionResult> DeleteEventComment([FromRoute] Guid commentId) + { + var comment = await _context.EventComments.FindAsync(commentId); + + if (comment is null) + { + return NotFound(); + } + + comment.UpdatedAt = DateTime.UtcNow; + comment.DeletedAt = DateTime.UtcNow; + + _context.EventComments.Update(comment); + await _context.SaveChangesAsync(); + + return Ok(); + } + } +} diff --git a/Api/Controllers/EventController.cs b/Api/Controllers/EventController.cs new file mode 100644 index 0000000..20c983c --- /dev/null +++ b/Api/Controllers/EventController.cs @@ -0,0 +1,129 @@ +using Api.Models; +using Api.Models.Event; +using DAL.Data; +using DAL.Models; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace Api.Controllers +{ + [Route("/[controller]")] + [ApiController] + public class EventController : Controller + { + private readonly RestaurantDBContext _context; + + public EventController(RestaurantDBContext context) + { + _context = context; + } + + [HttpGet] + [Route("{eventId:guid}")] + public async Task<IActionResult> GetEventById([FromRoute] Guid eventId) + { + var eventEntity = await _context.Events + .Include(e => e.Comments) + .Include(e => e.Participants) + .SingleOrDefaultAsync(e => e.Id == eventId); + + if (eventEntity is null || eventEntity.DeletedAt is not null) + { + return NotFound(); + } + + return Ok(Converter.ToEventModel(eventEntity)); + } + + [HttpGet] + public async Task<IActionResult> GetEvents([FromQuery] EventFilter filter, + [FromQuery] int limit = 0, [FromQuery] int offset = 0) + { + var filterFunc = Converter.ToEventFilterFunc(filter); + var eventsQuery = _context.Events + .Include(e => e.Comments) + .Include(e => e.Participants) + .Where(filterFunc) + .OrderBy(e => e.Date) + .Skip(offset); + + var events = limit > 0 + ? await eventsQuery.Take(limit).ToListAsync() + : await eventsQuery.ToListAsync(); + + return Ok(events.Select(Converter.ToEventModel).ToList()); + } + + [HttpPost] + public async Task<IActionResult> CreateEvent([FromBody] EventCreateModel data) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var eventEntity = new Event + { + Id = Guid.NewGuid(), + Title = data.Title, + RestaurantId = data.RestaurantId, + Content = data.Content, + Date = data.Date, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }; + + await _context.Events.AddAsync(eventEntity); + await _context.SaveChangesAsync(); + + return CreatedAtAction(nameof(CreateEvent), Converter.ToEventModel(eventEntity)); + } + + [HttpPatch] + [Route("{eventId:guid}")] + public async Task<IActionResult> UpdateEvent([FromRoute] Guid eventId, [FromBody] EventUpdateModel data) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var eventEntity = await _context.Events.FindAsync(eventId); + + if (eventEntity is null || eventEntity.DeletedAt is not null) + { + return NotFound(); + } + + eventEntity.Title = data.Title ?? eventEntity.Title; + eventEntity.Content = data.Content ?? eventEntity.Content; + eventEntity.Date = data.Date ?? eventEntity.Date; + eventEntity.UpdatedAt = DateTime.UtcNow; + + _context.Events.Update(eventEntity); + await _context.SaveChangesAsync(); + + return Ok(Converter.ToEventModel(eventEntity)); + } + + [HttpDelete] + [Route("{eventId:guid}")] + public async Task<IActionResult> DeleteEvent([FromRoute] Guid eventId) + { + var eventEntity = await _context.Events.FindAsync(eventId); + + if (eventEntity is null) + { + return NotFound(); + } + + eventEntity.UpdatedAt = DateTime.UtcNow; + eventEntity.DeletedAt = DateTime.UtcNow; + + _context.Events.Update(eventEntity); + await _context.SaveChangesAsync(); + + return Ok(); + } + } +} diff --git a/Api/Controllers/EventParticipantController.cs b/Api/Controllers/EventParticipantController.cs new file mode 100644 index 0000000..dce9b54 --- /dev/null +++ b/Api/Controllers/EventParticipantController.cs @@ -0,0 +1,139 @@ +using Api.Models; +using Api.Models.EventParticipant; +using DAL.Data; +using DAL.Models; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace Api.Controllers +{ + [Route("/[controller]")] + [ApiController] + public class EventParticipantController : Controller + { + private readonly RestaurantDBContext _context; + + public EventParticipantController(RestaurantDBContext context) + { + _context = context; + } + + [HttpGet] + [Route("{participantId:guid}")] + public async Task<IActionResult> GetEventParticipantById([FromRoute] Guid participantId) + { + var participant = await _context.EventParticipants + .Include(p => p.User) + .Include(p => p.Event) + .FirstOrDefaultAsync(p => p.Id == participantId); + + if (participant is null) + { + return NotFound(); + } + + return Ok(Converter.ToEventParticipantModel(participant)); + } + + [HttpGet] + public async Task<IActionResult> GetEventParticipants([FromQuery] EventParticipantFilter filter, + [FromQuery] int limit = 0, [FromQuery] int offset = 0) + { + var filterFunc = Converter.ToEventParticipantFilterFunc(filter); + + var participantsQuery = _context.EventParticipants + .Include(p => p.User) + .Include(p => p.Event) + .OrderBy(p => p.User.Name) + .Where(filterFunc) + .Skip(offset); + + var participants = limit > 0 + ? await participantsQuery.Take(limit).ToListAsync() + : await participantsQuery.ToListAsync(); + + return Ok(participants.Select(Converter.ToEventParticipantModel).ToList()); + } + + [HttpPost] + public async Task<IActionResult> CreateEventParticipant([FromBody] EventParticipantCreateModel data) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var user = await _context.Users.FindAsync(data.UserId); + if (user is null) + { + return NotFound("User not found."); + } + + var eventEntity = await _context.Events.FindAsync(data.EventId); + if (eventEntity is null || eventEntity.DeletedAt is not null) + { + return NotFound("Event not found."); + } + + var participant = new EventParticipant + { + Id = Guid.NewGuid(), + UserId = data.UserId, + EventId = data.EventId, + Attendance = data.Attendance, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }; + + await _context.EventParticipants.AddAsync(participant); + await _context.SaveChangesAsync(); + + return CreatedAtAction(nameof(CreateEventParticipant), Converter.ToEventParticipantModel(participant)); + } + + [HttpPatch] + [Route("{participantId:guid}")] + public async Task<IActionResult> UpdateEventParticipant([FromRoute] Guid participantId, [FromBody] EventParticipantUpdateModel data) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var participant = await _context.EventParticipants.FindAsync(participantId); + + if (participant is null) + { + return NotFound(); + } + + participant.Attendance = data.Attendance ?? participant.Attendance; + participant.UpdatedAt = DateTime.UtcNow; + + _context.EventParticipants.Update(participant); + await _context.SaveChangesAsync(); + + return Ok(Converter.ToEventParticipantModel(participant)); + } + + [HttpDelete] + [Route("{participantId:guid}")] + public async Task<IActionResult> DeleteEventParticipant([FromRoute] Guid participantId) + { + var participant = await _context.EventParticipants.FindAsync(participantId); + + if (participant is null) + { + return NotFound(); + } + + participant.UpdatedAt = DateTime.UtcNow; + participant.DeletedAt = DateTime.UtcNow; + + _context.EventParticipants.Update(participant); + await _context.SaveChangesAsync(); + + return Ok(); + } + } +} diff --git a/Api/Models/Converter.cs b/Api/Models/Converter.cs index 63e322b..7b892d8 100644 --- a/Api/Models/Converter.cs +++ b/Api/Models/Converter.cs @@ -1,4 +1,7 @@ -using Api.Models.Review; +using Api.Models.Event; +using Api.Models.EventComment; +using Api.Models.EventParticipant; +using Api.Models.Review; using Api.Models.ReviewAggregate; using Api.Models.ReviewComment; using Api.Models.User; @@ -88,5 +91,77 @@ namespace Api.Models && (filter.RestaurantId == null || r.RestaurantId == filter.RestaurantId) && r.DeletedAt == null && r.Poster.DeletedAt == null; } + + // EVENT + public static EventModel ToEventModel(DAL.Models.Event eventEntity) + { + return new EventModel + { + Id = eventEntity.Id, + Title = eventEntity.Title, + RestaurantId = eventEntity.RestaurantId, + Date = eventEntity.Date.ToLocalTime(), + Content = eventEntity.Content, + CreatedAt = eventEntity.CreatedAt.ToLocalTime(), + UpdatedAt = eventEntity.UpdatedAt.ToLocalTime(), + DeletedAt = eventEntity.DeletedAt?.ToLocalTime(), + }; + } + + public static Expression<Func<DAL.Models.Event, bool>> ToEventFilterFunc(EventFilter filter) + { + return e => (filter.RestaurantId == null || e.RestaurantId == filter.RestaurantId) + && (filter.DateFrom == null || e.Date >= filter.DateFrom) + && (filter.DateTo == null || e.Date <= filter.DateTo) + && e.DeletedAt == null; + } + + // EVENT COMMENT + public static EventCommentModel ToEventCommentModel(DAL.Models.EventComment comment) + { + return new EventCommentModel + { + Id = comment.Id, + Poster = ToUserModel(comment.Poster).Name, + EventId = comment.EventId, + ParentCommentId = comment.ParentCommentId, + Content = comment.Content, + CreatedAt = comment.CreatedAt.ToLocalTime(), + UpdatedAt = comment.UpdatedAt.ToLocalTime(), + DeletedAt = comment.DeletedAt?.ToLocalTime(), + }; + } + + public static Expression<Func<DAL.Models.EventComment, bool>> ToEventCommentFilterFunc(EventCommentFilter filter) + { + return c => (filter.PosterId == null || c.PosterId == filter.PosterId) + && (filter.EventId == null || c.EventId == filter.EventId) + && (filter.ParentCommentId == null || c.ParentCommentId == filter.ParentCommentId) + && c.DeletedAt == null; + } + + + // EVENT PARTICIPANT + public static EventParticipantModel ToEventParticipantModel(DAL.Models.EventParticipant participant) + { + return new EventParticipantModel + { + Id = participant.Id, + UserId = participant.UserId, + EventId = participant.EventId, + Attendance = participant.Attendance, + CreatedAt = participant.CreatedAt.ToLocalTime(), + UpdatedAt = participant.UpdatedAt.ToLocalTime(), + DeletedAt = participant.DeletedAt?.ToLocalTime(), + }; + } + + public static Expression<Func<DAL.Models.EventParticipant, bool>> ToEventParticipantFilterFunc(EventParticipantFilter filter) + { + return p => (filter.UserId == null || p.UserId == filter.UserId) + && (filter.EventId == null || p.EventId == filter.EventId) + && p.DeletedAt == null; + } + } } diff --git a/Api/Models/Event/EventCreateModel.cs b/Api/Models/Event/EventCreateModel.cs new file mode 100644 index 0000000..cd5fe1f --- /dev/null +++ b/Api/Models/Event/EventCreateModel.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; + +namespace Api.Models.Event +{ + public class EventCreateModel + { + [Required] + [MaxLength(100)] + public string Title { get; set; } + + [Required] + public Guid RestaurantId { get; set; } + + [Required] + public DateTime Date { get; set; } + + [Required] + [MaxLength(3600)] + public string Content { get; set; } + } +} diff --git a/Api/Models/Event/EventFilter.cs b/Api/Models/Event/EventFilter.cs new file mode 100644 index 0000000..36fd422 --- /dev/null +++ b/Api/Models/Event/EventFilter.cs @@ -0,0 +1,13 @@ +using System; + +namespace Api.Models.Event +{ + public class EventFilter + { + public Guid? RestaurantId { get; set; } + + public DateTime? DateFrom { get; set; } + + public DateTime? DateTo { get; set; } + } +} diff --git a/Api/Models/Event/EventModel.cs b/Api/Models/Event/EventModel.cs new file mode 100644 index 0000000..4053d7e --- /dev/null +++ b/Api/Models/Event/EventModel.cs @@ -0,0 +1,17 @@ +using Api.Models.EventComment; +using Api.Models.EventParticipant; + +namespace Api.Models.Event +{ + public class EventModel + { + public Guid Id { get; set; } + public string Title { get; set; } + public Guid RestaurantId { get; set; } + public DateTime Date { get; set; } + public string Content { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime? UpdatedAt { get; set; } + public DateTime? DeletedAt { get; set; } + } +} diff --git a/Api/Models/Event/EventUpdateModel.cs b/Api/Models/Event/EventUpdateModel.cs new file mode 100644 index 0000000..5cda265 --- /dev/null +++ b/Api/Models/Event/EventUpdateModel.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Api.Models.Event +{ + public class EventUpdateModel + { + public string Title { get; set; } + + [MaxLength(3200)] + public string Content { get; set; } + + public DateTime? Date { get; set; } + } +} diff --git a/Api/Models/EventComment/EventCommentCreateModel.cs b/Api/Models/EventComment/EventCommentCreateModel.cs new file mode 100644 index 0000000..5893d32 --- /dev/null +++ b/Api/Models/EventComment/EventCommentCreateModel.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; + +namespace Api.Models.EventComment +{ + public class EventCommentCreateModel + { + [Required] + public Guid PosterId { get; set; } + + [Required] + public Guid EventId { get; set; } + + [Required] + [MaxLength(1800)] + public string Content { get; set; } + + public Guid? ParentCommentId { get; set; } + } +} diff --git a/Api/Models/EventComment/EventCommentFilter.cs b/Api/Models/EventComment/EventCommentFilter.cs new file mode 100644 index 0000000..3af2cab --- /dev/null +++ b/Api/Models/EventComment/EventCommentFilter.cs @@ -0,0 +1,12 @@ +namespace Api.Models.EventComment +{ + public class EventCommentFilter + { + public Guid? EventId { get; set; } + public Guid? PosterId { get; set; } + public Guid? ParentCommentId { get; set; } + public string ContentKeyword { get; set; } + public DateTime? CreatedAfter { get; set; } + public DateTime? CreatedBefore { get; set; } + } +} diff --git a/Api/Models/EventComment/EventCommentModel.cs b/Api/Models/EventComment/EventCommentModel.cs new file mode 100644 index 0000000..2024977 --- /dev/null +++ b/Api/Models/EventComment/EventCommentModel.cs @@ -0,0 +1,15 @@ +namespace Api.Models.EventComment +{ + public class EventCommentModel + { + public Guid Id { get; set; } + public Guid PosterId { get; set; } + public string Poster { get; set; } + public Guid EventId { get; set; } + public string Content { get; set; } + public Guid? ParentCommentId { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + public DateTime? DeletedAt { get; set; } + } +} diff --git a/Api/Models/EventComment/EventCommentUpdateModel.cs b/Api/Models/EventComment/EventCommentUpdateModel.cs new file mode 100644 index 0000000..e0baaf6 --- /dev/null +++ b/Api/Models/EventComment/EventCommentUpdateModel.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; + +namespace Api.Models.EventComment +{ + public class EventCommentUpdateModel + { + [MaxLength(1800)] + public string Content { get; set; } + } +} diff --git a/Api/Models/EventParticipant/EventParticipantCreateModel.cs b/Api/Models/EventParticipant/EventParticipantCreateModel.cs new file mode 100644 index 0000000..dc217e7 --- /dev/null +++ b/Api/Models/EventParticipant/EventParticipantCreateModel.cs @@ -0,0 +1,17 @@ +using DAL.Enums; +using System.ComponentModel.DataAnnotations; + +namespace Api.Models.EventParticipant +{ + public class EventParticipantCreateModel + { + [Required] + public Guid UserId { get; set; } + + [Required] + public Guid EventId { get; set; } + + [Required] + public ParticipantType Attendance { get; set; } + } +} diff --git a/Api/Models/EventParticipant/EventParticipantFilter.cs b/Api/Models/EventParticipant/EventParticipantFilter.cs new file mode 100644 index 0000000..86dbc09 --- /dev/null +++ b/Api/Models/EventParticipant/EventParticipantFilter.cs @@ -0,0 +1,11 @@ +using DAL.Enums; + +namespace Api.Models.EventParticipant +{ + public class EventParticipantFilter + { + public Guid? UserId { get; set; } + public Guid? EventId { get; set; } + public ParticipantType? Attendance { get; set; } + } +} diff --git a/Api/Models/EventParticipant/EventParticipantModel.cs b/Api/Models/EventParticipant/EventParticipantModel.cs new file mode 100644 index 0000000..2fe62c5 --- /dev/null +++ b/Api/Models/EventParticipant/EventParticipantModel.cs @@ -0,0 +1,16 @@ +using Api.Models.User; +using DAL.Enums; + +namespace Api.Models.EventParticipant +{ + public class EventParticipantModel + { + public Guid Id { get; set; } + public Guid UserId { get; set; } + public Guid EventId { get; set; } + public ParticipantType Attendance { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + public DateTime? DeletedAt { get; set; } + } +} diff --git a/Api/Models/EventParticipant/EventParticipantUpdateModel.cs b/Api/Models/EventParticipant/EventParticipantUpdateModel.cs new file mode 100644 index 0000000..3925295 --- /dev/null +++ b/Api/Models/EventParticipant/EventParticipantUpdateModel.cs @@ -0,0 +1,9 @@ +using DAL.Enums; + +namespace Api.Models.EventParticipant +{ + public class EventParticipantUpdateModel + { + public ParticipantType? Attendance { get; set; } + } +} diff --git a/DAL/Constants/SeedingValues.cs b/DAL/Constants/SeedingValues.cs index a8d54f8..eb1067d 100644 --- a/DAL/Constants/SeedingValues.cs +++ b/DAL/Constants/SeedingValues.cs @@ -2,11 +2,30 @@ { public class SeedingValues { + // User IDs public static readonly Guid User1Id = new("afde48a8-99e3-423e-a48d-9e4e6a3d823a"); public static readonly Guid User2Id = new("32669bac-a1bd-4e9d-9580-ee4a7764cda3"); + + // Review IDs public static readonly Guid Review1Id = new("32669bac-a1bd-4e9d-9580-ee4a7764cda3"); + + // Review Comment IDs public static readonly Guid ReviewComment1Id = new("af16972e-d611-4c1c-8ce3-a93d667c1b9a"); public static readonly Guid ReviewComment2Id = new("9ddbe84f-f2f4-4532-bca7-13152905c3b1"); + + // Restaurant IDs public static readonly Guid Restaurant1Id = new("104fdc28-a328-4f7b-85fe-81550cf1e247"); + + // Event IDs + public static readonly Guid Event1Id = new("10ba7f93-895f-4be5-987e-45e6d55bda3f"); + public static readonly Guid Event2Id = new("c68be8ab-fc64-456a-a5fb-f97f2a96e2d1"); + + // Event Participant IDs + public static readonly Guid EventParticipant1Id = new("7c673b56-473e-4fd4-b49b-f69e8fd9adbb"); + public static readonly Guid EventParticipant2Id = new("6f995134-cbcf-42d2-9ec9-e028d85726b9"); + + // Event Comment IDs + public static readonly Guid EventComment1Id = new("88a4b4d4-b74d-40c5-823e-e708f15664d3"); + public static readonly Guid EventComment2Id = new("e0e27f5b-bd6f-47d9-b5fa-5b7e7e77d462"); } } diff --git a/DAL/Data/DataInitializer.cs b/DAL/Data/DataInitializer.cs index 96720b7..55869d2 100644 --- a/DAL/Data/DataInitializer.cs +++ b/DAL/Data/DataInitializer.cs @@ -11,6 +11,9 @@ namespace DAL.Data var users = PrepareUserModels(); var reviews = PrepareReviewModels(); var reviewComments = PrepareReviewCommentsModels(); + var events = PrepareEventModels(); + var eventParticipants = PrepareEventParticipantModels(); + var eventComments = PrepareEventCommentModels(); var reviewAggregates = reviews .GroupBy(r => r.RestaurantId) @@ -30,6 +33,12 @@ namespace DAL.Data .HasData(reviewComments); modelBuilder.Entity<ReviewAggregate>() .HasData(reviewAggregates); + modelBuilder.Entity<Event>() + .HasData(events); + modelBuilder.Entity<EventParticipant>() + .HasData(eventParticipants); + modelBuilder.Entity<EventComment>() + .HasData(eventComments); } private static List<User> PrepareUserModels() @@ -91,5 +100,83 @@ namespace DAL.Data } ]; } + + private static List<Event> PrepareEventModels() + { + return new List<Event> + { + new Event + { + Id = SeedingValues.Event1Id, + Title = "Exclusive Dinner Event", + RestaurantId = SeedingValues.Restaurant1Id, + Date = DateTime.UtcNow.AddDays(10), + Content = "Join us for an exclusive dinner with gourmet cuisine.", + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }, + new Event + { + Id = SeedingValues.Event2Id, + Title = "Wine Tasting Evening", + RestaurantId = SeedingValues.Restaurant1Id, + Date = DateTime.UtcNow.AddDays(15), + Content = "An evening of exquisite wine tasting with fine cheeses.", + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + } + }; + } + + private static List<EventParticipant> PrepareEventParticipantModels() + { + return new List<EventParticipant> + { + new EventParticipant + { + Id = SeedingValues.EventParticipant1Id, + UserId = SeedingValues.User1Id, + EventId = SeedingValues.Event1Id, + Attendance = Enums.ParticipantType.Attending, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }, + new EventParticipant + { + Id = SeedingValues.EventParticipant2Id, + UserId = SeedingValues.User2Id, + EventId = SeedingValues.Event1Id, + Attendance = Enums.ParticipantType.Tentative, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + } + }; + } + + private static List<EventComment> PrepareEventCommentModels() + { + return new List<EventComment> + { + new EventComment + { + Id = SeedingValues.EventComment1Id, + PosterId = SeedingValues.User2Id, + EventId = SeedingValues.Event1Id, + Content = "Looking forward to this event!", + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }, + new EventComment + { + Id = SeedingValues.EventComment2Id, + PosterId = SeedingValues.User1Id, + EventId = SeedingValues.Event1Id, + ParentCommentId = SeedingValues.EventComment1Id, + Content = "Me too! It sounds like a great night.", + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + } + }; + } } } diff --git a/DAL/Data/RestaurantDBContext.cs b/DAL/Data/RestaurantDBContext.cs index 90842ab..668134e 100644 --- a/DAL/Data/RestaurantDBContext.cs +++ b/DAL/Data/RestaurantDBContext.cs @@ -9,6 +9,9 @@ namespace DAL.Data public DbSet<Review> Reviews { get; set; } public DbSet<ReviewComment> ReviewComments { get; set; } public DbSet<ReviewAggregate> ReviewAggregate { get; set; } + public DbSet<Event> Events { get; set; } + public DbSet<EventComment> EventComments { get; set; } + public DbSet<EventParticipant> EventParticipants { get; set; } public RestaurantDBContext(DbContextOptions<RestaurantDBContext> options) : base(options) { } diff --git a/DAL/Enums/ParticipantType.cs b/DAL/Enums/ParticipantType.cs new file mode 100644 index 0000000..b5f52c6 --- /dev/null +++ b/DAL/Enums/ParticipantType.cs @@ -0,0 +1,11 @@ +namespace DAL.Enums +{ + public enum ParticipantType + { + Creator, + Attending, + Declined, + Tentative + } + +} diff --git a/DAL/Models/Event.cs b/DAL/Models/Event.cs new file mode 100644 index 0000000..a8e865a --- /dev/null +++ b/DAL/Models/Event.cs @@ -0,0 +1,31 @@ +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; + +namespace DAL.Models +{ + + public class Event : BaseEntity + { + [Required] + [MaxLength(100)] + public string Title { get; set; } + + [Required] + public Guid RestaurantId { get; set; } + + [Required] + public DateTime Date { get; set; } + + [Required] + [MaxLength(3600)] + public string Content { get; set; } + + [ForeignKey(nameof(RestaurantId))] + public virtual Restaurant Restaurant { get; set; } + + public virtual ICollection<EventParticipant> Participants { get; set; } = new List<EventParticipant>(); + + public virtual ICollection<EventComment> Comments { get; set; } = new List<EventComment>(); + } + +} diff --git a/DAL/Models/EventComment.cs b/DAL/Models/EventComment.cs new file mode 100644 index 0000000..1f20505 --- /dev/null +++ b/DAL/Models/EventComment.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DAL.Models +{ + public class EventComment : CommentBase + { + [Required] + public Guid PosterId { get; set; } + + public Guid? ParentCommentId { get; set; } + + [Required] + public Guid EventId { get; set; } + + [ForeignKey(nameof(PosterId))] + public virtual User Poster { get; set; } + + [ForeignKey(nameof(ParentCommentId))] + public virtual EventComment ParentComment { get; set; } + + [ForeignKey(nameof(EventId))] + public virtual Event Event { get; set; } + } + +} diff --git a/DAL/Models/EventParticipant .cs b/DAL/Models/EventParticipant .cs new file mode 100644 index 0000000..a9c2fd9 --- /dev/null +++ b/DAL/Models/EventParticipant .cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using DAL.Enums; + +namespace DAL.Models +{ + public class EventParticipant : BaseEntity + { + [Required] + public Guid UserId { get; set; } + + [Required] + public Guid EventId { get; set; } + + [Required] + public ParticipantType Attendance { get; set; } + + [ForeignKey(nameof(UserId))] + public virtual User User { get; set; } + + [ForeignKey(nameof(EventId))] + public virtual Event Event { get; set; } + } +} diff --git a/DAL/Models/Restaurant.cs b/DAL/Models/Restaurant.cs new file mode 100644 index 0000000..33e43ae --- /dev/null +++ b/DAL/Models/Restaurant.cs @@ -0,0 +1,7 @@ +namespace DAL.Models +{ + public class Restaurant + { + // placeholder till implemented + } +} -- GitLab