From 8110ee18f1371f57eed4484004cd90e1c459c703 Mon Sep 17 00:00:00 2001 From: "DESKTOP-T0O5CDB\\DESK-555BD" Date: Wed, 8 Jan 2025 14:14:23 -0700 Subject: [PATCH 1/2] Create endpoint to upload documents and add ability to attach uploaded documents to records. --- Controllers/APIController.cs | 59 +++++++++++++++++++++++--- Helper/GasHelper.cs | 6 ++- Models/GasRecord/GasRecordViewModel.cs | 1 + Models/Shared/ImportModel.cs | 16 ++++--- Views/API/Index.cshtml | 35 +++++++++++++++ 5 files changed, 103 insertions(+), 14 deletions(-) diff --git a/Controllers/APIController.cs b/Controllers/APIController.cs index eba424d..27300dc 100644 --- a/Controllers/APIController.cs +++ b/Controllers/APIController.cs @@ -5,6 +5,8 @@ using CarCareTracker.Logic; using CarCareTracker.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Reflection.Metadata; using System.Security.Claims; namespace CarCareTracker.Controllers @@ -34,6 +36,7 @@ namespace CarCareTracker.Controllers private readonly IFileHelper _fileHelper; private readonly IMailHelper _mailHelper; private readonly IConfigHelper _config; + private readonly IWebHostEnvironment _webEnv; public APIController(IVehicleDataAccess dataAccess, IGasHelper gasHelper, IReminderHelper reminderHelper, @@ -55,7 +58,8 @@ namespace CarCareTracker.Controllers IConfigHelper config, IUserLogic userLogic, IVehicleLogic vehicleLogic, - IOdometerLogic odometerLogic) + IOdometerLogic odometerLogic, + IWebHostEnvironment webEnv) { _dataAccess = dataAccess; _noteDataAccess = noteDataAccess; @@ -79,6 +83,7 @@ namespace CarCareTracker.Controllers _vehicleLogic = vehicleLogic; _fileHelper = fileHelper; _config = config; + _webEnv = webEnv; } public IActionResult Index() { @@ -163,7 +168,7 @@ namespace CarCareTracker.Controllers return Json(response); } var vehicleRecords = _serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId); - var result = vehicleRecords.Select(x => new GenericRecordExportModel { Id = x.Id.ToString(), Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString(), ExtraFields = x.ExtraFields, Tags = string.Join(' ', x.Tags) }); + var result = vehicleRecords.Select(x => new GenericRecordExportModel { Id = x.Id.ToString(), Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString(), ExtraFields = x.ExtraFields, Files = x.Files, Tags = string.Join(' ', x.Tags) }); if (_config.GetInvariantApi() || Request.Headers.ContainsKey("culture-invariant")) { return Json(result, StaticHelper.GetInvariantOption()); @@ -206,6 +211,7 @@ namespace CarCareTracker.Controllers Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes, Cost = decimal.Parse(input.Cost), ExtraFields = input.ExtraFields, + Files = input.Files, Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList() }; _serviceRecordDataAccess.SaveServiceRecordToVehicle(serviceRecord); @@ -291,6 +297,7 @@ namespace CarCareTracker.Controllers existingRecord.Description = input.Description; existingRecord.Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes; existingRecord.Cost = decimal.Parse(input.Cost); + existingRecord.Files = input.Files; existingRecord.ExtraFields = input.ExtraFields; existingRecord.Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList(); _serviceRecordDataAccess.SaveServiceRecordToVehicle(existingRecord); @@ -322,7 +329,7 @@ namespace CarCareTracker.Controllers return Json(response); } var vehicleRecords = _collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId); - var result = vehicleRecords.Select(x => new GenericRecordExportModel { Id = x.Id.ToString(), Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString(), ExtraFields = x.ExtraFields, Tags = string.Join(' ', x.Tags) }); + var result = vehicleRecords.Select(x => new GenericRecordExportModel { Id = x.Id.ToString(), Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString(), ExtraFields = x.ExtraFields, Files = x.Files, Tags = string.Join(' ', x.Tags) }); if (_config.GetInvariantApi() || Request.Headers.ContainsKey("culture-invariant")) { return Json(result, StaticHelper.GetInvariantOption()); @@ -366,6 +373,7 @@ namespace CarCareTracker.Controllers Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes, Cost = decimal.Parse(input.Cost), ExtraFields = input.ExtraFields, + Files = input.Files, Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList() }; _collisionRecordDataAccess.SaveCollisionRecordToVehicle(repairRecord); @@ -453,6 +461,7 @@ namespace CarCareTracker.Controllers existingRecord.Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes; existingRecord.Cost = decimal.Parse(input.Cost); existingRecord.ExtraFields = input.ExtraFields; + existingRecord.Files = input.Files; existingRecord.Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList(); _collisionRecordDataAccess.SaveCollisionRecordToVehicle(existingRecord); StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromGenericRecord(existingRecord, "repairrecord.update.api", User.Identity.Name)); @@ -484,7 +493,7 @@ namespace CarCareTracker.Controllers return Json(response); } var vehicleRecords = _upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId); - var result = vehicleRecords.Select(x => new GenericRecordExportModel { Id = x.Id.ToString(), Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString(), ExtraFields = x.ExtraFields, Tags = string.Join(' ', x.Tags) }); + var result = vehicleRecords.Select(x => new GenericRecordExportModel { Id = x.Id.ToString(), Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, Odometer = x.Mileage.ToString(), ExtraFields = x.ExtraFields, Files = x.Files, Tags = string.Join(' ', x.Tags) }); if (_config.GetInvariantApi() || Request.Headers.ContainsKey("culture-invariant")) { return Json(result, StaticHelper.GetInvariantOption()); @@ -528,6 +537,7 @@ namespace CarCareTracker.Controllers Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes, Cost = decimal.Parse(input.Cost), ExtraFields = input.ExtraFields, + Files = input.Files, Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList() }; _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(upgradeRecord); @@ -614,6 +624,7 @@ namespace CarCareTracker.Controllers existingRecord.Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes; existingRecord.Cost = decimal.Parse(input.Cost); existingRecord.ExtraFields = input.ExtraFields; + existingRecord.Files = input.Files; existingRecord.Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList(); _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(existingRecord); StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromGenericRecord(existingRecord, "upgraderecord.update.api", User.Identity.Name)); @@ -644,7 +655,7 @@ namespace CarCareTracker.Controllers Response.StatusCode = 400; return Json(response); } - var result = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId).Select(x => new TaxRecordExportModel { Id = x.Id.ToString(), Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, ExtraFields = x.ExtraFields, Tags = string.Join(' ', x.Tags) }); + var result = _taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId).Select(x => new TaxRecordExportModel { Id = x.Id.ToString(), Date = x.Date.ToShortDateString(), Description = x.Description, Cost = x.Cost.ToString(), Notes = x.Notes, ExtraFields = x.ExtraFields, Files = x.Files, Tags = string.Join(' ', x.Tags) }); if (_config.GetInvariantApi() || Request.Headers.ContainsKey("culture-invariant")) { return Json(result, StaticHelper.GetInvariantOption()); @@ -721,6 +732,7 @@ namespace CarCareTracker.Controllers Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes, Cost = decimal.Parse(input.Cost), ExtraFields = input.ExtraFields, + Files = input.Files, Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList() }; _taxRecordDataAccess.SaveTaxRecordToVehicle(taxRecord); @@ -790,6 +802,7 @@ namespace CarCareTracker.Controllers existingRecord.Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes; existingRecord.Cost = decimal.Parse(input.Cost); existingRecord.ExtraFields = input.ExtraFields; + existingRecord.Files = input.Files; existingRecord.Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList(); _taxRecordDataAccess.SaveTaxRecordToVehicle(existingRecord); StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromTaxRecord(existingRecord, "taxrecord.update.api", User.Identity.Name)); @@ -840,7 +853,7 @@ namespace CarCareTracker.Controllers { vehicleRecords = _odometerLogic.AutoConvertOdometerRecord(vehicleRecords); } - var result = vehicleRecords.Select(x => new OdometerRecordExportModel { Id = x.Id.ToString(), Date = x.Date.ToShortDateString(), InitialOdometer = x.InitialMileage.ToString(), Odometer = x.Mileage.ToString(), Notes = x.Notes, ExtraFields = x.ExtraFields, Tags = string.Join(' ', x.Tags) }); + var result = vehicleRecords.Select(x => new OdometerRecordExportModel { Id = x.Id.ToString(), Date = x.Date.ToShortDateString(), InitialOdometer = x.InitialMileage.ToString(), Odometer = x.Mileage.ToString(), Notes = x.Notes, ExtraFields = x.ExtraFields, Files = x.Files, Tags = string.Join(' ', x.Tags) }); if (_config.GetInvariantApi() || Request.Headers.ContainsKey("culture-invariant")) { return Json(result, StaticHelper.GetInvariantOption()); @@ -881,6 +894,7 @@ namespace CarCareTracker.Controllers InitialMileage = (string.IsNullOrWhiteSpace(input.InitialOdometer) || int.Parse(input.InitialOdometer) == default) ? _odometerLogic.GetLastOdometerRecordMileage(vehicleId, new List()) : int.Parse(input.InitialOdometer), Mileage = int.Parse(input.Odometer), ExtraFields = input.ExtraFields, + Files = input.Files, Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList() }; _odometerRecordDataAccess.SaveOdometerRecordToVehicle(odometerRecord); @@ -948,6 +962,7 @@ namespace CarCareTracker.Controllers existingRecord.InitialMileage = int.Parse(input.InitialOdometer); existingRecord.Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes; existingRecord.ExtraFields = input.ExtraFields; + existingRecord.Files = input.Files; existingRecord.Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList(); _odometerRecordDataAccess.SaveOdometerRecordToVehicle(existingRecord); StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromOdometerRecord(existingRecord, "odometerrecord.update.api", User.Identity.Name)); @@ -991,6 +1006,7 @@ namespace CarCareTracker.Controllers MissedFuelUp = x.MissedFuelUp.ToString(), Notes = x.Notes, ExtraFields = x.ExtraFields, + Files = x.Files, Tags = string.Join(' ', x.Tags) }); if (_config.GetInvariantApi() || Request.Headers.ContainsKey("culture-invariant")) @@ -1179,6 +1195,37 @@ namespace CarCareTracker.Controllers var calendarContent = StaticHelper.RemindersToCalendar(reminders); return File(calendarContent, "text/calendar"); } + [HttpPost] + [Route("/api/documents/upload")] + public IActionResult UploadDocument(List documents) + { + if (documents.Any()) + { + List uploadedFiles = new List(); + string uploadDirectory = "documents/"; + string uploadPath = Path.Combine(_webEnv.ContentRootPath, "data", uploadDirectory); + if (!Directory.Exists(uploadPath)) + Directory.CreateDirectory(uploadPath); + foreach (IFormFile document in documents) + { + string fileName = Guid.NewGuid() + Path.GetExtension(document.FileName); + string filePath = Path.Combine(uploadPath, fileName); + using (var stream = System.IO.File.Create(filePath)) + { + document.CopyTo(stream); + } + uploadedFiles.Add(new UploadedFiles + { + Location = Path.Combine("/", uploadDirectory, fileName), + Name = Path.GetFileName(document.FileName) + }); + } + return Json(uploadedFiles); + } else + { + return Json(OperationResponse.Failed("No files to upload")); + } + } [Authorize(Roles = nameof(UserData.IsRootUser))] [HttpGet] [Route("/api/vehicle/reminders/send")] diff --git a/Helper/GasHelper.cs b/Helper/GasHelper.cs index a7c340f..59d2315 100644 --- a/Helper/GasHelper.cs +++ b/Helper/GasHelper.cs @@ -76,7 +76,8 @@ namespace CarCareTracker.Helper MissedFuelUp = currentObject.MissedFuelUp, Notes = currentObject.Notes, Tags = currentObject.Tags, - ExtraFields = currentObject.ExtraFields + ExtraFields = currentObject.ExtraFields, + Files = currentObject.Files }; if (currentObject.MissedFuelUp) { @@ -130,7 +131,8 @@ namespace CarCareTracker.Helper MissedFuelUp = currentObject.MissedFuelUp, Notes = currentObject.Notes, Tags = currentObject.Tags, - ExtraFields = currentObject.ExtraFields + ExtraFields = currentObject.ExtraFields, + Files = currentObject.Files }); } previousMileage = currentObject.Mileage; diff --git a/Models/GasRecord/GasRecordViewModel.cs b/Models/GasRecord/GasRecordViewModel.cs index a4b3f30..2e90f4d 100644 --- a/Models/GasRecord/GasRecordViewModel.cs +++ b/Models/GasRecord/GasRecordViewModel.cs @@ -23,6 +23,7 @@ public string Notes { get; set; } public List Tags { get; set; } = new List(); public List ExtraFields { get; set; } = new List(); + public List Files { get; set; } = new List(); public bool IncludeInAverage { get { return MilesPerGallon > 0 || (!IsFillToFull && !MissedFuelUp); } } } } diff --git a/Models/Shared/ImportModel.cs b/Models/Shared/ImportModel.cs index 88d9d72..07909c8 100644 --- a/Models/Shared/ImportModel.cs +++ b/Models/Shared/ImportModel.cs @@ -43,7 +43,7 @@ namespace CarCareTracker.Models public string Cost { get; set; } public string Notes { get; set; } public string Tags { get; set; } - public List ExtraFields { get; set; } + public List ExtraFields { get; set; } = new List(); } public class GenericRecordExportModel { @@ -58,7 +58,8 @@ namespace CarCareTracker.Models [JsonConverter(typeof(FromDecimalOptional))] public string Cost { get; set; } public string Tags { get; set; } - public List ExtraFields { get; set; } + public List ExtraFields { get; set; } = new List(); + public List Files { get; set; } = new List(); } public class OdometerRecordExportModel { @@ -72,7 +73,8 @@ namespace CarCareTracker.Models public string Odometer { get; set; } public string Notes { get; set; } public string Tags { get; set; } - public List ExtraFields { get; set; } + public List ExtraFields { get; set; } = new List(); + public List Files { get; set; } = new List(); } public class TaxRecordExportModel { @@ -85,7 +87,8 @@ namespace CarCareTracker.Models [JsonConverter(typeof(FromDecimalOptional))] public string Cost { get; set; } public string Tags { get; set; } - public List ExtraFields { get; set; } + public List ExtraFields { get; set; } = new List(); + public List Files { get; set; } = new List(); } public class GasRecordExportModel { @@ -107,7 +110,8 @@ namespace CarCareTracker.Models public string MissedFuelUp { get; set; } public string Notes { get; set; } public string Tags { get; set; } - public List ExtraFields { get; set; } + public List ExtraFields { get; set; } = new List(); + public List Files { get; set; } = new List(); } public class ReminderExportModel { @@ -130,6 +134,6 @@ namespace CarCareTracker.Models public string Priority { get; set; } public string Progress { get; set; } public string Cost { get; set; } - public List ExtraFields { get; set; } + public List ExtraFields { get; set; } = new List(); } } diff --git a/Views/API/Index.cshtml b/Views/API/Index.cshtml index b46d5aa..f817f1e 100644 --- a/Views/API/Index.cshtml +++ b/Views/API/Index.cshtml @@ -118,6 +118,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -140,6 +141,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -192,6 +194,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -215,6 +218,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -267,6 +271,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -290,6 +295,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -342,6 +348,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -365,6 +372,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -430,6 +438,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -452,6 +461,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -510,6 +520,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -535,6 +546,7 @@ notes - notes(optional)
tags - tags separated by space(optional)
extrafields - extrafields(optional)
+ files - attachments(optional)
} @@ -566,6 +578,22 @@ vehicleId - Id of Vehicle +
+
+ POST +
+
+ /api/documents/upload +
+
+ Upload Documents +
+
+ Body(form-data): {
+ documents[] - Files to Upload
+ } +
+
@if (User.IsInRole(nameof(UserData.IsRootUser))) {
@@ -624,4 +652,11 @@ icon: "info" }); } + function showAttachmentsInfo(){ + Swal.fire({ + title: "Attaching Files", + html: "The Document Upload Endpoint will upload the files and provide a formatted output which you can pass into this method", + icon: "info" + }); + } \ No newline at end of file From 520f47955b4ca052723267501d8c6b5e2b886299 Mon Sep 17 00:00:00 2001 From: "DESKTOP-T0O5CDB\\DESK-555BD" Date: Wed, 8 Jan 2025 14:15:15 -0700 Subject: [PATCH 2/2] cleaned up usings. --- Controllers/APIController.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Controllers/APIController.cs b/Controllers/APIController.cs index 27300dc..b6320fa 100644 --- a/Controllers/APIController.cs +++ b/Controllers/APIController.cs @@ -5,8 +5,6 @@ using CarCareTracker.Logic; using CarCareTracker.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using System.Collections.Generic; -using System.Reflection.Metadata; using System.Security.Claims; namespace CarCareTracker.Controllers