Y2S1-Web_Apps_and_Services/ThAmCo.Events/Controllers/EventsController.cs
2020-06-07 22:36:12 +01:00

606 lines
22 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using ThAmCo.Events.Data;
using ThAmCo.Events.Models;
using System.Net.Http;
using System.Diagnostics;
using ThAmCo.Events.Models.ViewModels.Events;
using ThAmCo.Events.Models.Dto;
namespace ThAmCo.Events.Views
{
public class EventsController : Controller
{
private readonly EventsDbContext _context;
public EventsController(EventsDbContext context)
{
_context = context;
}
// GET: Events
public async Task<IActionResult> Index()
{
var @event = await _context.Events.Include(e => e.Bookings).Include(s => s.Staffings).ThenInclude(s => s.Staff).Where(e => e.IsDeleted == false).ToListAsync();
return View(@event);
}
// GET: Events/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var @event = await _context.Events
.FirstOrDefaultAsync(m => m.Id == id);
//Get both bookings and staffings from the database so pass to the view, so it can show the guests and staff for that event.
@event.Bookings = await _context.Guests.Include(m => m.Customer).Where(m => m.EventId == id).ToListAsync();
@event.Staffings = await _context.Staffing.Include(m => m.Staff).Where(m => m.EventId == id).ToListAsync();
if (@event == null)
{
return NotFound();
}
ReservationDto reservation = null;
//Get the reservation information for the event, if it exists.
HttpClient client = new HttpClient
{
BaseAddress = new Uri("http://localhost:23652/")
};
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
HttpResponseMessage response = await client.GetAsync("api/reservations/" + @event.VenueReference);
if (response.IsSuccessStatusCode)
{
reservation = await response.Content.ReadAsAsync<ReservationDto>();
}
else
{
Debug.WriteLine("Index received a bad response from the web service.");
}
var edm = new EventDetailsModel
{
Id = @event.Id,
Title = @event.Title,
Date = @event.Date,
Duration = @event.Duration,
TypeId = @event.TypeId,
Bookings = @event.Bookings,
Reservation = reservation,
FoodReference = @event.FoodReference,
Staffing = @event.Staffings
};
return View(edm);
}
// GET: Events/Create
public async Task<IActionResult> Create()
{
//For this code, AJAX calls can be used, along with regular HTTP redirects.
//It depends on whether the programmer wants the client or the server to make the call to the web service.
//This isn't a live action effecting the user interface, so it can be done either way.
//This code works and returns the correct things, however the ViewBag doesn't have the correct ID.
/*var eventTypes = new List<EventTypeDto>().AsEnumerable();
HttpClient client = new HttpClient
{
BaseAddress = new Uri("http://localhost:23652/")
};
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
HttpResponseMessage response = await client.GetAsync("api/eventtypes");
if (response.IsSuccessStatusCode)
{
eventTypes = await response.Content.ReadAsAsync<IEnumerable<EventTypeDto>>();
}
else
{
Debug.WriteLine("Index received a bad response from the web service.");
}
ViewData["EventLists"] = new SelectList(eventTypes, "TypeId", "Title");*/
return View();
}
// POST: Events/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,Date,Duration,TypeId")] Event @event)
{
if (ModelState.IsValid)
{
_context.Add(@event);
await _context.SaveChangesAsync();
//Return to the newly created Details page of the event.
return RedirectToAction(nameof(Details), new { id = @event.Id });
}
return View(@event);
}
// GET: Events/SelectVenue
public async Task<IActionResult> SelectVenue(int id)
{
if (ModelState.IsValid)
{
var @event = _context.Events.FirstOrDefaultAsync(e => e.Id == id).Result;
//Check if event exists.
if (@event.Id != 0)
{
var venues = new List<VenueDto>().AsEnumerable();
//For the Selection of the Venue, it could all be handled within one page, however it's loaded on page load.
//AJAX could be used here also, however loading from the server is also fine.
//Get list of the available venues from the web service.
HttpClient client = new HttpClient
{
BaseAddress = new Uri("http://localhost:23652/")
};
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
HttpResponseMessage response = await client.GetAsync("api/Availability?eventType=" + @event.TypeId + "&beginDate=" + @event.Date.ToString("MM/dd/yyyy") + "&endDate=" + @event.Date.ToString("MM/dd/yyyy"));
if (response.IsSuccessStatusCode)
{
venues = await response.Content.ReadAsAsync<IEnumerable<VenueDto>>();
}
else
{
Debug.WriteLine("Index received a bad response from the web service.");
}
SelectVenueModel svm = new SelectVenueModel
{
Id = id,
Venues = venues.ToList()
};
return View(@svm);
}
}
return RedirectToAction(nameof(Details), new { id = id });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateReservation([Bind("Id,VenueDate,VenueCode")] EventCreateReservationModel @event)
{
if (ModelState.IsValid)
{
//Add reservation (call add api)
//Needs redirect afterwards so AJAX doesn't need to be used to call here.
HttpClient client = new HttpClient()
{
BaseAddress = new Uri("http://localhost:23652/")
};
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
var reservation = new ReservationCreateDto
{
EventDate = @event.VenueDate,
VenueCode = @event.VenueCode,
StaffId = "Test"
};
HttpResponseMessage response = await client.PostAsJsonAsync("api/reservations", reservation);
//Add the venue reference to the database.
var eventContext = await _context.Events.Include(m => m.Bookings).FirstOrDefaultAsync(e => e.Id == @event.Id);
var originalEvent = eventContext;
eventContext.VenueReference = @event.VenueCode + @event.VenueDate.ToString("yyyyMMdd");
_context.Entry(originalEvent).CurrentValues.SetValues(eventContext);
_context.SaveChanges();
return RedirectToAction(nameof(Details), new { id = @event.Id });
}
return View(@event);
}
public async Task<IActionResult> FreeReservation(int id)
{
var eventContext = await _context.Events.FirstOrDefaultAsync(e => e.Id == id);
if (eventContext.Id != 0)
{
//Request that the reservation called is deleted by the web service.
HttpClient client = new HttpClient()
{
BaseAddress = new Uri("http://localhost:23652/")
};
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
HttpResponseMessage response = await client.DeleteAsync("api/reservations/" + eventContext.VenueReference);
if (response.IsSuccessStatusCode)
{
//Save this change to local database.
var editedEventContext = eventContext;
editedEventContext.VenueReference = null;
_context.Entry(eventContext).CurrentValues.SetValues(editedEventContext);
_context.SaveChanges();
return RedirectToAction(nameof(Details), new { id = id });
}
else
{
Debug.WriteLine("Index Delete Error.");
}
}
return RedirectToAction(nameof(Details), new { id = id });
}
// GET: Events/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var @event = await _context.Events.FindAsync(id);
if (@event == null)
{
return NotFound();
}
return View(@event);
}
// POST: Events/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,Duration")] EventEditModel @event)
{
var eventContext = await _context.Events.FirstOrDefaultAsync(m => m.Id == id);
eventContext.Title = @event.Title;
eventContext.Duration = @event.Duration;
if (id != @event.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(eventContext);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!EventExists(@event.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(@event);
}
//Register attendance for customer at event
public async Task<IActionResult> RegisterAttendance([Bind("EventId,CustomerId,Attending")] EventRegisterAttendanceModel @event)
{
//Change attendance for a customer at an event (toggle)
if (@event.CustomerId != 0 && @event.EventId != 0)
{
if (_context.Guests.Any(g => g.EventId == @event.EventId && g.CustomerId == @event.CustomerId))
{
var booking = await _context.Guests.FirstOrDefaultAsync(g => g.EventId == @event.EventId && g.CustomerId == @event.CustomerId);
booking.Attended = !booking.Attended;
_context.Update(booking);
await _context.SaveChangesAsync();
}
}
return RedirectToAction(nameof(Details), new { id = @event.EventId });
}
// GET: Events/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var @event = await _context.Events
.FirstOrDefaultAsync(m => m.Id == id);
if (@event == null)
{
return NotFound();
}
return View(@event);
}
// POST: Events/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
//Change the event to deleted.
var @event = await _context.Events.FindAsync(id);
if (@event != null)
{
//Ask web api to delete the reservation that the event used to hold.
HttpClient client = new HttpClient()
{
BaseAddress = new Uri("http://localhost:23652/")
};
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
HttpResponseMessage response = await client.DeleteAsync("api/reservations/" + @event.VenueReference);
//Soft deletion is done by having a boolean value in the object, true being deleted and false being not deleted.
//Other ways of doing this could be nullable values, such as dates, such that not null values are not deleted, and null values are deleted.
//Using dates is useful if you want to un-delete a lot of data at once from a certain time.
//If successful, soft delete event.
@event.IsDeleted = true;
@event.VenueReference = null;
_context.Events.Update(@event);
/*Guest bookings can be deleted if required.
var guestBookings = await _context.Guests.Where(g => g.EventId == id).ToListAsync();
_context.Guests.RemoveRange(guestBookings);*/
//Hard delete staffings.
var staffings = await _context.Staffing.Where(s => s.EventId == id).ToListAsync();
_context.Staffing.RemoveRange(staffings);
await _context.SaveChangesAsync();
}
return RedirectToAction(nameof(Index));
}
private bool EventExists(int id)
{
return _context.Events.Any(e => e.Id == id);
}
//Removes a Customer from an Event.
// POST: Events/RemoveCustomer/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveCustomer(int id, [Bind("CustomerId,EventId")] GuestBooking guestBooking)
{
if (id != guestBooking.EventId)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Remove(guestBooking);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
throw;
}
return RedirectToAction(nameof(Details), new { id });
}
return RedirectToAction(nameof(Details));
}
public async Task<IActionResult> RemoveStaff(int id, [Bind("StaffId,EventId")] Staffing staffing)
{
if (id != staffing.EventId)
{
return NotFound();
}
if (ModelState.IsValid && staffing.EventId != 0 && staffing.StaffId != 0)
{
try
{
_context.Remove(staffing);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
throw;
}
return RedirectToAction(nameof(Details), new { id = id });
}
return RedirectToAction(nameof(Details));
}
public async Task<IActionResult> AddCustomer(int id)
{
//Get customers that dont exist in current event.
var guests = await _context.Guests.Include(g => g.Customer).Where(g => g.EventId == id).Select(c => c.Customer).ToListAsync();
var customers = await _context.Customers.ToListAsync();
//This seems to be the simplest way to go about it in LINQ.
//Excludes data in the current set.
var result = await _context.Customers.Except(guests).ToListAsync();
EventAddCustomerModel eacm = new EventAddCustomerModel
{
EventId = id,
Customer = result
};
return View(eacm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddCustomer([Bind("CustomerId,EventId")] GuestBooking guestBooking)
{
if (ModelState.IsValid)
{
guestBooking.Customer = _context.Customers.First(c => c.Id == guestBooking.CustomerId);
guestBooking.Event = _context.Events.First(e => e.Id == guestBooking.EventId);
_context.Add(guestBooking);
await _context.SaveChangesAsync();
//Return to the newly created Details page of the event.
return RedirectToAction(nameof(Details), new { id = guestBooking.EventId });
}
return RedirectToAction(nameof(Details));
}
public async Task<IActionResult> AddStaff(int id)
{
var staff = await _context.Staffing.Include(g => g.Staff).Where(g => g.EventId == id).Select(c => c.Staff).ToListAsync();
//Also uses the except function in LINQ.
var result = await _context.Staff.Except(staff).ToListAsync();
EventAddStaffModel eacm = new EventAddStaffModel
{
EventId = id,
Staff = result
};
return View(eacm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddStaff([Bind("StaffId,EventId")] Staffing staffing)
{
if (ModelState.IsValid)
{
staffing.Staff = _context.Staff.First(s => s.Id == staffing.StaffId);
staffing.Event = _context.Events.First(e => e.Id == staffing.EventId);
_context.Add(staffing);
await _context.SaveChangesAsync();
//Return to the newly created Details page of the event.
return RedirectToAction(nameof(Details), new { id = staffing.EventId });
}
return RedirectToAction(nameof(Details));
}
public async Task<IActionResult> AddMenu(int id)
{
if (EventExists(id))
{
//Get menu back from api.
HttpClient client = new HttpClient()
{
BaseAddress = new Uri("http://localhost:32824")
};
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
HttpResponseMessage response = await client.GetAsync("api/values");
if (response.IsSuccessStatusCode)
{
var menus = response.Content.ReadAsAsync<IEnumerable<MenuDTO>>().Result.ToList();
EventAddMenuModel eamm = new EventAddMenuModel
{
EventId = id,
Menus = menus
};
return View(eamm);
}
else
{
Debug.WriteLine("API GET Error.");
}
}
return RedirectToAction(nameof(Details), new { id = id });
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddMenu(int EventID, int MenuID)
{
if (EventExists(EventID))
{
//Add the menu reference to database.
var @event = _context.Events.First(e => e.Id == EventID);
@event.FoodReference = MenuID;
_context.Update(@event);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Details), new { id = EventID });
}
return NotFound();
}
public IActionResult FindVenue()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> FindVenueResults([Bind("EventType,StartDate,EndDate")] EventFindVenueModel search)
{
if (ModelState.IsValid)
{
//Return all venues that satify the constraints.
//AJAX could be used here if it was loading on the same page, however different pages are used.
var venues = new List<VenueDto>().AsEnumerable();
HttpClient client = new HttpClient
{
BaseAddress = new Uri("http://localhost:23652/")
};
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
HttpResponseMessage response = await client.GetAsync("api/Availability?eventType=" + search.EventType + "&beginDate=" + search.StartDate.ToString("MM/dd/yyyy") + "&endDate=" + search.EndDate.ToString("MM/dd/yyyy"));
if (response.IsSuccessStatusCode)
{
venues = await response.Content.ReadAsAsync<IEnumerable<VenueDto>>();
}
else
{
Debug.WriteLine("Index received a bad response from the web service.");
}
return View(venues);
}
return NotFound();
}
public IActionResult CreateWithVenue(string reference)
{
return View(new Event { VenueReference = reference });
}
}
}