From 6065c14f3b2327367727626d2fa93416dabb586b Mon Sep 17 00:00:00 2001 From: "DESKTOP-T0O5CDB\\DESK-555BD" Date: Thu, 13 Nov 2025 07:42:08 -0700 Subject: [PATCH] add role check in bulk actions. --- Controllers/Vehicle/GasController.cs | 7 +- Controllers/Vehicle/ImportController.cs | 6 +- Controllers/VehicleController.cs | 126 +++++++++++++++++++++--- Filter/CollaboratorFilter.cs | 56 +++++++---- Filter/StrictCollaboratorFilter.cs | 5 +- Helper/StaticHelper.cs | 5 + Logic/UserLogic.cs | 25 ++--- Views/Vehicle/_BulkDataImporter.cshtml | 5 +- wwwroot/js/gasrecord.js | 4 +- wwwroot/js/shared.js | 32 +++--- wwwroot/js/vehicle.js | 12 +-- 11 files changed, 205 insertions(+), 78 deletions(-) diff --git a/Controllers/Vehicle/GasController.cs b/Controllers/Vehicle/GasController.cs index 8f8d8fb..46e29aa 100644 --- a/Controllers/Vehicle/GasController.cs +++ b/Controllers/Vehicle/GasController.cs @@ -163,6 +163,11 @@ namespace CarCareTracker.Controllers foreach (int recordId in editModel.RecordIds) { var existingRecord = _gasRecordDataAccess.GetGasRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } if (dateIsEdited) { existingRecord.Date = editModel.EditRecord.Date; @@ -205,7 +210,7 @@ namespace CarCareTracker.Controllers } result = _gasRecordDataAccess.SaveGasRecordToVehicle(existingRecord); } - return Json(result); + return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage)); } } } diff --git a/Controllers/Vehicle/ImportController.cs b/Controllers/Vehicle/ImportController.cs index c16907a..b95a6b7 100644 --- a/Controllers/Vehicle/ImportController.cs +++ b/Controllers/Vehicle/ImportController.cs @@ -186,7 +186,7 @@ namespace CarCareTracker.Controllers return Json(OperationResponse.Failed($"An error has occurred while generating CSV sample: {ex.Message}")); } } - [TypeFilter(typeof(CollaboratorFilter))] + [TypeFilter(typeof(CollaboratorFilter), Arguments = new object[] { false, true, HouseholdPermission.View })] [HttpGet] public IActionResult ExportFromVehicleToCsv(int vehicleId, ImportMode mode) { @@ -408,9 +408,9 @@ namespace CarCareTracker.Controllers } return Json($"/{fileNameToExport}"); } - return Json(false); + return Json(OperationResponse.Failed(StaticHelper.GenericErrorMessage)); } - [TypeFilter(typeof(CollaboratorFilter))] + [TypeFilter(typeof(CollaboratorFilter), Arguments = new object[] { false, true, HouseholdPermission.Edit })] [HttpPost] public IActionResult ImportToVehicleIdFromCsv(int vehicleId, ImportMode mode, string fileName) { diff --git a/Controllers/VehicleController.cs b/Controllers/VehicleController.cs index 5d2b40b..2f69b63 100644 --- a/Controllers/VehicleController.cs +++ b/Controllers/VehicleController.cs @@ -126,7 +126,7 @@ namespace CarCareTracker.Controllers { if (!_userLogic.UserCanEditVehicle(GetUserID(), vehicleInput.Id, HouseholdPermission.Edit)) { - return View("401"); + return Json(OperationResponse.Failed("Access Denied")); } } //move image from temp folder to images folder. @@ -143,12 +143,12 @@ namespace CarCareTracker.Controllers { StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.Generic($"Updated Vehicle {vehicleInput.Year} {vehicleInput.Make} {vehicleInput.Model}({StaticHelper.GetVehicleIdentifier(vehicleInput)})", "vehicle.update", User.Identity.Name, vehicleInput.Id.ToString())); } - return Json(result); + return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage)); } catch (Exception ex) { _logger.LogError(ex, "Error Saving Vehicle"); - return Json(false); + return Json(OperationResponse.Failed(StaticHelper.GenericErrorMessage)); } } [HttpPost] @@ -206,7 +206,7 @@ namespace CarCareTracker.Controllers } results.Add(result); } - return Json(OperationResponse.Conditional(results.Any() && results.All(x => x), "", StaticHelper.GenericErrorMessage)); + return Json(OperationResponse.Conditional(results.Any() && results.All(x => x), string.Empty, StaticHelper.GenericErrorMessage)); } [HttpPost] [TypeFilter(typeof(StrictCollaboratorFilter), Arguments = new object[] { true, true })] @@ -631,6 +631,11 @@ namespace CarCareTracker.Controllers genericRecord = _upgradeRecordDataAccess.GetUpgradeRecordById(recordId); break; } + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), genericRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } //save switch (destination) { @@ -681,6 +686,11 @@ namespace CarCareTracker.Controllers genericRecord = _upgradeRecordDataAccess.GetUpgradeRecordById(recordId); break; } + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), genericRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } //save switch (destination) { @@ -715,7 +725,7 @@ namespace CarCareTracker.Controllers { StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.Generic($"Moved multiple {source.ToString()} to {destination.ToString()} - Ids: {string.Join(",", recordIds)}", "bulk.move", User.Identity.Name, string.Empty)); } - return Json(result); + return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage)); } public IActionResult DeleteRecords(List recordIds, ImportMode importMode) { @@ -762,8 +772,8 @@ namespace CarCareTracker.Controllers } return Json(result); } - [TypeFilter(typeof(CollaboratorFilter))] [HttpPost] + [TypeFilter(typeof(CollaboratorFilter), Arguments = new object[] {false, true, HouseholdPermission.Edit})] public IActionResult AdjustRecordsOdometer(List recordIds, int vehicleId, ImportMode importMode) { bool result = false; @@ -819,7 +829,7 @@ namespace CarCareTracker.Controllers { StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.Generic($"Adjusted odometer for multiple {importMode.ToString()} - Ids: {string.Join(",", recordIds)}", "bulk.odometer.adjust", User.Identity.Name, string.Empty)); } - return Json(result); + return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage)); } [HttpPost] public IActionResult DuplicateRecords(List recordIds, ImportMode importMode) @@ -832,6 +842,11 @@ namespace CarCareTracker.Controllers case ImportMode.ServiceRecord: { var existingRecord = _serviceRecordDataAccess.GetServiceRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; existingRecord.RequisitionHistory = new List(); result = _serviceRecordDataAccess.SaveServiceRecordToVehicle(existingRecord); @@ -840,6 +855,11 @@ namespace CarCareTracker.Controllers case ImportMode.RepairRecord: { var existingRecord = _collisionRecordDataAccess.GetCollisionRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; existingRecord.RequisitionHistory = new List(); result = _collisionRecordDataAccess.SaveCollisionRecordToVehicle(existingRecord); @@ -848,6 +868,11 @@ namespace CarCareTracker.Controllers case ImportMode.UpgradeRecord: { var existingRecord = _upgradeRecordDataAccess.GetUpgradeRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; existingRecord.RequisitionHistory = new List(); result = _upgradeRecordDataAccess.SaveUpgradeRecordToVehicle(existingRecord); @@ -856,6 +881,11 @@ namespace CarCareTracker.Controllers case ImportMode.GasRecord: { var existingRecord = _gasRecordDataAccess.GetGasRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; result = _gasRecordDataAccess.SaveGasRecordToVehicle(existingRecord); } @@ -863,6 +893,11 @@ namespace CarCareTracker.Controllers case ImportMode.TaxRecord: { var existingRecord = _taxRecordDataAccess.GetTaxRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; result = _taxRecordDataAccess.SaveTaxRecordToVehicle(existingRecord); } @@ -870,6 +905,11 @@ namespace CarCareTracker.Controllers case ImportMode.SupplyRecord: { var existingRecord = _supplyRecordDataAccess.GetSupplyRecordById(recordId); + //security check if not shop supply + if (existingRecord.VehicleId != default && !_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; existingRecord.RequisitionHistory = new List(); result = _supplyRecordDataAccess.SaveSupplyRecordToVehicle(existingRecord); @@ -878,6 +918,11 @@ namespace CarCareTracker.Controllers case ImportMode.NoteRecord: { var existingRecord = _noteDataAccess.GetNoteById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; result = _noteDataAccess.SaveNoteToVehicle(existingRecord); } @@ -885,6 +930,11 @@ namespace CarCareTracker.Controllers case ImportMode.OdometerRecord: { var existingRecord = _odometerRecordDataAccess.GetOdometerRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; result = _odometerRecordDataAccess.SaveOdometerRecordToVehicle(existingRecord); } @@ -892,6 +942,11 @@ namespace CarCareTracker.Controllers case ImportMode.ReminderRecord: { var existingRecord = _reminderRecordDataAccess.GetReminderRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; result = _reminderRecordDataAccess.SaveReminderRecordToVehicle(existingRecord); } @@ -899,6 +954,11 @@ namespace CarCareTracker.Controllers case ImportMode.PlanRecord: { var existingRecord = _planRecordDataAccess.GetPlanRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; existingRecord.ReminderRecordId = default; existingRecord.RequisitionHistory = new List(); @@ -908,6 +968,11 @@ namespace CarCareTracker.Controllers case ImportMode.InspectionRecord: { var existingRecord = _inspectionRecordTemplateDataAccess.GetInspectionRecordTemplateById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } existingRecord.Id = default; existingRecord.ReminderRecordId = new List(); result = _inspectionRecordTemplateDataAccess.SaveInspectionReportTemplateToVehicle(existingRecord); @@ -919,9 +984,10 @@ namespace CarCareTracker.Controllers { StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.Generic($"Duplicated multiple {importMode.ToString()} - Ids: {string.Join(",", recordIds)}", "bulk.duplicate", User.Identity.Name, string.Empty)); } - return Json(result); + return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage)); } [HttpPost] + [TypeFilter(typeof(CollaboratorFilter), Arguments = new object[] { true, true, HouseholdPermission.Edit })] public IActionResult DuplicateRecordsToOtherVehicles(List recordIds, List vehicleIds, ImportMode importMode) { bool result = false; @@ -1066,7 +1132,7 @@ namespace CarCareTracker.Controllers { StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.Generic($"Duplicated multiple {importMode.ToString()} - Ids: {string.Join(",", recordIds)} - to Vehicle Ids: {string.Join(",", vehicleIds)}", "bulk.duplicate.to.vehicles", User.Identity.Name, string.Join(",", vehicleIds))); } - return Json(result); + return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage)); } [HttpPost] public IActionResult BulkCreateOdometerRecords(List recordIds, ImportMode importMode) @@ -1079,6 +1145,11 @@ namespace CarCareTracker.Controllers case ImportMode.ServiceRecord: { var existingRecord = _serviceRecordDataAccess.GetServiceRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } result = _odometerLogic.AutoInsertOdometerRecord(new OdometerRecord { Date = existingRecord.Date, @@ -1092,6 +1163,11 @@ namespace CarCareTracker.Controllers case ImportMode.RepairRecord: { var existingRecord = _collisionRecordDataAccess.GetCollisionRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } result = _odometerLogic.AutoInsertOdometerRecord(new OdometerRecord { Date = existingRecord.Date, @@ -1105,6 +1181,11 @@ namespace CarCareTracker.Controllers case ImportMode.UpgradeRecord: { var existingRecord = _upgradeRecordDataAccess.GetUpgradeRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } result = _odometerLogic.AutoInsertOdometerRecord(new OdometerRecord { Date = existingRecord.Date, @@ -1118,6 +1199,11 @@ namespace CarCareTracker.Controllers case ImportMode.GasRecord: { var existingRecord = _gasRecordDataAccess.GetGasRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } result = _odometerLogic.AutoInsertOdometerRecord(new OdometerRecord { Date = existingRecord.Date, @@ -1134,7 +1220,7 @@ namespace CarCareTracker.Controllers { StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.Generic($"Created Odometer Records based on {importMode.ToString()} - Ids: {string.Join(",", recordIds)}", "bulk.odometer.insert", User.Identity.Name, string.Empty)); } - return Json(result); + return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage)); } [HttpPost] public IActionResult GetGenericRecordModal(List recordIds, ImportMode dataType) @@ -1169,6 +1255,11 @@ namespace CarCareTracker.Controllers case ImportMode.ServiceRecord: { var existingRecord = _serviceRecordDataAccess.GetServiceRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } if (dateIsEdited) { existingRecord.Date = genericRecordEditModel.EditRecord.Date; @@ -1215,6 +1306,11 @@ namespace CarCareTracker.Controllers case ImportMode.RepairRecord: { var existingRecord = _collisionRecordDataAccess.GetCollisionRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } if (dateIsEdited) { existingRecord.Date = genericRecordEditModel.EditRecord.Date; @@ -1261,6 +1357,11 @@ namespace CarCareTracker.Controllers case ImportMode.UpgradeRecord: { var existingRecord = _upgradeRecordDataAccess.GetUpgradeRecordById(recordId); + //security check + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId, HouseholdPermission.Edit)) + { + return Json(OperationResponse.Failed("Access Denied")); + } if (dateIsEdited) { existingRecord.Date = genericRecordEditModel.EditRecord.Date; @@ -1306,9 +1407,10 @@ namespace CarCareTracker.Controllers break; } } - return Json(result); + return Json(OperationResponse.Conditional(result, string.Empty, StaticHelper.GenericErrorMessage)); } [HttpPost] + [TypeFilter(typeof(CollaboratorFilter), Arguments = new object[] { false, true, HouseholdPermission.View })] public IActionResult PrintRecordStickers(int vehicleId, List recordIds, ImportMode importMode) { bool result = false; @@ -1475,7 +1577,7 @@ namespace CarCareTracker.Controllers { return PartialView("_Stickers", stickerViewModel); } - return Json(result); + return Json(OperationResponse.Failed(StaticHelper.GenericErrorMessage)); } [HttpPost] public IActionResult SaveUserColumnPreferences(UserColumnPreference columnPreference) diff --git a/Filter/CollaboratorFilter.cs b/Filter/CollaboratorFilter.cs index a0f40d1..f871701 100644 --- a/Filter/CollaboratorFilter.cs +++ b/Filter/CollaboratorFilter.cs @@ -11,42 +11,58 @@ namespace CarCareTracker.Filter { private readonly IUserLogic _userLogic; private readonly IConfigHelper _config; - public CollaboratorFilter(IUserLogic userLogic, IConfigHelper config) { + private readonly bool _multiple; + private readonly bool _jsonResponse; + private readonly HouseholdPermission _permission; + public CollaboratorFilter(IUserLogic userLogic, IConfigHelper config, bool? multiple = false, bool? jsonResponse = false, HouseholdPermission? permission = HouseholdPermission.View) { _userLogic = userLogic; _config = config; + _multiple = multiple ?? false; ; + _jsonResponse = jsonResponse ?? false; + _permission = permission ?? HouseholdPermission.View; } public override void OnActionExecuting(ActionExecutingContext filterContext) { if (!filterContext.HttpContext.User.IsInRole(nameof(UserData.IsRootUser))) { - if (filterContext.ActionArguments.ContainsKey("vehicleId")) + List vehicleIds = new List(); + if (!_multiple && filterContext.ActionArguments.ContainsKey("vehicleId")) { - var vehicleId = int.Parse(filterContext.ActionArguments["vehicleId"].ToString()); - if (vehicleId != default) + vehicleIds.Add(int.Parse(filterContext.ActionArguments["vehicleId"].ToString())); + } + else if (_multiple && filterContext.ActionArguments.ContainsKey("vehicleIds")) + { + vehicleIds.AddRange(filterContext.ActionArguments["vehicleIds"] as List); + } + if (vehicleIds.Any()) + { + foreach(int vehicleId in vehicleIds) { - var userId = int.Parse(filterContext.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier)); - if (!_userLogic.UserCanEditVehicle(userId, vehicleId, HouseholdPermission.View)) + if (vehicleId != default) { - filterContext.Result = new RedirectResult("/Error/Unauthorized"); + var userId = int.Parse(filterContext.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier)); + if (!_userLogic.UserCanEditVehicle(userId, vehicleId, _permission)) + { + filterContext.Result = _jsonResponse ? new JsonResult(OperationResponse.Failed("Access Denied")) : new RedirectResult("/Error/Unauthorized"); + } } - } - else - { - var shopSupplyEndpoints = new List { "ImportToVehicleIdFromCsv", "GetSupplyRecordsByVehicleId", "ExportFromVehicleToCsv" }; - if (shopSupplyEndpoints.Contains(filterContext.RouteData.Values["action"].ToString()) && !_config.GetServerEnableShopSupplies()) + else { - //user trying to access shop supplies but shop supplies is not enabled by root user. - filterContext.Result = new RedirectResult("/Error/Unauthorized"); - } - else if (!shopSupplyEndpoints.Contains(filterContext.RouteData.Values["action"].ToString())) - { - //user trying to access any other endpoints using 0 as vehicle id. - filterContext.Result = new RedirectResult("/Error/Unauthorized"); + if (StaticHelper.IsShopSupplyEndpoint(filterContext.RouteData.Values["action"].ToString()) && !_config.GetServerEnableShopSupplies()) + { + //user trying to access shop supplies but shop supplies is not enabled by root user. + filterContext.Result = _jsonResponse ? new JsonResult(OperationResponse.Failed("Access Denied")) : new RedirectResult("/Error/Unauthorized"); + } + else if (!StaticHelper.IsShopSupplyEndpoint(filterContext.RouteData.Values["action"].ToString())) + { + //user trying to access any other endpoints using 0 as vehicle id. + filterContext.Result = _jsonResponse ? new JsonResult(OperationResponse.Failed("Access Denied")) : new RedirectResult("/Error/Unauthorized"); + } } } } else { - filterContext.Result = new RedirectResult("/Error/Unauthorized"); + filterContext.Result = _jsonResponse ? new JsonResult(OperationResponse.Failed("Access Denied")) : new RedirectResult("/Error/Unauthorized"); } } } diff --git a/Filter/StrictCollaboratorFilter.cs b/Filter/StrictCollaboratorFilter.cs index 5746543..37a1b43 100644 --- a/Filter/StrictCollaboratorFilter.cs +++ b/Filter/StrictCollaboratorFilter.cs @@ -47,13 +47,12 @@ namespace CarCareTracker.Filter } else { - var shopSupplyEndpoints = new List { "ImportToVehicleIdFromCsv", "GetSupplyRecordsByVehicleId", "ExportFromVehicleToCsv" }; - if (shopSupplyEndpoints.Contains(filterContext.RouteData.Values["action"].ToString()) && !_config.GetServerEnableShopSupplies()) + if (StaticHelper.IsShopSupplyEndpoint(filterContext.RouteData.Values["action"].ToString()) && !_config.GetServerEnableShopSupplies()) { //user trying to access shop supplies but shop supplies is not enabled by root user. filterContext.Result = _jsonResponse ? new JsonResult(OperationResponse.Failed("Access Denied")) : new RedirectResult("/Error/Unauthorized"); } - else if (!shopSupplyEndpoints.Contains(filterContext.RouteData.Values["action"].ToString())) + else if (!StaticHelper.IsShopSupplyEndpoint(filterContext.RouteData.Values["action"].ToString())) { //user trying to access any other endpoints using 0 as vehicle id. filterContext.Result = _jsonResponse ? new JsonResult(OperationResponse.Failed("Access Denied")) : new RedirectResult("/Error/Unauthorized"); diff --git a/Helper/StaticHelper.cs b/Helper/StaticHelper.cs index 65ef7fa..6f1abac 100644 --- a/Helper/StaticHelper.cs +++ b/Helper/StaticHelper.cs @@ -935,5 +935,10 @@ namespace CarCareTracker.Helper return Convert.ToDecimal(goodNormalizedStep * stepPower); } + public static bool IsShopSupplyEndpoint(string endpoint) + { + var shopSupplyEndpoints = new List { "ImportToVehicleIdFromCsv", "GetSupplyRecordsByVehicleId", "ExportFromVehicleToCsv", "DuplicateRecordsToOtherVehicles", "PrintRecordStickers" }; + return shopSupplyEndpoints.Contains(endpoint); + } } } diff --git a/Logic/UserLogic.cs b/Logic/UserLogic.cs index bd86c7b..ec4768c 100644 --- a/Logic/UserLogic.cs +++ b/Logic/UserLogic.cs @@ -144,26 +144,19 @@ namespace CarCareTracker.Logic } public bool UserCanEditVehicle(int userId, int vehicleId, HouseholdPermission permission) { - if (userId == -1) + //check if user is full collaborator or root user + if (UserCanDirectlyEditVehicle(userId, vehicleId)) { return true; } - List userIds = new List { userId }; + //user is not a full collaborator, check households + List userIds = new List(); var userHouseholds = _userHouseholdData.GetUserHouseholdByChildUserId(userId); - if (userHouseholds.Any()) + foreach (UserHousehold userHousehold in userHouseholds) { - //add parent's user ids - userIds.AddRange(userHouseholds.Select(x => x.Id.ParentUserId)); - } - foreach (int userIdToCheck in userIds) - { - var userAccess = _userAccess.GetUserAccessByVehicleAndUserId(userIdToCheck, vehicleId); - if (userAccess != null && userAccess.Id.UserId == userId && userAccess.Id.VehicleId == vehicleId) - { - //full collaborator, not through household - return true; - } - else if (userAccess != null && userAccess.Id.UserId == userIdToCheck && userAccess.Id.VehicleId == vehicleId) + //check if the direct parents have access to the vehicle + var userAccess = _userAccess.GetUserAccessByVehicleAndUserId(userHousehold.Id.ParentUserId, vehicleId); + if (userAccess != null && userAccess.Id.UserId == userHousehold.Id.ParentUserId && userAccess.Id.VehicleId == vehicleId) { //every member in a household has permission to view vehicles if (permission == HouseholdPermission.View) @@ -171,7 +164,7 @@ namespace CarCareTracker.Logic return true; } else { - return userHouseholds.First(x => x.Id.ParentUserId == userIdToCheck && x.Id.ChildUserId == userId).Permissions.Contains(permission); + return userHousehold.Permissions.Contains(permission); } } } diff --git a/Views/Vehicle/_BulkDataImporter.cshtml b/Views/Vehicle/_BulkDataImporter.cshtml index 05ef0d0..80834e3 100644 --- a/Views/Vehicle/_BulkDataImporter.cshtml +++ b/Views/Vehicle/_BulkDataImporter.cshtml @@ -45,7 +45,10 @@ sloader.show(); $.post('/Vehicle/ImportToVehicleIdFromCsv', { vehicleId: vehicleId, mode: mode, fileName: uploadedFile }, function (data) { sloader.hide(); - if (data) { + if (isOperationResponse(data)) { + return; + } + else if (data) { successToast("Data Imported Successfully"); hideBulkImportModal(); if (mode == "GasRecord") { diff --git a/wwwroot/js/gasrecord.js b/wwwroot/js/gasrecord.js index 34c84eb..7797682 100644 --- a/wwwroot/js/gasrecord.js +++ b/wwwroot/js/gasrecord.js @@ -486,13 +486,13 @@ function saveMultipleGasRecordsToVehicle() { } } $.post('/Vehicle/SaveMultipleGasRecords', { editModel: formValues }, function (data) { - if (data) { + if (data.success) { successToast("Gas Records Updated"); hideAddGasRecordModal(); saveScrollPosition(); getVehicleGasRecords(GetVehicleId().vehicleId); } else { - errorToast(genericErrorMessage()); + errorToast(data.message); } }) } \ No newline at end of file diff --git a/wwwroot/js/shared.js b/wwwroot/js/shared.js index bdaa3bf..f2b8201 100644 --- a/wwwroot/js/shared.js +++ b/wwwroot/js/shared.js @@ -178,7 +178,7 @@ function saveVehicle(isEdit) { dashboardMetrics: vehicleDashboardMetrics, vehicleIdentifier: vehicleIdentifier }, function (data) { - if (data) { + if (data.success) { if (!isEdit) { successToast("Vehicle Added"); hideAddVehicleModal(); @@ -190,7 +190,7 @@ function saveVehicle(isEdit) { viewVehicle(vehicleId); } } else { - errorToast(genericErrorMessage()); + errorToast(data.message); } }); } @@ -756,7 +756,10 @@ function printTabStickers(ids, source) { recordIds: ids, importMode: source }, function (data) { - if (data) { + if (isOperationResponse(data)) { + return; + } + else if (data) { printContainer(data); } }) @@ -764,9 +767,10 @@ function printTabStickers(ids, source) { function exportVehicleData(mode) { var vehicleId = GetVehicleId().vehicleId; $.get('/Vehicle/ExportFromVehicleToCsv', { vehicleId: vehicleId, mode: mode }, function (data) { - if (!data) { - errorToast(genericErrorMessage()); - } else { + if (isOperationResponse(data)) { + return; + } + else if (data) { window.location.href = data; } }); @@ -857,12 +861,12 @@ function moveRecords(ids, source, dest) { }).then((result) => { if (result.isConfirmed) { $.post('/Vehicle/MoveRecords', { recordIds: ids, source: source, destination: dest }, function (data) { - if (data) { + if (data.success) { successToast(`${ids.length} Record(s) Moved`); var vehicleId = GetVehicleId().vehicleId; refreshDataCallBack(vehicleId); } else { - errorToast(genericErrorMessage()); + errorToast(data.message); } }); } else { @@ -1005,12 +1009,12 @@ function duplicateRecords(ids, source) { }).then((result) => { if (result.isConfirmed) { $.post('/Vehicle/DuplicateRecords', { recordIds: ids, importMode: source }, function (data) { - if (data) { + if (data.success) { successToast(`${ids.length} Record(s) Duplicated`); var vehicleId = GetVehicleId().vehicleId; refreshDataCallBack(vehicleId); } else { - errorToast(genericErrorMessage()); + errorToast(data.message); } }); } else { @@ -1091,10 +1095,10 @@ function duplicateRecordsToOtherVehicles(ids, source) { }).then(function (result) { if (result.isConfirmed) { $.post('/Vehicle/DuplicateRecordsToOtherVehicles', { recordIds: ids, vehicleIds: result.value.selectedVehicleData.ids, importMode: source}, function (data) { - if (data) { + if (data.success) { successToast(`${ids.length} Record(s) Duplicated`); } else { - errorToast(genericErrorMessage()); + errorToast(data.message); } }); } @@ -1140,12 +1144,12 @@ function insertOdometer(ids, source) { }).then((result) => { if (result.isConfirmed) { $.post('/Vehicle/BulkCreateOdometerRecords', { recordIds: ids, importMode: source }, function (data) { - if (data) { + if (data.success) { successToast(`${ids.length} Odometer Record(s) Created`); var vehicleId = GetVehicleId().vehicleId; refreshDataCallBack(vehicleId); } else { - errorToast(genericErrorMessage()); + errorToast(data.message); } }); } else { diff --git a/wwwroot/js/vehicle.js b/wwwroot/js/vehicle.js index 93a7657..4901393 100644 --- a/wwwroot/js/vehicle.js +++ b/wwwroot/js/vehicle.js @@ -306,13 +306,13 @@ function moveRecord(recordId, source, dest) { }).then((result) => { if (result.isConfirmed) { $.post('/Vehicle/MoveRecord', { recordId: recordId, source: source, destination: dest }, function (data) { - if (data) { + if (data.success) { hideModalCallBack(); successToast("Record Moved"); var vehicleId = GetVehicleId().vehicleId; refreshDataCallBack(vehicleId); } else { - errorToast(genericErrorMessage()); + errorToast(data.message); } }); } else { @@ -414,12 +414,12 @@ function saveGenericRecord() { } //save to db. $.post('/Vehicle/EditMultipleRecords', { genericRecordEditModel: formValues }, function (data) { - if (data) { + if (data.success) { successToast(formValues.recordIds.length > 1 ? "Records Updated" : "Record Updated."); hideGenericRecordModal(); refreshDataCallBack(GetVehicleId().vehicleId); } else { - errorToast(genericErrorMessage()); + errorToast(data.message); } }) } @@ -563,12 +563,12 @@ function adjustRecordsOdometer(ids, source) { if (result.isConfirmed) { saveScrollPosition(); $.post('/Vehicle/AdjustRecordsOdometer', { recordIds: ids, vehicleId: GetVehicleId().vehicleId, importMode: source }, function (data) { - if (data) { + if (data.success) { successToast(`${ids.length} Record(s) Updated`); var vehicleId = GetVehicleId().vehicleId; refreshDataCallBack(vehicleId); } else { - errorToast(genericErrorMessage()); + errorToast(data.message); } }); } else {