Log Import for CreateLog
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity.Validation;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using MileageTraker.Web.Attributes;
|
||||
using MileageTraker.Web.DAL;
|
||||
using MileageTraker.Web.Models;
|
||||
using MileageTraker.Web.ViewModels;
|
||||
using MileageTraker.Web.ViewModels.CreateLog;
|
||||
using MileageTraker.Web.ViewModels.Log;
|
||||
|
||||
namespace MileageTraker.Web.Controllers
|
||||
{
|
||||
@@ -160,5 +164,189 @@ namespace MileageTraker.Web.Controllers
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#region Import
|
||||
|
||||
public ActionResult ImportUpload()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Import(ImportUploadViewModel viewModel)
|
||||
{
|
||||
if (ModelState.IsValid && viewModel.File != null && viewModel.File.ContentLength > 0)
|
||||
{
|
||||
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 (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(LogImportViewModel viewModel)
|
||||
{
|
||||
var buttonAttributes = new Dictionary<string, object> { { "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.User = DataService.FindUserByUsername(User.Identity.Name);
|
||||
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,
|
||||
"Edit", "Default", "EditPast", "CreateLog",
|
||||
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 (DataService.GetVehicle(log.VehicleId) == null)
|
||||
{
|
||||
return Json(new
|
||||
{
|
||||
Status = ImportStatus.Failure.ToString(),
|
||||
Message = "Vehile with supplied ID does not exist",
|
||||
Action = GetFixLink(viewModel)
|
||||
}, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
// SAVE IT!
|
||||
DataService.AddLog(log);
|
||||
|
||||
var successLink = HtmlHelper.GenerateLink(
|
||||
ControllerContext.RequestContext, RouteTable.Routes,
|
||||
"Edit", "Default", "EditPast", "CreateLog",
|
||||
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(LogImportViewModel viewModel)
|
||||
{
|
||||
try
|
||||
{
|
||||
viewModel.GetLogViewModel();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return RenderRazorViewToString("ImportFix", viewModel);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult ImportFix(LogImportViewModel viewModel)
|
||||
{
|
||||
var createGetLogViewModel = viewModel.GetCreateLogViewModel();
|
||||
createGetLogViewModel.Purpose = new SelectListViewModel
|
||||
{
|
||||
Available = GetPurposeTypesSelectList()
|
||||
};
|
||||
return View("Index", createGetLogViewModel);
|
||||
}
|
||||
|
||||
public ActionResult ImportTemplate()
|
||||
{
|
||||
var template = LogImportTemplateWriter.Write();
|
||||
return File(template, "application/ms-excel", "MileageTraker_ImportTemplate.xls");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -241,6 +241,8 @@ namespace MileageTraker.Web.Controllers
|
||||
return PartialView(new LogPartialDetails(log));
|
||||
}
|
||||
|
||||
#region Import
|
||||
|
||||
public ActionResult ImportUpload()
|
||||
{
|
||||
return View();
|
||||
@@ -414,7 +416,7 @@ namespace MileageTraker.Web.Controllers
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return RenderRazorViewToString("LogImportPartial", viewModel);
|
||||
return RenderRazorViewToString("ImportFix", viewModel);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
@@ -430,5 +432,7 @@ namespace MileageTraker.Web.Controllers
|
||||
var template = LogImportTemplateWriter.Write();
|
||||
return File(template, "application/ms-excel", "MileageTraker_ImportTemplate.xls");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,14 @@
|
||||
if ($logs.length > 0) {
|
||||
var $row = $($logs[0]);
|
||||
var data = $('form', $row).serialize();
|
||||
data += "&userFullName=" + userFullName;
|
||||
var url = $('form', $row).attr('action');
|
||||
if (userFullName != null) {
|
||||
data += "&userFullName=" + userFullName;
|
||||
}
|
||||
$('.import-status', $row).html('<span class="label label-info"><i class="fa fa-spinner fa-spin"></i> Submitting</span');
|
||||
|
||||
$.ajax({
|
||||
url: "/Log/ImportCreate",
|
||||
url: url,
|
||||
type: 'post',
|
||||
data: data,
|
||||
success: function (result) {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using MileageTraker.Web.Attributes;
|
||||
|
||||
namespace MileageTraker.Web.ViewModels.CreateLog
|
||||
{
|
||||
public class ImportUploadViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "XLS Excel File")]
|
||||
public HttpPostedFileBase File { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using MileageTraker.Web.Attributes;
|
||||
|
||||
namespace MileageTraker.Web.ViewModels.Log
|
||||
{
|
||||
public class ImportUploadViewModel
|
||||
public class ImportUploadViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "XLS Excel File")]
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Web.Mvc;
|
||||
using AutoMapper;
|
||||
using MileageTraker.Web.Attributes;
|
||||
using MileageTraker.Web.Utility;
|
||||
using MileageTraker.Web.ViewModels.CreateLog;
|
||||
using MileageTraker.Web.ViewModels.Log;
|
||||
|
||||
namespace MileageTraker.Web.ViewModels
|
||||
@@ -61,6 +62,9 @@ namespace MileageTraker.Web.ViewModels
|
||||
Mapper.CreateMap<LogImportViewModel, LogViewModel>()
|
||||
.ForMember(u => u.LogType, opt => opt.Ignore())
|
||||
.ForMember(u => u.Purpose, opt => opt.Ignore());
|
||||
Mapper.CreateMap<LogImportViewModel, CreateLogViewModel>()
|
||||
.ForMember(u => u.LogType, opt => opt.Ignore())
|
||||
.ForMember(u => u.Purpose, opt => opt.Ignore());
|
||||
Mapper.CreateMap<LogImportViewModel, Models.Log>()
|
||||
.ForMember(u => u.Purpose, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.GasPurchased,
|
||||
@@ -82,6 +86,13 @@ namespace MileageTraker.Web.ViewModels
|
||||
return log;
|
||||
}
|
||||
|
||||
public CreateLogViewModel GetCreateLogViewModel()
|
||||
{
|
||||
var log = new CreateLogViewModel();
|
||||
Mapper.Map(this, log);
|
||||
return log;
|
||||
}
|
||||
|
||||
public Models.Log GetLog()
|
||||
{
|
||||
var log = new Models.Log();
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
@model IList<MileageTraker.Web.ViewModels.LogImportViewModel>
|
||||
|
||||
@{
|
||||
ViewBag.Title = "Import Logs";
|
||||
}
|
||||
@section Styles
|
||||
{
|
||||
<link href="@Url.Content("~/Content/font-awesome.min.css")" rel="stylesheet" type="text/css" />
|
||||
}
|
||||
|
||||
@Html.Partial("_StatusMessage")
|
||||
|
||||
<h2>@ViewBag.Title</h2>
|
||||
|
||||
<p id="page-import-status"></p>
|
||||
|
||||
<table id="logs" class="table table-striped table-bordered table-hover table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Import Status</th>
|
||||
<th style="width:20%"></th>
|
||||
<th>Vehicle ID</th>
|
||||
<th>End Odometer</th>
|
||||
<th>Type</th>
|
||||
<th>Destination City</th>
|
||||
<th>Purpose</th>
|
||||
<th>Notes</th>
|
||||
<th>Gas Purchased</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@for (var i = 0; i < Model.Count; i++)
|
||||
{
|
||||
var viewModel = Model[i];
|
||||
<tr id="log-@i">
|
||||
@using (Html.BeginForm("ImportCreate", "CreateLog", FormMethod.Post))
|
||||
{
|
||||
@Html.EditorFor(x => viewModel)
|
||||
}
|
||||
<td class="import-status"></td>
|
||||
<td class="import-message"></td>
|
||||
<td>@Html.ValueFor(x => viewModel.VehicleId)</td>
|
||||
<td>@Html.ValueFor(x => viewModel.EndOdometer)</td>
|
||||
<td>@Html.ValueFor(x => viewModel.LogType)</td>
|
||||
<td>@Html.ValueFor(x => viewModel.CityName)</td>
|
||||
<td>@Html.ValueFor(x => viewModel.Purpose)</td>
|
||||
<td>@Html.ValueFor(x => viewModel.Notes)</td>
|
||||
<td>@Html.ValueFor(x => viewModel.GasPurchased)</td>
|
||||
<td>@Html.ValueFor(x => viewModel.Date)</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
<script src="@Url.Content("~/Scripts/Shared/ImportCreate.js")" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
importLogs(null);
|
||||
});
|
||||
</script>
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
@model MileageTraker.Web.ViewModels.LogImportViewModel
|
||||
@{
|
||||
Layout = null;
|
||||
}
|
||||
@using (Html.BeginForm("ImportFix", "CreateLog", FormMethod.Post, new{target="_blank"}))
|
||||
{
|
||||
@Html.EditorForModel()
|
||||
<input type="submit" value="Fix" class="btn btn-mini" />
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
@model MileageTraker.Web.ViewModels.CreateLog.ImportUploadViewModel
|
||||
@{
|
||||
ViewBag.Title = "Import Logs";
|
||||
}
|
||||
|
||||
@Html.Partial("_StatusMessage")
|
||||
|
||||
<h2 class="center-content">@ViewBag.Title</h2>
|
||||
|
||||
<p class="center-content">Download the import template: @Html.ActionLink("Excel Template", "ImportTemplate")
|
||||
</p>
|
||||
|
||||
@using (Html.BeginForm("Import", "CreateLog", FormMethod.Post, new { enctype="multipart/form-data", @class = "form-horizontal well center-content", style="max-width:440px"}))
|
||||
{
|
||||
@Html.Partial("_ValidationSummary")
|
||||
@Html.EditorForModel()
|
||||
<div class="form-actions">
|
||||
<input type="submit" value="Import" class="btn btn-primary" />
|
||||
</div>
|
||||
}
|
||||
@@ -23,3 +23,7 @@
|
||||
<div id="RecentLogs" class="center-content well">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="center-content" style="text-align: center">
|
||||
@Html.ActionLink("Import", "ImportUpload", new {}, new { @class = "btn"})
|
||||
</div>
|
||||
@@ -36,7 +36,10 @@
|
||||
{
|
||||
var viewModel = Model[i];
|
||||
<tr id="log-@i">
|
||||
<form>@Html.EditorFor(x => viewModel)</form>
|
||||
@using (Html.BeginForm("ImportCreate", "Log", FormMethod.Post))
|
||||
{
|
||||
@Html.EditorFor(x => viewModel)
|
||||
}
|
||||
<td class="import-status"></td>
|
||||
<td class="import-message"></td>
|
||||
<td>@Html.ValueFor(x => viewModel.VehicleId)</td>
|
||||
|
||||
+24
-20
@@ -25,7 +25,7 @@
|
||||
<IISExpressAnonymousAuthentication />
|
||||
<IISExpressWindowsAuthentication />
|
||||
<IISExpressUseClassicPipelineMode />
|
||||
<AfterAddIisSettingAndFileContentsToSourceManifest>AddSkipRules</AfterAddIisSettingAndFileContentsToSourceManifest>
|
||||
<AfterAddIisSettingAndFileContentsToSourceManifest>AddSkipRules</AfterAddIisSettingAndFileContentsToSourceManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -187,6 +187,7 @@
|
||||
<Compile Include="ViewModels\Account\RegisterModel.cs" />
|
||||
<Compile Include="ViewModels\CheckBoxViewModel.cs" />
|
||||
<Compile Include="ViewModels\CreateLog\EditPastViewModel.cs" />
|
||||
<Compile Include="ViewModels\CreateLog\ImportUploadViewModel.cs" />
|
||||
<Compile Include="ViewModels\DriverMileageItem.cs" />
|
||||
<Compile Include="ViewModels\DriverMileageViewModel.cs" />
|
||||
<Compile Include="ViewModels\LogImportViewModel.cs" />
|
||||
@@ -233,7 +234,7 @@
|
||||
<Content Include="fonts\fontawesome-webfont.ttf" />
|
||||
<Content Include="fonts\fontawesome-webfont.eot" />
|
||||
<Content Include="fonts\FontAwesome.otf" />
|
||||
<Content Include="Views\Log\LogImportPartial.cshtml" />
|
||||
<Content Include="Views\Log\ImportFix.cshtml" />
|
||||
<Content Include="Views\Shared\EditorTemplates\HttpPostedFileBase.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -351,6 +352,9 @@
|
||||
<Content Include="Views\CreateLog\EditPast.cshtml" />
|
||||
<Content Include="Views\Log\Import.cshtml" />
|
||||
<Content Include="Views\Log\ImportUpload.cshtml" />
|
||||
<Content Include="Views\CreateLog\Import.cshtml" />
|
||||
<Content Include="Views\CreateLog\ImportUpload.cshtml" />
|
||||
<Content Include="Views\CreateLog\ImportFix.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="packages.config">
|
||||
@@ -487,24 +491,24 @@
|
||||
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
|
||||
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
|
||||
</Target>
|
||||
<Target Name="AddSkipRules">
|
||||
<ItemGroup>
|
||||
<MsDeploySkipRules Include="SkipDeleteAppData">
|
||||
<SkipAction>Delete</SkipAction>
|
||||
<ObjectName>filePath</ObjectName>
|
||||
<AbsolutePath>$(_Escaped_PackageTempDir)\\App_Data\\.*</AbsolutePath>
|
||||
<XPath>
|
||||
</XPath>
|
||||
</MsDeploySkipRules>
|
||||
<MsDeploySkipRules Include="SkipDeleteAppData">
|
||||
<SkipAction>Delete</SkipAction>
|
||||
<ObjectName>dirPath</ObjectName>
|
||||
<AbsolutePath>$(_Escaped_PackageTempDir)\\App_Data\\.*</AbsolutePath>
|
||||
<XPath>
|
||||
</XPath>
|
||||
</MsDeploySkipRules>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<Target Name="AddSkipRules">
|
||||
<ItemGroup>
|
||||
<MsDeploySkipRules Include="SkipDeleteAppData">
|
||||
<SkipAction>Delete</SkipAction>
|
||||
<ObjectName>filePath</ObjectName>
|
||||
<AbsolutePath>$(_Escaped_PackageTempDir)\\App_Data\\.*</AbsolutePath>
|
||||
<XPath>
|
||||
</XPath>
|
||||
</MsDeploySkipRules>
|
||||
<MsDeploySkipRules Include="SkipDeleteAppData">
|
||||
<SkipAction>Delete</SkipAction>
|
||||
<ObjectName>dirPath</ObjectName>
|
||||
<AbsolutePath>$(_Escaped_PackageTempDir)\\App_Data\\.*</AbsolutePath>
|
||||
<XPath>
|
||||
</XPath>
|
||||
</MsDeploySkipRules>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
|
||||
Reference in New Issue
Block a user