Compare commits

...

6 Commits

Author SHA1 Message Date
Hargata Softworks
b184a1664b
Merge pull request #1167 from hargata/Hargata/all.api.endpoints
add endpoints to retrieve all records from all vehicles the user has …
2025-11-30 11:05:27 -07:00
DESKTOP-T0O5CDB\DESK-555BD
1963fb8134 add endpoints to retrieve all records from all vehicles the user has access to 2025-11-30 11:01:34 -07:00
Hargata Softworks
1d5aeada6d
Merge pull request #1166 from hargata/Hargata/supply.api
add API endpoints for supplies
2025-11-30 09:21:20 -07:00
DESKTOP-T0O5CDB\DESK-555BD
64f25ddcb2 additional patches for access control 2025-11-30 09:19:26 -07:00
DESKTOP-T0O5CDB\DESK-555BD
f5efe96856 fix error message 2025-11-30 09:10:09 -07:00
DESKTOP-T0O5CDB\DESK-555BD
bf8bc6a119 add API endpoints for supplies 2025-11-30 09:05:27 -07:00
7 changed files with 1676 additions and 789 deletions

View File

@ -218,6 +218,57 @@ namespace CarCareTracker.Controllers
}
}
#region PlanRecord
[HttpGet]
[Route("/api/vehicle/planrecords/all")]
public IActionResult AllPlanRecords(MethodParameter parameters)
{
List<int> vehicleIds = new List<int>();
var vehicles = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehicles = _userLogic.FilterUserVehicles(vehicles, GetUserID());
}
vehicleIds.AddRange(vehicles.Select(x=>x.Id));
List<PlanRecord> vehicleRecords = new List<PlanRecord>();
foreach(int vehicleId in vehicleIds)
{
vehicleRecords.AddRange(_planRecordDataAccess.GetPlanRecordsByVehicleId(vehicleId));
}
if (parameters.Id != default)
{
vehicleRecords.RemoveAll(x => x.Id != parameters.Id);
}
if (!string.IsNullOrWhiteSpace(parameters.StartDate) && DateTime.TryParse(parameters.StartDate, out DateTime startDate))
{
vehicleRecords.RemoveAll(x => x.DateCreated < startDate);
}
if (!string.IsNullOrWhiteSpace(parameters.EndDate) && DateTime.TryParse(parameters.EndDate, out DateTime endDate))
{
vehicleRecords.RemoveAll(x => x.DateCreated > endDate);
}
var result = vehicleRecords.Select(x => new PlanRecordExportModel
{
Id = x.Id.ToString(),
DateCreated = x.DateCreated.ToShortDateString(),
DateModified = x.DateModified.ToShortDateString(),
Description = x.Description,
Cost = x.Cost.ToString(),
Notes = x.Notes,
Type = x.ImportMode.ToString(),
Priority = x.Priority.ToString(),
Progress = x.Progress.ToString(),
ExtraFields = x.ExtraFields,
Files = x.Files
});
if (_config.GetInvariantApi() || Request.Headers.ContainsKey("culture-invariant"))
{
return Json(result, StaticHelper.GetInvariantOption());
}
else
{
return Json(result);
}
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpGet]
[Route("/api/vehicle/planrecords")]
@ -451,6 +502,49 @@ namespace CarCareTracker.Controllers
}
#endregion
#region ServiceRecord
[HttpGet]
[Route("/api/vehicle/servicerecords/all")]
public IActionResult AllServiceRecords(MethodParameter parameters)
{
List<int> vehicleIds = new List<int>();
var vehicles = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehicles = _userLogic.FilterUserVehicles(vehicles, GetUserID());
}
vehicleIds.AddRange(vehicles.Select(x => x.Id));
List<ServiceRecord> vehicleRecords = new List<ServiceRecord>();
foreach (int vehicleId in vehicleIds)
{
vehicleRecords.AddRange(_serviceRecordDataAccess.GetServiceRecordsByVehicleId(vehicleId));
}
if (parameters.Id != default)
{
vehicleRecords.RemoveAll(x => x.Id != parameters.Id);
}
if (!string.IsNullOrWhiteSpace(parameters.StartDate) && DateTime.TryParse(parameters.StartDate, out DateTime startDate))
{
vehicleRecords.RemoveAll(x => x.Date < startDate);
}
if (!string.IsNullOrWhiteSpace(parameters.EndDate) && DateTime.TryParse(parameters.EndDate, out DateTime endDate))
{
vehicleRecords.RemoveAll(x => x.Date > endDate);
}
if (!string.IsNullOrWhiteSpace(parameters.Tags))
{
var tagsFilter = parameters.Tags.Split(' ').Distinct();
vehicleRecords.RemoveAll(x => !x.Tags.Any(y => tagsFilter.Contains(y)));
}
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());
}
else
{
return Json(result);
}
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpGet]
[Route("/api/vehicle/servicerecords")]
@ -646,6 +740,49 @@ namespace CarCareTracker.Controllers
}
#endregion
#region RepairRecord
[HttpGet]
[Route("/api/vehicle/repairrecords/all")]
public IActionResult AllRepairRecords(MethodParameter parameters)
{
List<int> vehicleIds = new List<int>();
var vehicles = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehicles = _userLogic.FilterUserVehicles(vehicles, GetUserID());
}
vehicleIds.AddRange(vehicles.Select(x => x.Id));
List<CollisionRecord> vehicleRecords = new List<CollisionRecord>();
foreach (int vehicleId in vehicleIds)
{
vehicleRecords.AddRange(_collisionRecordDataAccess.GetCollisionRecordsByVehicleId(vehicleId));
}
if (parameters.Id != default)
{
vehicleRecords.RemoveAll(x => x.Id != parameters.Id);
}
if (!string.IsNullOrWhiteSpace(parameters.StartDate) && DateTime.TryParse(parameters.StartDate, out DateTime startDate))
{
vehicleRecords.RemoveAll(x => x.Date < startDate);
}
if (!string.IsNullOrWhiteSpace(parameters.EndDate) && DateTime.TryParse(parameters.EndDate, out DateTime endDate))
{
vehicleRecords.RemoveAll(x => x.Date > endDate);
}
if (!string.IsNullOrWhiteSpace(parameters.Tags))
{
var tagsFilter = parameters.Tags.Split(' ').Distinct();
vehicleRecords.RemoveAll(x => !x.Tags.Any(y => tagsFilter.Contains(y)));
}
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());
}
else
{
return Json(result);
}
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpGet]
[Route("/api/vehicle/repairrecords")]
@ -844,6 +981,49 @@ namespace CarCareTracker.Controllers
}
#endregion
#region UpgradeRecord
[HttpGet]
[Route("/api/vehicle/upgraderecords/all")]
public IActionResult AllUpgradeRecords(MethodParameter parameters)
{
List<int> vehicleIds = new List<int>();
var vehicles = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehicles = _userLogic.FilterUserVehicles(vehicles, GetUserID());
}
vehicleIds.AddRange(vehicles.Select(x => x.Id));
List<UpgradeRecord> vehicleRecords = new List<UpgradeRecord>();
foreach (int vehicleId in vehicleIds)
{
vehicleRecords.AddRange(_upgradeRecordDataAccess.GetUpgradeRecordsByVehicleId(vehicleId));
}
if (parameters.Id != default)
{
vehicleRecords.RemoveAll(x => x.Id != parameters.Id);
}
if (!string.IsNullOrWhiteSpace(parameters.StartDate) && DateTime.TryParse(parameters.StartDate, out DateTime startDate))
{
vehicleRecords.RemoveAll(x => x.Date < startDate);
}
if (!string.IsNullOrWhiteSpace(parameters.EndDate) && DateTime.TryParse(parameters.EndDate, out DateTime endDate))
{
vehicleRecords.RemoveAll(x => x.Date > endDate);
}
if (!string.IsNullOrWhiteSpace(parameters.Tags))
{
var tagsFilter = parameters.Tags.Split(' ').Distinct();
vehicleRecords.RemoveAll(x => !x.Tags.Any(y => tagsFilter.Contains(y)));
}
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());
}
else
{
return Json(result);
}
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpGet]
[Route("/api/vehicle/upgraderecords")]
@ -1041,6 +1221,49 @@ namespace CarCareTracker.Controllers
}
#endregion
#region TaxRecord
[HttpGet]
[Route("/api/vehicle/taxrecords/all")]
public IActionResult AllTaxRecords(MethodParameter parameters)
{
List<int> vehicleIds = new List<int>();
var vehicles = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehicles = _userLogic.FilterUserVehicles(vehicles, GetUserID());
}
vehicleIds.AddRange(vehicles.Select(x => x.Id));
List<TaxRecord> vehicleRecords = new List<TaxRecord>();
foreach (int vehicleId in vehicleIds)
{
vehicleRecords.AddRange(_taxRecordDataAccess.GetTaxRecordsByVehicleId(vehicleId));
}
if (parameters.Id != default)
{
vehicleRecords.RemoveAll(x => x.Id != parameters.Id);
}
if (!string.IsNullOrWhiteSpace(parameters.StartDate) && DateTime.TryParse(parameters.StartDate, out DateTime startDate))
{
vehicleRecords.RemoveAll(x => x.Date < startDate);
}
if (!string.IsNullOrWhiteSpace(parameters.EndDate) && DateTime.TryParse(parameters.EndDate, out DateTime endDate))
{
vehicleRecords.RemoveAll(x => x.Date > endDate);
}
if (!string.IsNullOrWhiteSpace(parameters.Tags))
{
var tagsFilter = parameters.Tags.Split(' ').Distinct();
vehicleRecords.RemoveAll(x => !x.Tags.Any(y => tagsFilter.Contains(y)));
}
var result = vehicleRecords.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());
}
else
{
return Json(result);
}
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpGet]
[Route("/api/vehicle/taxrecords")]
@ -1267,6 +1490,49 @@ namespace CarCareTracker.Controllers
var result = _vehicleLogic.GetMaxMileage(vehicleId);
return Json(result);
}
[HttpGet]
[Route("/api/vehicle/odometerrecords/all")]
public IActionResult AllOdometerRecords(MethodParameter parameters)
{
List<int> vehicleIds = new List<int>();
var vehicles = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehicles = _userLogic.FilterUserVehicles(vehicles, GetUserID());
}
vehicleIds.AddRange(vehicles.Select(x => x.Id));
List<OdometerRecord> vehicleRecords = new List<OdometerRecord>();
foreach (int vehicleId in vehicleIds)
{
vehicleRecords.AddRange(_odometerRecordDataAccess.GetOdometerRecordsByVehicleId(vehicleId));
}
if (parameters.Id != default)
{
vehicleRecords.RemoveAll(x => x.Id != parameters.Id);
}
if (!string.IsNullOrWhiteSpace(parameters.StartDate) && DateTime.TryParse(parameters.StartDate, out DateTime startDate))
{
vehicleRecords.RemoveAll(x => x.Date < startDate);
}
if (!string.IsNullOrWhiteSpace(parameters.EndDate) && DateTime.TryParse(parameters.EndDate, out DateTime endDate))
{
vehicleRecords.RemoveAll(x => x.Date > endDate);
}
if (!string.IsNullOrWhiteSpace(parameters.Tags))
{
var tagsFilter = parameters.Tags.Split(' ').Distinct();
vehicleRecords.RemoveAll(x => !x.Tags.Any(y => tagsFilter.Contains(y)));
}
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());
}
else
{
return Json(result);
}
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpGet]
[Route("/api/vehicle/odometerrecords")]
@ -1446,6 +1712,65 @@ namespace CarCareTracker.Controllers
}
#endregion
#region GasRecord
[HttpGet]
[Route("/api/vehicle/gasrecords/all")]
public IActionResult AllGasRecords(MethodParameter parameters)
{
List<int> vehicleIds = new List<int>();
var vehicles = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehicles = _userLogic.FilterUserVehicles(vehicles, GetUserID());
}
vehicleIds.AddRange(vehicles.Select(x => x.Id));
List<GasRecordViewModel> vehicleRecords = new List<GasRecordViewModel>();
foreach (int vehicleId in vehicleIds)
{
var rawVehicleRecords = _gasRecordDataAccess.GetGasRecordsByVehicleId(vehicleId);
vehicleRecords.AddRange(_gasHelper.GetGasRecordViewModels(rawVehicleRecords, parameters.UseMPG, parameters.UseUKMPG));
}
if (parameters.Id != default)
{
vehicleRecords.RemoveAll(x => x.Id != parameters.Id);
}
if (!string.IsNullOrWhiteSpace(parameters.StartDate) && DateTime.TryParse(parameters.StartDate, out DateTime startDate))
{
vehicleRecords.RemoveAll(x => DateTime.Parse(x.Date) < startDate);
}
if (!string.IsNullOrWhiteSpace(parameters.EndDate) && DateTime.TryParse(parameters.EndDate, out DateTime endDate))
{
vehicleRecords.RemoveAll(x => DateTime.Parse(x.Date) > endDate);
}
if (!string.IsNullOrWhiteSpace(parameters.Tags))
{
var tagsFilter = parameters.Tags.Split(' ').Distinct();
vehicleRecords.RemoveAll(x => !x.Tags.Any(y => tagsFilter.Contains(y)));
}
var result = vehicleRecords
.Select(x => new GasRecordExportModel
{
Id = x.Id.ToString(),
Date = x.Date,
Odometer = x.Mileage.ToString(),
Cost = x.Cost.ToString(),
FuelConsumed = x.Gallons.ToString(),
FuelEconomy = x.MilesPerGallon.ToString(),
IsFillToFull = x.IsFillToFull.ToString(),
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"))
{
return Json(result, StaticHelper.GetInvariantOption());
}
else
{
return Json(result);
}
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpGet]
[Route("/api/vehicle/gasrecords")]
@ -1661,7 +1986,324 @@ namespace CarCareTracker.Controllers
}
}
#endregion
#region SupplyRecord
[HttpGet]
[Route("/api/vehicle/supplyrecords/all")]
public IActionResult AllSupplyRecords(MethodParameter parameters)
{
List<int> vehicleIds = new List<int>();
var vehicles = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehicles = _userLogic.FilterUserVehicles(vehicles, GetUserID());
}
vehicleIds.AddRange(vehicles.Select(x => x.Id));
if (_config.GetServerEnableShopSupplies())
{
vehicleIds.Add(0);
}
List<SupplyRecord> vehicleRecords = new List<SupplyRecord>();
foreach (int vehicleId in vehicleIds)
{
vehicleRecords.AddRange(_supplyRecordDataAccess.GetSupplyRecordsByVehicleId(vehicleId));
}
if (parameters.Id != default)
{
vehicleRecords.RemoveAll(x => x.Id != parameters.Id);
}
if (!string.IsNullOrWhiteSpace(parameters.StartDate) && DateTime.TryParse(parameters.StartDate, out DateTime startDate))
{
vehicleRecords.RemoveAll(x => x.Date < startDate);
}
if (!string.IsNullOrWhiteSpace(parameters.EndDate) && DateTime.TryParse(parameters.EndDate, out DateTime endDate))
{
vehicleRecords.RemoveAll(x => x.Date > endDate);
}
if (!string.IsNullOrWhiteSpace(parameters.Tags))
{
var tagsFilter = parameters.Tags.Split(' ').Distinct();
vehicleRecords.RemoveAll(x => !x.Tags.Any(y => tagsFilter.Contains(y)));
}
var result = vehicleRecords
.Select(x => new SupplyRecordExportModel
{
Id = x.Id.ToString(),
Date = x.Date.ToString(),
PartNumber = x.PartNumber,
PartSupplier = x.PartSupplier,
PartQuantity = x.Quantity.ToString(),
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());
}
else
{
return Json(result);
}
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpGet]
[Route("/api/vehicle/supplyrecords")]
public IActionResult SupplyRecords(int vehicleId, MethodParameter parameters)
{
if (vehicleId == default && !_config.GetServerEnableShopSupplies())
{
var response = OperationResponse.Failed("Must provide a valid vehicle id");
Response.StatusCode = 400;
return Json(response);
}
var vehicleRecords = _supplyRecordDataAccess.GetSupplyRecordsByVehicleId(vehicleId);
if (parameters.Id != default)
{
vehicleRecords.RemoveAll(x => x.Id != parameters.Id);
}
if (!string.IsNullOrWhiteSpace(parameters.StartDate) && DateTime.TryParse(parameters.StartDate, out DateTime startDate))
{
vehicleRecords.RemoveAll(x => x.Date < startDate);
}
if (!string.IsNullOrWhiteSpace(parameters.EndDate) && DateTime.TryParse(parameters.EndDate, out DateTime endDate))
{
vehicleRecords.RemoveAll(x => x.Date > endDate);
}
if (!string.IsNullOrWhiteSpace(parameters.Tags))
{
var tagsFilter = parameters.Tags.Split(' ').Distinct();
vehicleRecords.RemoveAll(x => !x.Tags.Any(y => tagsFilter.Contains(y)));
}
var result = vehicleRecords
.Select(x => new SupplyRecordExportModel
{
Id = x.Id.ToString(),
Date = x.Date.ToString(),
PartNumber = x.PartNumber,
PartSupplier = x.PartSupplier,
PartQuantity = x.Quantity.ToString(),
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());
}
else
{
return Json(result);
}
}
[TypeFilter(typeof(CollaboratorFilter), Arguments = new object[] { false, true, HouseholdPermission.Edit })]
[HttpPost]
[Route("/api/vehicle/supplyrecords/add")]
[Consumes("application/json")]
public IActionResult AddSupplyRecordJson(int vehicleId, [FromBody] SupplyRecordExportModel input) => AddSupplyRecord(vehicleId, input);
[TypeFilter(typeof(CollaboratorFilter), Arguments = new object[] { false, true, HouseholdPermission.Edit })]
[HttpPost]
[Route("/api/vehicle/supplyrecords/add")]
public IActionResult AddSupplyRecord(int vehicleId, SupplyRecordExportModel input)
{
if (vehicleId == default && !_config.GetServerEnableShopSupplies())
{
Response.StatusCode = 400;
return Json(OperationResponse.Failed("Must provide a valid vehicle id"));
}
if (string.IsNullOrWhiteSpace(input.Date) ||
string.IsNullOrWhiteSpace(input.Description) ||
string.IsNullOrWhiteSpace(input.PartQuantity) ||
string.IsNullOrWhiteSpace(input.Cost))
{
Response.StatusCode = 400;
return Json(OperationResponse.Failed("Input object invalid, Date, Description, Quantity and Cost cannot be empty."));
}
if (input.Files == null)
{
input.Files = new List<UploadedFiles>();
}
if (input.ExtraFields == null)
{
input.ExtraFields = new List<ExtraField>();
}
try
{
var supplyRecord = new SupplyRecord()
{
VehicleId = vehicleId,
Date = DateTime.Parse(input.Date),
PartNumber = input.PartNumber,
PartSupplier = input.PartSupplier,
Quantity = decimal.Parse(input.PartQuantity),
Description = input.Description,
Cost = decimal.Parse(input.Cost),
Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes,
ExtraFields = input.ExtraFields,
Files = input.Files,
Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List<string>() : input.Tags.Split(' ').Distinct().ToList()
};
_supplyRecordDataAccess.SaveSupplyRecordToVehicle(supplyRecord);
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromSupplyRecord(supplyRecord, "supplyrecord.add.api", User.Identity.Name));
return Json(OperationResponse.Succeed("Supply Record Added", new { recordId = supplyRecord.Id }));
}
catch (Exception ex)
{
Response.StatusCode = 500;
return Json(OperationResponse.Failed(ex.Message));
}
}
[HttpDelete]
[Route("/api/vehicle/supplyrecords/delete")]
public IActionResult DeleteSupplyRecord(int id)
{
var existingRecord = _supplyRecordDataAccess.GetSupplyRecordById(id);
if (existingRecord == null || existingRecord.Id == default)
{
Response.StatusCode = 400;
return Json(OperationResponse.Failed("Invalid Record Id"));
}
//security check.
if (existingRecord.VehicleId != default)
{
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Delete))
{
Response.StatusCode = 401;
return Json(OperationResponse.Failed("Access Denied, you don't have access to this vehicle."));
}
}
else if (!_config.GetServerEnableShopSupplies())
{
//shop supplies not enabled
Response.StatusCode = 401;
return Json(OperationResponse.Failed("Access Denied, shop supplies is not enabled."));
}
var result = _supplyRecordDataAccess.DeleteSupplyRecordById(existingRecord.Id);
if (result)
{
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromSupplyRecord(existingRecord, "supplyrecord.delete.api", User.Identity.Name));
}
return Json(OperationResponse.Conditional(result, "Supply Record Deleted"));
}
[HttpPut]
[Route("/api/vehicle/supplyrecords/update")]
[Consumes("application/json")]
public IActionResult UpdateSupplyRecordJson([FromBody] SupplyRecordExportModel input) => UpdateSupplyRecord(input);
[HttpPut]
[Route("/api/vehicle/supplyrecords/update")]
public IActionResult UpdateSupplyRecord(SupplyRecordExportModel input)
{
if (string.IsNullOrWhiteSpace(input.Id) ||
string.IsNullOrWhiteSpace(input.Date) ||
string.IsNullOrWhiteSpace(input.Description) ||
string.IsNullOrWhiteSpace(input.PartQuantity) ||
string.IsNullOrWhiteSpace(input.Cost))
{
Response.StatusCode = 400;
return Json(OperationResponse.Failed("Input object invalid, Id, Date, Description, Quantity and Cost cannot be empty."));
}
if (input.Files == null)
{
input.Files = new List<UploadedFiles>();
}
if (input.ExtraFields == null)
{
input.ExtraFields = new List<ExtraField>();
}
try
{
//retrieve existing record
var existingRecord = _supplyRecordDataAccess.GetSupplyRecordById(int.Parse(input.Id));
if (existingRecord != null && existingRecord.Id == int.Parse(input.Id))
{
//check if user has access to the vehicleId
if (existingRecord.VehicleId != default)
{
if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit))
{
Response.StatusCode = 401;
return Json(OperationResponse.Failed("Access Denied, you don't have access to this vehicle."));
}
}
else if (!_config.GetServerEnableShopSupplies())
{
//shop supplies not enabled
Response.StatusCode = 401;
return Json(OperationResponse.Failed("Access Denied, shop supplies is not enabled."));
}
existingRecord.Date = DateTime.Parse(input.Date);
existingRecord.PartNumber = input.PartNumber;
existingRecord.PartSupplier = input.PartSupplier;
existingRecord.Quantity = decimal.Parse(input.PartQuantity);
existingRecord.Description = input.Description;
existingRecord.Cost = decimal.Parse(input.Cost);
existingRecord.Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes;
existingRecord.ExtraFields = input.ExtraFields;
existingRecord.Files = input.Files;
existingRecord.Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List<string>() : input.Tags.Split(' ').Distinct().ToList();
_supplyRecordDataAccess.SaveSupplyRecordToVehicle(existingRecord);
StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromSupplyRecord(existingRecord, "supplyrecord.update.api", User.Identity.Name));
}
else
{
Response.StatusCode = 400;
return Json(OperationResponse.Failed("Invalid Record Id"));
}
return Json(OperationResponse.Succeed("Supply Record Updated"));
}
catch (Exception ex)
{
Response.StatusCode = 500;
return Json(OperationResponse.Failed(ex.Message));
}
}
#endregion
#region ReminderRecord
[HttpGet]
[Route("/api/vehicle/reminders/all")]
public IActionResult AllReminders(List<ReminderUrgency> urgencies, string tags)
{
List<int> vehicleIds = new List<int>();
var vehicles = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehicles = _userLogic.FilterUserVehicles(vehicles, GetUserID());
}
vehicleIds.AddRange(vehicles.Select(x => x.Id));
List<ReminderRecordViewModel> reminderResults = new List<ReminderRecordViewModel>();
foreach (int vehicleId in vehicleIds)
{
var currentMileage = _vehicleLogic.GetMaxMileage(vehicleId);
var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId);
reminderResults.AddRange(_reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now));
}
if (!urgencies.Any())
{
//if no urgencies parameter, we will default to all urgencies.
urgencies = new List<ReminderUrgency> { ReminderUrgency.NotUrgent, ReminderUrgency.Urgent, ReminderUrgency.VeryUrgent, ReminderUrgency.PastDue };
}
reminderResults.RemoveAll(x => !urgencies.Contains(x.Urgency));
if (!string.IsNullOrWhiteSpace(tags))
{
var tagsFilter = tags.Split(' ').Distinct();
reminderResults.RemoveAll(x => !x.Tags.Any(y => tagsFilter.Contains(y)));
}
var results = reminderResults.Select(x => new ReminderAPIExportModel { Id = x.Id.ToString(), Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), UserMetric = x.UserMetric.ToString(), Notes = x.Notes, DueDate = x.Date.ToShortDateString(), DueOdometer = x.Mileage.ToString(), DueDays = x.DueDays.ToString(), DueDistance = x.DueMileage.ToString(), Tags = string.Join(' ', x.Tags) });
if (_config.GetInvariantApi() || Request.Headers.ContainsKey("culture-invariant"))
{
return Json(results, StaticHelper.GetInvariantOption());
}
else
{
return Json(results);
}
}
[TypeFilter(typeof(CollaboratorFilter))]
[HttpGet]
[Route("/api/vehicle/reminders")]

