diff --git a/Controllers/APIController.cs b/Controllers/APIController.cs index 1b9d773..f56c841 100644 --- a/Controllers/APIController.cs +++ b/Controllers/APIController.cs @@ -1504,6 +1504,7 @@ namespace CarCareTracker.Controllers } } #endregion + #region ReminderRecord [TypeFilter(typeof(CollaboratorFilter))] [HttpGet] [Route("/api/vehicle/reminders")] @@ -1516,7 +1517,7 @@ namespace CarCareTracker.Controllers } var currentMileage = _vehicleLogic.GetMaxMileage(vehicleId); var reminders = _reminderRecordDataAccess.GetReminderRecordsByVehicleId(vehicleId); - var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).Select(x=> new ReminderExportModel { Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), Notes = x.Notes, DueDate = x.Date.ToShortDateString(), DueOdometer = x.Mileage.ToString()}); + var results = _reminderHelper.GetReminderRecordViewModels(reminders, currentMileage, DateTime.Now).Select(x=> new ReminderExportModel { Id = x.Id.ToString(), Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), Notes = x.Notes, DueDate = x.Date.ToShortDateString(), DueOdometer = x.Mileage.ToString(), Tags = string.Join(' ', x.Tags) }); if (_config.GetInvariantApi() || Request.Headers.ContainsKey("culture-invariant")) { return Json(results, StaticHelper.GetInvariantOption()); @@ -1526,6 +1527,183 @@ namespace CarCareTracker.Controllers return Json(results); } } + [TypeFilter(typeof(CollaboratorFilter))] + [HttpPost] + [Route("/api/vehicle/reminders/add")] + [Consumes("application/json")] + public IActionResult AddReminderRecordJson(int vehicleId, [FromBody] ReminderExportModel input) => AddReminderRecord(vehicleId, input); + [TypeFilter(typeof(CollaboratorFilter))] + [HttpPost] + [Route("/api/vehicle/reminders/add")] + public IActionResult AddReminderRecord(int vehicleId, ReminderExportModel input) + { + if (vehicleId == default) + { + Response.StatusCode = 400; + return Json(OperationResponse.Failed("Must provide a valid vehicle id")); + } + if (string.IsNullOrWhiteSpace(input.Description) || + string.IsNullOrWhiteSpace(input.Metric)) + { + Response.StatusCode = 400; + return Json(OperationResponse.Failed("Input object invalid, Description and Metric cannot be empty.")); + } + bool validMetric = Enum.TryParse(input.Metric, out ReminderMetric parsedMetric); + bool validDate = DateTime.TryParse(input.DueDate, out DateTime parsedDate); + bool validOdometer = int.TryParse(input.DueOdometer, out int parsedOdometer); + if (!validMetric) + { + Response.StatusCode = 400; + return Json(OperationResponse.Failed("Input object invalid, values for Metric(Date, Odometer, Both) is invalid.")); + } + //validate metrics + switch (parsedMetric) + { + case ReminderMetric.Both: + //validate due date and odometer + if (!validDate || !validOdometer) + { + return Json(OperationResponse.Failed("Input object invalid, DueDate and DueOdometer must be valid if Metric is Both")); + } + break; + case ReminderMetric.Date: + if (!validDate) + { + return Json(OperationResponse.Failed("Input object invalid, DueDate must be valid if Metric is Date")); + } + break; + case ReminderMetric.Odometer: + if (!validOdometer) + { + return Json(OperationResponse.Failed("Input object invalid, DueOdometer must be valid if Metric is Odometer")); + } + break; + } + try + { + var reminderRecord = new ReminderRecord() + { + VehicleId = vehicleId, + Description = input.Description, + Mileage = parsedOdometer, + Date = parsedDate, + Metric = parsedMetric, + Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes, + Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList() + }; + _reminderRecordDataAccess.SaveReminderRecordToVehicle(reminderRecord); + StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromReminderRecord(reminderRecord, "reminderrecord.add.api", User.Identity.Name)); + return Json(OperationResponse.Succeed("Reminder Record Added")); + } + catch (Exception ex) + { + Response.StatusCode = 500; + return Json(OperationResponse.Failed(ex.Message)); + } + } + [HttpPut] + [Route("/api/vehicle/reminders/update")] + [Consumes("application/json")] + public IActionResult UpdateReminderRecordJson([FromBody] ReminderExportModel input) => UpdateReminderRecord(input); + [HttpPut] + [Route("/api/vehicle/reminders/update")] + public IActionResult UpdateReminderRecord(ReminderExportModel input) + { + if (string.IsNullOrWhiteSpace(input.Id) || + string.IsNullOrWhiteSpace(input.Description) || + string.IsNullOrWhiteSpace(input.Metric)) + { + Response.StatusCode = 400; + return Json(OperationResponse.Failed("Input object invalid, Id, Description and Metric cannot be empty.")); + } + bool validMetric = Enum.TryParse(input.Metric, out ReminderMetric parsedMetric); + bool validDate = DateTime.TryParse(input.DueDate, out DateTime parsedDate); + bool validOdometer = int.TryParse(input.DueOdometer, out int parsedOdometer); + if (!validMetric) + { + Response.StatusCode = 400; + return Json(OperationResponse.Failed("Input object invalid, values for Metric(Date, Odometer, Both) is invalid.")); + } + //validate metrics + switch (parsedMetric) + { + case ReminderMetric.Both: + //validate due date and odometer + if (!validDate || !validOdometer) + { + return Json(OperationResponse.Failed("Input object invalid, DueDate and DueOdometer must be valid if Metric is Both")); + } + break; + case ReminderMetric.Date: + if (!validDate) + { + return Json(OperationResponse.Failed("Input object invalid, DueDate must be valid if Metric is Date")); + } + break; + case ReminderMetric.Odometer: + if (!validOdometer) + { + return Json(OperationResponse.Failed("Input object invalid, DueOdometer must be valid if Metric is Odometer")); + } + break; + } + try + { + //retrieve existing record + var existingRecord = _reminderRecordDataAccess.GetReminderRecordById(int.Parse(input.Id)); + if (existingRecord != null && existingRecord.Id == int.Parse(input.Id)) + { + //check if user has access to the vehicleId + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId)) + { + Response.StatusCode = 401; + return Json(OperationResponse.Failed("Access Denied, you don't have access to this vehicle.")); + } + existingRecord.Date = parsedDate; + existingRecord.Mileage = parsedOdometer; + existingRecord.Description = input.Description; + existingRecord.Metric = parsedMetric; + existingRecord.Notes = string.IsNullOrWhiteSpace(input.Notes) ? "" : input.Notes; + existingRecord.Tags = string.IsNullOrWhiteSpace(input.Tags) ? new List() : input.Tags.Split(' ').Distinct().ToList(); + _reminderRecordDataAccess.SaveReminderRecordToVehicle(existingRecord); + StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromReminderRecord(existingRecord, "reminderrecord.update.api", User.Identity.Name)); + } + else + { + Response.StatusCode = 400; + return Json(OperationResponse.Failed("Invalid Record Id")); + } + return Json(OperationResponse.Succeed("Reminder Record Updated")); + } + catch (Exception ex) + { + Response.StatusCode = 500; + return Json(OperationResponse.Failed(ex.Message)); + } + } + [HttpDelete] + [Route("/api/vehicle/reminders/delete")] + public IActionResult DeleteReminderRecord(int id) + { + var existingRecord = _reminderRecordDataAccess.GetReminderRecordById(id); + if (existingRecord == null || existingRecord.Id == default) + { + Response.StatusCode = 400; + return Json(OperationResponse.Failed("Invalid Record Id")); + } + //security check. + if (!_userLogic.UserCanEditVehicle(GetUserID(), existingRecord.VehicleId)) + { + Response.StatusCode = 401; + return Json(OperationResponse.Failed("Access Denied, you don't have access to this vehicle.")); + } + var result = _reminderRecordDataAccess.DeleteReminderRecordById(existingRecord.Id); + if (result) + { + StaticHelper.NotifyAsync(_config.GetWebHookUrl(), WebHookPayload.FromReminderRecord(existingRecord, "reminderrecord.delete.api", User.Identity.Name)); + } + return Json(OperationResponse.Conditional(result, "Reminder Record Deleted")); + } [HttpGet] [Route("/api/calendar")] public IActionResult Calendar() @@ -1539,6 +1717,7 @@ namespace CarCareTracker.Controllers var calendarContent = StaticHelper.RemindersToCalendar(reminders); return File(calendarContent, "text/calendar"); } + #endregion [HttpPost] [Route("/api/documents/upload")] public IActionResult UploadDocument(List documents) diff --git a/Logic/VehicleLogic.cs b/Logic/VehicleLogic.cs index 04dc5b6..653e641 100644 --- a/Logic/VehicleLogic.cs +++ b/Logic/VehicleLogic.cs @@ -303,11 +303,11 @@ namespace CarCareTracker.Logic //set next reminder if (results.Any(x => (x.Metric == ReminderMetric.Date || x.Metric == ReminderMetric.Both) && x.Date >= DateTime.Now.Date)) { - resultToAdd.NextReminder = results.Where(x => x.Date >= DateTime.Now.Date).OrderBy(x => x.Date).Select(x => new ReminderExportModel { Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), Notes = x.Notes, DueDate = x.Date.ToShortDateString(), DueOdometer = x.Mileage.ToString() }).First(); + resultToAdd.NextReminder = results.Where(x => x.Date >= DateTime.Now.Date).OrderBy(x => x.Date).Select(x => new ReminderExportModel { Id = x.Id.ToString(), Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), Notes = x.Notes, DueDate = x.Date.ToShortDateString(), DueOdometer = x.Mileage.ToString(), Tags = string.Join(' ', x.Tags) }).First(); } else if (results.Any(x => (x.Metric == ReminderMetric.Odometer || x.Metric == ReminderMetric.Both) && x.Mileage >= currentMileage)) { - resultToAdd.NextReminder = results.Where(x => x.Mileage >= currentMileage).OrderBy(x => x.Mileage).Select(x => new ReminderExportModel { Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), Notes = x.Notes, DueDate = x.Date.ToShortDateString(), DueOdometer = x.Mileage.ToString() }).First(); + resultToAdd.NextReminder = results.Where(x => x.Mileage >= currentMileage).OrderBy(x => x.Mileage).Select(x => new ReminderExportModel { Id = x.Id.ToString(), Description = x.Description, Urgency = x.Urgency.ToString(), Metric = x.Metric.ToString(), Notes = x.Notes, DueDate = x.Date.ToShortDateString(), DueOdometer = x.Mileage.ToString(), Tags = string.Join(' ', x.Tags) }).First(); } apiResult.Add(resultToAdd); } diff --git a/Models/Shared/ImportModel.cs b/Models/Shared/ImportModel.cs index cbb424a..a4e5059 100644 --- a/Models/Shared/ImportModel.cs +++ b/Models/Shared/ImportModel.cs @@ -115,6 +115,8 @@ namespace CarCareTracker.Models } public class ReminderExportModel { + [JsonConverter(typeof(FromIntOptional))] + public string Id { get; set; } public string Description { get; set; } public string Urgency { get; set; } public string Metric { get; set; } @@ -123,6 +125,7 @@ namespace CarCareTracker.Models public string DueDate { get; set; } [JsonConverter(typeof(FromIntOptional))] public string DueOdometer { get; set; } + public string Tags { get; set; } } public class PlanRecordExportModel { diff --git a/Views/API/Index.cshtml b/Views/API/Index.cshtml index 8477a4e..8a71a68 100644 --- a/Views/API/Index.cshtml +++ b/Views/API/Index.cshtml @@ -669,6 +669,65 @@ vehicleId - Id of Vehicle +
+
+ POST +
+
+ /api/vehicle/reminders/add +
+
+ Adds Reminder Record to the vehicle +
+
+ vehicleId - Id of Vehicle +
+ Body(form-data): {
+ description - Description
+ dueDate - Due Date
+ dueOdometer - Due Odometer reading
+ metric - Date/Odometer/Both
+ notes - notes(optional)
+ tags - tags separated by space(optional)
+ } +
+
+
+
+ PUT +
+
+ /api/vehicle/reminders/update +
+
+ Updates Reminder Record +
+
+ Body(form-data): {
+ Id - Id of Reminder Record
+ description - Description
+ dueDate - Due Date
+ dueOdometer - Due Odometer reading
+ metric - Date/Odometer/Both
+ notes - notes(optional)
+ tags - tags separated by space(optional)
+ } +
+
+
+
+ DELETE +
+
+ /api/vehicle/reminders/delete +
+
+ Deletes Reminder Record +
+
+ Id - Id of Reminder Record +
+
GET