using System.Globalization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.EntityFrameworkCore; using TicketOffice.Data; using TicketOffice.Models; using TicketOffice.Services; using Route = TicketOffice.Models.Route; namespace TicketOffice.Pages.Management.Routes; public class EditModel : PageModel { // Error massage displaying when route number validation failed. public string NumberValidationError = null!; // Error massage displaying when route capacity validation failed. public string CapacityValidationError = null!; // Array of error massages displaying when route name validation failed. public string[] NameValidationError = null!; // Array of error massages displaying when cities // departure time validation failed. public string[] DepartureTimeValidationError = null!; // Array of error massages displaying when cities // arrival time validation failed. public string[] ArrivalTimeValidationError = null!; private readonly TicketOfficeContext context; private readonly UserValidationService validationService; public EditModel(TicketOfficeContext context, UserValidationService validationService) { this.context = context; this.validationService = validationService; } // Object representing that will be created. [BindProperty] public Route? Route { get; set; } // Object holding cities' arrival/departure dates. [BindProperty] public DateString[] TimeStrings { get; set; } = null!; // Holds cities' ids between loading and saving [BindProperty] public int[] CityIds { get; set; } = null!; // Called when GET request is sent to the page. // Retrieves route. public IActionResult OnGet(int? id) { if (!validationService.IsManager(HttpContext)) { return RedirectToPage("/Index"); } if (id == null) { return NotFound(); } Route = context.Route.Where(m => m.Id == id) .Include(r => r.Cities) .First(); InitializeArrays(); TimeStrings = new DateString[Route.Cities.Count]; for (int i = 0; i < TimeStrings.Length; i++) { TimeStrings[i] = new DateString(); } InsertDatesIntoStrings(); SaveCityIds(); if (Route == null) { return NotFound(); } return Page(); } // Called when POST request is sent to the page. // Saves changes made to route. public IActionResult OnPost(int? id) { InitializeArrays(); InsertDatesIntoCities(); LoadCityIds(); Route!.Id = (int) id; if (!ValidateInput()) { return Page(); } context.Attach(Route).State = EntityState.Modified; foreach (var city in Route.Cities) { context.Attach(city).State = EntityState.Modified; } try { context.SaveChanges(); } catch (DbUpdateConcurrencyException) { if (!RouteExists(Route.Id)) { return NotFound(); } else { throw; } } return RedirectToPage("./Index"); } private bool RouteExists(int id) { return context.Route.Any(e => e.Id == id); } private void InsertDatesIntoCities() { for (int i = 0; i < Route!.Cities.Count; i++) { try { Route.Cities[i].DepartureTime = ConvertStringToDate(TimeStrings[i].DepartureDate!); } catch(Exception) { if (Route.Cities.Count > 2) { DepartureTimeValidationError= InitializeArray( Route.Cities.Count, ""); } DepartureTimeValidationError[i] = "Формат: dd.MM.yyyy, hh:mm"; } try { Route.Cities[i].ArrivalTime = ConvertStringToDate(TimeStrings[i].ArrivalDate!); } catch(Exception) { if (Route.Cities.Count > 2) { ArrivalTimeValidationError = InitializeArray( Route.Cities.Count, ""); } ArrivalTimeValidationError[i] = "Формат: dd.MM.yyyy, hh:mm"; } } DateTime? ConvertStringToDate(string dateStr) { if (String.IsNullOrWhiteSpace(dateStr) || String.IsNullOrEmpty(dateStr)) { return null; } string[] date = dateStr.Split(",")[0].Split("."); string[] time = dateStr.Split(",")[1].Split(":"); date.ToList().ForEach(s => s.Trim()); time.ToList().ForEach(s => s.Trim()); return new DateTime( Int32.Parse(date[2]), Int32.Parse(date[1]), Int32.Parse(date[0]), Int32.Parse(time[0]), Int32.Parse(time[1]), 0); } } private void InsertDatesIntoStrings() { for (int i = 0; i < Route!.Cities.Count; i++) { if (Route.Cities[i].DepartureTime != null) { TimeStrings[i].DepartureDate = Route.Cities[i].DepartureTime! .Value.ToString("dd.MM.yyyy, hh:mm"); } if (Route.Cities[i].ArrivalTime != null) { TimeStrings[i].ArrivalDate = Route.Cities[i].ArrivalTime! .Value.ToString("dd.MM.yyyy, hh:mm"); } } } // This method doesn't actually work, but stays here for representing // an idea. It should be removed. private void SaveCityIds() { CityIds = new int[Route!.Cities.Count]; for (int i = 0; i < Route.Cities.Count; i++) { CityIds[i] = Route.Cities[i].Id; } } private void LoadCityIds() { for (int i = 0; i < CityIds.Length; i++) { Route!.Cities[i].Id = CityIds[i]; } } private bool ValidateInput() { bool isValidNumber = ValidateNumber(Route!.Number, out NumberValidationError); bool isValidCapacity = ValidateCapacity(Route.Capacity, out CapacityValidationError); for (int i = 0; i < Route.Cities.Count; i++) { if (Route.Cities.Count > 2) { NameValidationError = InitializeArray( Route.Cities.Count, ""); } ValidateName(Route.Cities[i].Name, out NameValidationError[i]); } for (int i = 0; i < Route.Cities.Count; i++) { if (Route.Cities.Count > 2) { DepartureTimeValidationError= InitializeArray( Route.Cities.Count, ""); } ValidateDate(Route.Cities[i].DepartureTime, out DepartureTimeValidationError[i]); } for (int i = 0; i < Route.Cities.Count; i++) { if (Route.Cities.Count > 2) { ArrivalTimeValidationError = InitializeArray( Route.Cities.Count, ""); } ValidateDate(Route.Cities[i].ArrivalTime, out ArrivalTimeValidationError[i]); } if (!isValidNumber || !isValidCapacity || NameValidationError.Any(e => e != "") || DepartureTimeValidationError.Any(e => e != "") || ArrivalTimeValidationError.Any(e => e != "")) { return false; } return true; bool ValidateNumber(int number, out string validationError) { validationError = ""; if (number < 1 || number > 9999) { validationError = "Має бути в проміжку від 1 до 9999"; return false; } return true; } bool ValidateCapacity(int capacity, out string validationError) { validationError = ""; if (capacity < 1 || capacity > 40) { validationError = "Має бути в проміжку від 5 до 45"; return false; } return true; } bool ValidateName(string name, out string validationError) { validationError = ""; if (String.IsNullOrWhiteSpace(name) || String.IsNullOrEmpty(name)) { validationError = "Поле має бути заповненим"; return false; } return true; } bool ValidateDate(DateTime? date, out string validationError) { validationError = ""; if (date == null) { return true; } if (date < DateTime.Today) { validationError = $"Має бути пізніше ніж {DateTime.Today.ToString(CultureInfo.GetCultureInfo("uk-UA"))}"; return false; } return true; } } private T[] InitializeArray(int length, T initVal) { T[] arr = new T[length]; for (int i = 0; i < length; i++) { arr[i] = initVal; } return arr; } private void InitializeArrays() { NameValidationError = InitializeArray(Route!.Cities.Count, ""); DepartureTimeValidationError = InitializeArray(Route.Cities.Count, ""); ArrivalTimeValidationError = InitializeArray(Route.Cities.Count, ""); } }