View File

@ -153,6 +153,10 @@ namespace CarCareTracker.Controllers
return Json(OperationResponse.Failed("Access Denied"));
}
}
else if (!_config.GetServerEnableShopSupplies())
{
return Json(OperationResponse.Failed("Access Denied"));
}
//move files from temp.
supplyRecord.Files = supplyRecord.Files.Select(x => { return new UploadedFiles { Name = x.Name, Location = _fileHelper.MoveFileFromTemp(x.Location, "documents/") }; }).ToList();
var result = _supplyRecordDataAccess.SaveSupplyRecordToVehicle(supplyRecord.ToSupplyRecord());
@ -179,6 +183,10 @@ namespace CarCareTracker.Controllers
return Redirect("/Error/Unauthorized");
}
}
else if (!_config.GetServerEnableShopSupplies())
{
return Redirect("/Error/Unauthorized");
}
if (result.RequisitionHistory.Any())
{
//requisition history when viewed through the supply is always immutable.
@ -214,6 +222,10 @@ namespace CarCareTracker.Controllers
return OperationResponse.Failed("Access Denied");
}
}
else if (!_config.GetServerEnableShopSupplies())
{
return OperationResponse.Failed("Access Denied");
}
var result = _supplyRecordDataAccess.DeleteSupplyRecordById(existingRecord.Id);
if (result)
{

View File

@ -937,7 +937,7 @@ namespace CarCareTracker.Helper
}
public static bool IsShopSupplyEndpoint(string endpoint)
{
var shopSupplyEndpoints = new List<string> { "ImportToVehicleIdFromCsv", "GetSupplyRecordsByVehicleId", "ExportFromVehicleToCsv", "DuplicateRecordsToOtherVehicles", "PrintRecordStickers" };
var shopSupplyEndpoints = new List<string> { "ImportToVehicleIdFromCsv", "GetSupplyRecordsByVehicleId", "ExportFromVehicleToCsv", "DuplicateRecordsToOtherVehicles", "PrintRecordStickers", "SupplyRecords", "AddSupplyRecord", "AddSupplyRecordJson" };
return shopSupplyEndpoints.Contains(endpoint);
}
}

