using System; using System.Collections.Generic; using System.Data.Entity.Validation; using System.IO; using System.Linq; using System.Web.Mvc; using System.Web.Routing; using MileageTraker.Web.Attributes; using MileageTraker.Web.DAL; using MileageTraker.Web.Utility; using MileageTraker.Web.ViewModels; using MileageTraker.Web.ViewModels.Log; using MileageTraker.Web.ViewModels.Vehicle; namespace MileageTraker.Web.Controllers { [Authorize(Roles = "Administrator, Developer")] public class LogController : ControllerBase { public ViewResult Index(LogQueryViewModel query) { var validLogYearMonths = DataService.GetValidLogMonths(); if (!validLogYearMonths.Any()) // this means no logs in DB return View("Empty"); // default parameter processing if (!query.HasParameters()) { query.Year = validLogYearMonths.First().Year; query.Month = validLogYearMonths.First().Month; query.MonthRange = 1; } if (query.Year.HasValue && !query.Month.HasValue) { var validLogMonths = validLogYearMonths.Where(dt => dt.Year == query.Year).ToList(); query.Month = validLogMonths.Min(dt => dt.Month); query.MonthRange = validLogMonths.Max(dt => dt.Month) - query.Month + 1; } var logs = DataService.GetLogs(); var filteredLogs = (from log in DataService.GetLogIndexViewModels(DataService.FilterLogs(logs, query)) orderby log.Created descending select log).ToList(); var viewModel = new LogResultsViewModel(filteredLogs, query, CustomExtensions.YearMonthList(validLogYearMonths)); Session.Add("LogPage", Request.Url.PathAndQuery); return View(viewModel); } [ActionLog] public ActionResult Export(LogQueryViewModel query) { var logs = DataService.GetLogs(); var filteredLogs = DataService.GetLogIndexViewModels( DataService.FilterLogs(logs, query) ).ToList(); var name = string.Format("MileageLogs_{0}", query); var export = ExcelWriter.WriteXls(filteredLogs, name, name); return File(export, "application/ms-excel", name + ".xls"); } public ViewResult MonthlyVehicleMileage(LogQueryViewModel query) { var items = DataService.GetMonthlyVehicleMileageItems(query); var report = new VehicleMileageViewModel (items, query); return View(report); } public ActionResult MonthlyDriverMileage(LogQueryViewModel query) { var items = DataService.GetMonthlyDriverMileageItems(query); items = items.OrderBy(i => i.DriverName); var report = new DriverMileageViewModel(items, query); return View(report); } public ViewResult Details(int id) { var log = DataService.GetLog(id); var viewModel = new LogViewModel(log) { Purpose = {Available = GetPurposeTypesSelectList()} }; return View(viewModel); } public ActionResult PreviousDetails(int id) { var log = DataService.GetLog(id); int logId; if (log.VehiclePreviousLog != null) { logId = log.VehiclePreviousLog.LogId; } else { logId = id; TempData["StatusMessage"] = "This is the first log for this vehicle"; } return RedirectToAction("Details", new {id = logId}); } public ActionResult NextDetails(int id) { var nextLog = DataService.GetNextLog(id); int logId; if (nextLog != null) { logId = nextLog.LogId; } else { logId = id; TempData["StatusMessage"] = "This is the most recent log for this vehicle"; } return RedirectToAction("Details", new { id = logId }); } [HttpGet] public ActionResult Create(string vehicleId) { var viewModel = new LogViewModel { Date = DateTime.Today, VehicleId = vehicleId, Purpose = {Available = GetPurposeTypesSelectList()}, }; return View(viewModel); } [HttpPost] [ActionLog] public ActionResult Create(LogViewModel viewModel) { if (ModelState.IsValid) { var log = viewModel.GetLog(); log.Vehicle = DataService.GetVehicle(viewModel.VehicleId); log.User = DataService.FindUserByFullName(viewModel.UserFullName); log.Source = HttpContext.Request.Url.AbsolutePath; log.UserHostAddress = HttpContext.Request.UserHostAddress; log.UserAgent = HttpContext.Request.UserAgent; if (viewModel.Purpose != null) log.Purpose = DataService.GetPurposeTypes() .First(pt => pt.PurposeTypeId == viewModel.Purpose.Selected); DataService.AddLog(log); TempData["StatusMessage"] = "Log created"; if (TempData.ContainsKey("FuelLogId")) { // update fuel log var fuelLogId = (int)TempData["FuelLogId"]; var fuelLog = DataService.GetFuelLog(fuelLogId); fuelLog.Log = log; DataService.UpdateFuelLog(fuelLog); // return to the fuel log match page TempData["StatusMessage"] = "Log created and matched to the fuel log"; return RedirectToAction("Match", "FuelLog", new {id = fuelLogId}); } return RedirectToAction("Index"); } viewModel.Purpose.Available = GetPurposeTypesSelectList(); return View(viewModel); } public ActionResult Edit(int id) { var log = DataService.GetLog(id); var viewModel = new LogViewModel(log) { Purpose = {Available = GetPurposeTypesSelectList()} }; return View(viewModel); } [HttpPost] [ActionLog] public ActionResult Edit(LogViewModel viewModel) { if (ModelState.IsValid) { var log = DataService.GetLog(viewModel.LogId); viewModel.SetProperties(log); log.User = DataService.FindUserByFullName(viewModel.UserFullName); log.Vehicle = DataService.GetVehicle(viewModel.VehicleId); if (viewModel.Purpose != null) log.Purpose = DataService.GetPurposeTypes() .First(pt => pt.PurposeTypeId == viewModel.Purpose.Selected); DataService.UpdateLog(log); TempData["StatusMessage"] = "Log updated"; return RedirectToAction("Details", new{id = log.LogId}); } viewModel.Purpose.Available = GetPurposeTypesSelectList(); return View(viewModel); } public ActionResult Delete(int id) { var log = DataService.GetLog(id); var viewModel = new LogViewModel(log) { Purpose = {Available = GetPurposeTypesSelectList()} }; return View(viewModel); } [HttpPost, ActionName("Delete")] [ActionLog] public ActionResult DeleteConfirmed(int id) { DataService.DeleteLog(id); TempData["StatusMessage"] = "Log deleted"; if (Session["LogPage"] != null) return Redirect((string) Session["LogPage"]); return RedirectToAction("Index"); } public PartialViewResult DetailsPrevious(int id) { var log = DataService.GetLog(id); return PartialView(new LogPartialDetails(log)); } #region Import public ActionResult ImportUpload() { return View(); } [HttpPost] public ActionResult Import(ImportUploadViewModel viewModel) { if (ModelState.IsValid && viewModel.File != null && viewModel.File.ContentLength > 0) { var user = DataService.FindUserByFullName(viewModel.UserName) ?? DataService.FindUserByUsername(viewModel.UserName); if (user == null) { TempData["StatusMessage"] = "User " + viewModel.UserName + " not found"; TempData["StatusMessage-Type"] = "alert-error"; } else { ViewData["UserFullName"] = user.FullName; var fileName = Path.GetFileName(viewModel.File.FileName); var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName); viewModel.File.SaveAs(path); try { var logImports = LogImporter.Import(path); // todo: delete file? return View(logImports.ToList()); } catch (OutOfMemoryException) { TempData["StatusMessage"] = "Problem reading excel document - please verify that the document is in Excel 97-2003 Workbook (.xls) format"; TempData["StatusMessage-Type"] = "alert-error"; } catch (Exception ex) { TempData["StatusMessage"] = "Problem reading excel document: " + ex.Message; TempData["StatusMessage-Type"] = "alert-error"; } } } return RedirectToAction("ImportUpload"); } enum ImportStatus { Success, Failure, Duplicate } [HttpPost] [ActionLog] public ActionResult ImportCreate(ImportLogViewModel viewModel, string userFullName) { var buttonAttributes = new Dictionary { { "class", "btn btn-mini" }, { "target", "_blank" } }; try { // verify purpose var purposeType = DataService.FindPurposeType(viewModel.Purpose); if (purposeType == null) { return Json(new { Status = ImportStatus.Failure.ToString(), Message = "Invalid Purpose: " + viewModel.Purpose, Action = GetFixLink(viewModel) }, JsonRequestBehavior.AllowGet); } if (!ModelState.IsValid) { var errorList = GetModelStateErrorList(ModelState); // remove the object name from the errors errorList = errorList.Select(s => s.Replace("viewModel.", "")); return Json(new { Status = ImportStatus.Failure.ToString(), Message = string.Join(", ", errorList), Action = GetFixLink(viewModel) }, JsonRequestBehavior.AllowGet); } var log = viewModel.GetLog(); log.Vehicle = DataService.GetVehicle(viewModel.VehicleId); log.User = DataService.FindUserByFullName(userFullName); log.Source = HttpContext.Request.Url.AbsolutePath; log.UserHostAddress = HttpContext.Request.UserHostAddress; log.UserAgent = HttpContext.Request.UserAgent; log.Purpose = purposeType; // check duplicate var duplicateLogs = DataService.GetDuplicateLogs(log).ToList(); if (duplicateLogs.Any()) { var link = HtmlHelper.GenerateLink( ControllerContext.RequestContext, RouteTable.Routes, "Details", "Default", "Details", "Log", new RouteValueDictionary(new{ id = duplicateLogs.First().LogId }), buttonAttributes); return Json(new { Status = ImportStatus.Duplicate.ToString(), Message = "This log has been previously entered", Action = link }, JsonRequestBehavior.AllowGet); } // verify vehicle exists if (log.Vehicle == null) { return Json(new { Status = ImportStatus.Failure.ToString(), Message = "Vehile with supplied ID does not exist", Action = GetFixLink(viewModel) }, JsonRequestBehavior.AllowGet); } // verify city exists if (DataService.FindCityByName(log.CityName) == null) { return Json(new { Status = ImportStatus.Failure.ToString(), Message = "City must exist in system", Action = GetFixLink(viewModel) }, JsonRequestBehavior.AllowGet); } // SAVE IT! DataService.AddLog(log); var successLink = HtmlHelper.GenerateLink( ControllerContext.RequestContext, RouteTable.Routes, "Details", "Default", "Details", "Log", new RouteValueDictionary(new { id = log.LogId }), buttonAttributes); return Json(new { Status = ImportStatus.Success.ToString(), Action = successLink }, JsonRequestBehavior.AllowGet); } catch (DbEntityValidationException ex) { // Retrieve the error messages as a list of strings. var errorMessages = ex.EntityValidationErrors .SelectMany(x => x.ValidationErrors) .Select(x => x.ErrorMessage); // Join the list to a single string. var fullErrorMessage = string.Join(", ", errorMessages); return Json(new { Status = ImportStatus.Failure.ToString(), Message = fullErrorMessage, Action = GetFixLink(viewModel) }, JsonRequestBehavior.AllowGet); } catch (Exception ex) { var message = ex.Message; return Json(new { Status = ImportStatus.Failure.ToString(), Message = message, Action = GetFixLink(viewModel) }, JsonRequestBehavior.AllowGet); } } private string GetFixLink(ImportLogViewModel viewModel) { try { viewModel.GetLogViewModel(); } catch { return string.Empty; } return RenderRazorViewToString("ImportFix", viewModel); } [HttpPost] public ActionResult ImportFix(ImportLogViewModel viewModel) { var logViewModel = viewModel.GetLogViewModel(); logViewModel.Purpose.Available = GetPurposeTypesSelectList(); return View("Create", logViewModel); } public ActionResult ImportTemplate() { var template = LogImportTemplateWriter.Write(); return File(template, "application/ms-excel", "MileageTraker_ImportTemplate.xls"); } #endregion } }