View File

@ -35,15 +35,21 @@ namespace CarCareTracker.Models
public class SupplyRecordExportModel
{
[JsonConverter(typeof(FromIntOptional))]
public string Id { get; set; }
[JsonConverter(typeof(FromDateOptional))]
public string Date { get; set; }
public string PartNumber { get; set; }
public string PartSupplier { get; set; }
[JsonConverter(typeof(FromDecimalOptional))]
public string PartQuantity { get; set; }
public string Description { get; set; }
[JsonConverter(typeof(FromDecimalOptional))]
public string Cost { get; set; }
public string Notes { get; set; }
public string Tags { get; set; }
public List<ExtraField> ExtraFields { get; set; } = new List<ExtraField>();
public List<UploadedFiles> Files { get; set; } = new List<UploadedFiles>();
}
public class GenericRecordExportModel
{

View File

@ -104,6 +104,20 @@
odometer - Unadjusted odometer
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/odometerrecords/all</code>
</div>
<div class="col-3">
Returns a list of odometer records for all vehicles in the garage
</div>
<div class="col-3">
No Params
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
@ -193,6 +207,20 @@
Id - Id of Odometer Record
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/planrecords/all</code>
</div>
<div class="col-3">
Returns a list of plan records for all vehicles in the garage
</div>
<div class="col-3">
No Params
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
@ -270,6 +298,20 @@
Id - Id of Plan Record
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/servicerecords/all</code>
</div>
<div class="col-3">
Returns a list of service records for all vehicles in the garage
</div>
<div class="col-3">
No Params
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
@ -347,6 +389,20 @@
Id - Id of Service Record
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/repairrecords/all</code>
</div>
<div class="col-3">
Returns a list of repair records for all vehicles in the garage
</div>
<div class="col-3">
No Params
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
@ -424,6 +480,20 @@
Id - Id of Repair Record
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/upgraderecords/all</code>
</div>
<div class="col-3">
Returns a list of upgrade records for all vehicles in the garage
</div>
<div class="col-3">
No Params
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
@ -501,6 +571,115 @@
Id - Id of Upgrade Record
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/supplyrecords/all</code>
</div>
<div class="col-3">
Returns a list of supply records for all vehicles in the garage
</div>
<div class="col-3">
No Params
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/supplyrecords</code>
</div>
<div class="col-3">
Returns a list of supply records for the vehicle
</div>
<div class="col-3">
vehicleId - Id of Vehicle
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-primary">POST</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/supplyrecords/add</code>
</div>
<div class="col-3">
Adds Supply Record to the vehicle
</div>
<div class="col-3">
vehicleId - Id of Vehicle
<br />
Body(form-data): {<br />
date - Date to be entered<br />
partNumber - Part number(optional)<br />
partSupplier - Part supplier(optional)<br />
partQuantity - Part quantity<br />
description - Description<br />
cost - Cost<br />
notes - notes(optional)<br />
tags - tags separated by space(optional)<br />
extrafields - <a class="link-body-emphasis link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover reminder-calendar-item" onclick="showExtraFieldsInfo()">extrafields(optional)</a><br />
files - <a class="link-body-emphasis link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover reminder-calendar-item" onclick="showAttachmentsInfo()">attachments(optional)</a><br />
}
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge text-bg-warning">PUT</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/supplyrecords/update</code>
</div>
<div class="col-3">
Updates Supply Record
</div>
<div class="col-3">
Body(form-data): {<br />
Id - Id of Supply Record<br />
date - Date to be entered<br />
partNumber - Part number(optional)<br />
partSupplier - Part supplier(optional)<br />
partQuantity - Part quantity<br />
description - Description<br />
cost - Cost<br />
notes - notes(optional)<br />
tags - tags separated by space(optional)<br />
extrafields - <a class="link-body-emphasis link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover reminder-calendar-item" onclick="showExtraFieldsInfo()">extrafields(optional)</a><br />
files - <a class="link-body-emphasis link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover reminder-calendar-item" onclick="showAttachmentsInfo()">attachments(optional)</a><br />
}
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge text-bg-danger">DELETE</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/supplyrecords/delete</code>
</div>
<div class="col-3">
Deletes Supply Record
</div>
<div class="col-3">
Id - Id of Supply Record
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/taxrecords/all</code>
</div>
<div class="col-3">
Returns a list of tax records for all vehicles in the garage
</div>
<div class="col-3">
No Params
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
@ -590,6 +769,22 @@
Id - Id of Tax Record
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/gasrecords/all</code>
</div>
<div class="col-3">
Returns a list of gas records for all vehicles in the garage
</div>
<div class="col-3">
useMPG(bool) - Use Imperial Units and Calculation
<br />
useUKMPG(bool) - Use UK Imperial Calculation
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
@ -675,6 +870,21 @@
Id - Id of Gas Record
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
</div>
<div class="col-5 copyable">
<code>/api/vehicle/reminders/all</code>
</div>
<div class="col-3">
Returns a list of reminders for all vehicles in the garage
</div>
<div class="col-3">
urgencies[]=[NotUrgent,Urgent,VeryUrgent,PastDue](optional)<br />
tags - tags separated by space(optional)
</div>
</div>
<div class="row api-method">
<div class="col-1">
<span class="badge bg-success">GET</span>
@ -686,7 +896,9 @@
Returns a list of reminders for the vehicle
</div>
<div class="col-3">
vehicleId - Id of Vehicle
vehicleId - Id of Vehicle<br />
urgencies[]=[NotUrgent,Urgent,VeryUrgent,PastDue](optional)<br />
tags - tags separated by space(optional)
</div>
</div>
<div class="row api-method">

View File

@ -40,7 +40,7 @@
kioskWakeLock = wl;
});
} catch (err) {
errorToast('Location Services not Enabled');
warnToast('Wake Lock Not Acquired');
}
}
function setAccessToken(accessToken){

View File

@ -51,6 +51,21 @@ function infoToast(message) {
}
})
}
function warnToast(message) {
Swal.fire({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
title: message,
timerProgressBar: true,
icon: "warning",
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
})
}
function viewVehicle(vehicleId) {
window.location.href = `/Vehicle/Index?vehicleId=${vehicleId}`;
}