diff --git a/src/CodeGenHero.ResourceScheduler.API/Controllers/RS/Custom/ResourceSchedulesControllerCustom.cs b/src/CodeGenHero.ResourceScheduler.API/Controllers/RS/Custom/ResourceSchedulesControllerCustom.cs index 4bf28c9..f99f47e 100644 --- a/src/CodeGenHero.ResourceScheduler.API/Controllers/RS/Custom/ResourceSchedulesControllerCustom.cs +++ b/src/CodeGenHero.ResourceScheduler.API/Controllers/RS/Custom/ResourceSchedulesControllerCustom.cs @@ -1,65 +1,161 @@ // - Template:WebApiControllerPartialMethods, Version:1.1, Id:54f0612b-5235-437d-af2d-0b75efa68630 +using CodeGenHero.Repository; +using System; +using System.Collections.Generic; +using System.Data; using System.Data.Entity; using System.Linq; +using System.Net; +using System.Text; +using dtoRS = CodeGenHero.ResourceScheduler.DTO.RS; using entRS = CodeGenHero.ResourceScheduler.Repository.Entities.RS; namespace CodeGenHero.ResourceScheduler.API.Controllers.RS { - public partial class ResourceSchedulesRSController : RSBaseApiController - { - - //partial void RunCustomLogicAfterInsert(ref entRS.ResourceSchedule newDBItem, ref IRepositoryActionResult result) {} - - //partial void RunCustomLogicAfterUpdatePatch(ref entRS.ResourceSchedule updatedDBItem, ref IRepositoryActionResult result) {} - - //partial void RunCustomLogicAfterUpdatePut(ref entRS.ResourceSchedule updatedDBItem, ref IRepositoryActionResult result) {} - - - ///// - ///// A sample implementation of custom logic used to either manipulate a DTO item or include related entities. - ///// - ///// - ///// - ///// - // partial void RunCustomLogicOnGetEntityByPK(ref entRS.ResourceSchedule dbItem, System.Guid id, int numChildLevels) - // { - // if (numChildLevels > 1) - // { - // int[] orderLineItemIds = dbItem.OrderLineItems.Select(x => x.OrderLineItemId).ToArray(); - - // var lineItemDiscounts = Repo.RSDataContext.OrderLineItemDiscounts.Where(x => orderLineItemIds.Contains(x.OrderLineItemId)).ToList(); - - // foreach (var lineItemDiscount in lineItemDiscounts) - // { // Find the match and add the item to it. - // var orderLineItem = dbItem.OrderLineItems.Where(x => x.OrderLineItemId == lineItemDiscount.OrderLineItemId).FirstOrDefault(); - - // if (orderLineItem == null) - // { - // throw new System.Data.Entity.Core.ObjectNotFoundException($"Unable to locate matching OrderLineItem record for {lineItemDiscount.OrderLineItemId}." - // } - - // orderLineItem.LineItemDiscounts.Add(lineItemDiscount); - // } - // } - - // } - - ///// - ///// A sample implementation of custom logic used to filter on a field that exists in a related, parent, table. - ///// - ///// - ///// - //partial void RunCustomLogicAfterGetQueryableList(ref IQueryable dbItems, ref List filterList) - //{ - // var queryableFilters = filterList.ToQueryableFilter(); - // var myFilterCriterion = queryableFilters.Where(y => y.Member.ToLowerInvariant() == "").FirstOrDefault(); // Examine the incoming filter for the presence of a field name which does not exist on the target entity. - - // if (myFilterCriterion != null) - // { // myFieldName is a criterion that has to be evaluated at a level other than our target entity. - // dbItems = dbItems.Include(x => x.myFKRelatedEntity).Where(x => x.myFKRelatedEntity.myFieldName == new Guid(myFilterCriterion.Value)); - // queryableFilters.Remove(myFilterCriterion); // The evaluated criterion needs to be removed from the list of filters before we invoke the ApplyFilter() extension method. - // filterList = queryableFilters.ToQueryableStringList(); - // } - //} - } + public partial class ResourceSchedulesRSController : RSBaseApiController + { + partial void RunCustomLogicBeforeInsert(ref dtoRS.ResourceSchedule dtoItem, ref HttpStatusCode httpStatusCode, ref string message) + { // Business rule - check to see if the requested resource times conflict with what is reserved in the DB. + List messages = new List(); + if (!Validate(ref dtoItem, ref messages)) { httpStatusCode = HttpStatusCode.PreconditionFailed; message = String.Join(",", messages); } + } + + partial void RunCustomLogicBeforeUpdate(ref dtoRS.ResourceSchedule dtoItem, ref HttpStatusCode httpStatusCode, ref string message) + { // Business rule - check to see if the requested resource times conflict with what is reserved in the DB. + List messages = new List(); + if (!Validate(ref dtoItem, ref messages)) { httpStatusCode = HttpStatusCode.PreconditionFailed; message = String.Join(",", messages); } + } + + private bool Validate(ref dtoRS.ResourceSchedule dtoItem, ref List messages) + { + //fields need to be filled in and the end date/time needs to be after the before date/time + + //check that we have a reserved for field + if (string.IsNullOrEmpty(dtoItem.ReservedForUser)) + { + messages.Add("Please note who/what the reservation is for!"); + } + + if (dtoItem.ReservationStartDateTime == DateTime.MinValue || dtoItem.ReservationEndDateTime == DateTime.MinValue) + { + messages.Add("We are having trouble making your reservation. Please let an admin know."); + } + + //reservations should start before they end + if (dtoItem.ReservationStartDateTime >= dtoItem.ReservationEndDateTime) + { + messages.Add("Your reservation should begin before it ends!"); + } + + //lastly, make sure there is no conflict with existing reservations + var selectedDate = new DateTime(year: dtoItem.ReservationStartDateTime.Year, month: dtoItem.ReservationStartDateTime.Month, day: dtoItem.ReservationStartDateTime.Day); + var HourlySchedules = BuildHourlySchedules(selectedDate: selectedDate, resourceId: dtoItem.ResourceId); + foreach (var h in HourlySchedules) + { + if (h.IsReserved && h.ResourceSchedule != null) + { + //if the new/edited reservation is inbetween and of the existing reservations... + if (dtoItem.ReservationStartDateTime <= h.Hour && dtoItem.ReservationEndDateTime >= h.Hour) + { + //check if we are currently editing this record. + if (dtoItem.Id != h.ResourceSchedule.Id) + { + messages.Add("Your reservation conflicts with an existing reservation."); + } + } + } + } + + return messages.Count == 0; + } + + public List HourlySchedules { get; set; } + + public static List Hours = new List() { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + + public List BuildHourlySchedules(DateTime selectedDate, Guid resourceId) + { + var hourlySchedules = new List(); + var schedules = Repo.RSDataContext.ResourceSchedules.Where( + x => x.ResourceId == resourceId + && x.ReservationStartDateTime >= selectedDate + && x.ReservationStartDateTime <= selectedDate.AddDays(1) + && x.IsDeleted == false); + + foreach (var h in Hours) + { + var hour = selectedDate.AddHours(h); + var sched = schedules.Where(x => x.ReservationStartDateTime <= hour && x.ReservationEndDateTime >= hour).FirstOrDefault(); + + hourlySchedules.Add(new HourlySchedule() + { + Hour = hour, + ResourceSchedule = sched + }); + } + return hourlySchedules; + } + + public class HourlySchedule + { + public DateTime Hour { get; set; } + public bool IsReserved { get { return ResourceSchedule == null ? false : true; } } + public entRS.ResourceSchedule ResourceSchedule { get; set; } = new entRS.ResourceSchedule(); + } + + + //partial void RunCustomLogicAfterInsert(ref entRS.ResourceSchedule newDBItem, ref IRepositoryActionResult result) {} + + //partial void RunCustomLogicAfterUpdatePatch(ref entRS.ResourceSchedule updatedDBItem, ref IRepositoryActionResult result) {} + + //partial void RunCustomLogicAfterUpdatePut(ref entRS.ResourceSchedule updatedDBItem, ref IRepositoryActionResult result) {} + + + ///// + ///// A sample implementation of custom logic used to either manipulate a DTO item or include related entities. + ///// + ///// + ///// + ///// + // partial void RunCustomLogicOnGetEntityByPK(ref entRS.ResourceSchedule dbItem, System.Guid id, int numChildLevels) + // { + // if (numChildLevels > 1) + // { + // int[] orderLineItemIds = dbItem.OrderLineItems.Select(x => x.OrderLineItemId).ToArray(); + + // var lineItemDiscounts = Repo.RSDataContext.OrderLineItemDiscounts.Where(x => orderLineItemIds.Contains(x.OrderLineItemId)).ToList(); + + // foreach (var lineItemDiscount in lineItemDiscounts) + // { // Find the match and add the item to it. + // var orderLineItem = dbItem.OrderLineItems.Where(x => x.OrderLineItemId == lineItemDiscount.OrderLineItemId).FirstOrDefault(); + + // if (orderLineItem == null) + // { + // throw new System.Data.Entity.Core.ObjectNotFoundException($"Unable to locate matching OrderLineItem record for {lineItemDiscount.OrderLineItemId}." + // } + + // orderLineItem.LineItemDiscounts.Add(lineItemDiscount); + // } + // } + + // } + + ///// + ///// A sample implementation of custom logic used to filter on a field that exists in a related, parent, table. + ///// + ///// + ///// + //partial void RunCustomLogicAfterGetQueryableList(ref IQueryable dbItems, ref List filterList) + //{ + // var queryableFilters = filterList.ToQueryableFilter(); + // var myFilterCriterion = queryableFilters.Where(y => y.Member.ToLowerInvariant() == "").FirstOrDefault(); // Examine the incoming filter for the presence of a field name which does not exist on the target entity. + + // if (myFilterCriterion != null) + // { // myFieldName is a criterion that has to be evaluated at a level other than our target entity. + // dbItems = dbItems.Include(x => x.myFKRelatedEntity).Where(x => x.myFKRelatedEntity.myFieldName == new Guid(myFilterCriterion.Value)); + // queryableFilters.Remove(myFilterCriterion); // The evaluated criterion needs to be removed from the list of filters before we invoke the ApplyFilter() extension method. + // filterList = queryableFilters.ToQueryableStringList(); + // } + //} + } } diff --git a/src/CodeGenHero.ResourceScheduler.API/Controllers/RS/ResourceSchedulesController.cs b/src/CodeGenHero.ResourceScheduler.API/Controllers/RS/ResourceSchedulesController.cs index 144d50d..6d81f9d 100644 --- a/src/CodeGenHero.ResourceScheduler.API/Controllers/RS/ResourceSchedulesController.cs +++ b/src/CodeGenHero.ResourceScheduler.API/Controllers/RS/ResourceSchedulesController.cs @@ -21,273 +21,290 @@ namespace CodeGenHero.ResourceScheduler.API.Controllers.RS { - public partial class ResourceSchedulesRSController : RSBaseApiController - { - private const string GET_LIST_ROUTE_NAME = "ResourceSchedulesRSList"; - private const int maxPageSize = 100; - - private GenericFactory _factory - = new GenericFactory(); - - public ResourceSchedulesRSController() : base() - { - } - - public ResourceSchedulesRSController(ILoggingService log, IRSRepository repository) - : base(log, repository) - { - } - - [HttpDelete] - [VersionedRoute(template: "ResourceSchedules/{id}", allowedVersion: 1)] - public async Task Delete(System.Guid id) - { - try - { - if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } - - var result = await Repo.Delete_ResourceScheduleAsync(id); - - if (result.Status == cghEnums.RepositoryActionStatus.Deleted) - { - return StatusCode(HttpStatusCode.NoContent); - } - else if (result.Status == cghEnums.RepositoryActionStatus.NotFound) - { - return NotFound(); - } - - Warn("Unable to delete object via Web API", LogMessageType.Instance.Warn_WebApi, result.Exception, httpResponseStatusCode: 400, url: Request.RequestUri.ToString()); - return BadRequest(); - } - catch (Exception ex) - { - Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); - - if (System.Diagnostics.Debugger.IsAttached) - System.Diagnostics.Debugger.Break(); - - return InternalServerError(); - } - } - - [HttpGet] - [VersionedRoute(template: "ResourceSchedules", allowedVersion: 1, Name = GET_LIST_ROUTE_NAME)] - public async Task Get(string sort = null, - string fields = null, string filter = null, int page = 1, int pageSize = maxPageSize) - { - try - { - if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } - - var fieldList = GetListByDelimiter(fields); - bool childrenRequested = false; // TODO: set this based upon actual fields requested. - - var filterList = GetListByDelimiter(filter); - var dbItems = Repo.GetQueryable_ResourceSchedule().AsNoTracking(); - RunCustomLogicAfterGetQueryableList(ref dbItems, ref filterList); - dbItems = dbItems.ApplyFilter(filterList); - dbItems = dbItems.ApplySort(sort ?? (typeof(entRS.ResourceSchedule).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)).First().Name); - - if (pageSize > maxPageSize) - { // ensure the page size isn't larger than the maximum. - pageSize = maxPageSize; - } - - var urlHelper = new UrlHelper(Request); - PageData paginationHeader = BuildPaginationHeader(urlHelper, GET_LIST_ROUTE_NAME, page: page, totalCount: dbItems.Count(), pageSize: pageSize, sort: sort); - HttpContext.Current.Response.Headers.Add("X-Pagination", Newtonsoft.Json.JsonConvert.SerializeObject(paginationHeader)); - - // return result - return Ok(dbItems - .Skip(pageSize * (page - 1)) - .Take(pageSize) - .ToList() - .Select(x => _factory.CreateDataShapedObject(x, fieldList, childrenRequested))); - } - catch (Exception ex) - { - Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); - - if (System.Diagnostics.Debugger.IsAttached) - System.Diagnostics.Debugger.Break(); - - return InternalServerError(); - } - } - - [HttpGet] - [VersionedRoute(template: "ResourceSchedules/{id}/{numChildLevels:int=0}", allowedVersion: 1)] - public async Task Get(System.Guid id, int numChildLevels) - { - try - { - if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } - var dbItem = await Repo.Get_ResourceScheduleAsync(id, numChildLevels); - - if (dbItem == null) - { - Warn("Unable to get object via Web API", LogMessageType.Instance.Warn_WebApi, httpResponseStatusCode: 404, url: Request.RequestUri.ToString()); - return NotFound(); - } - - RunCustomLogicOnGetEntityByPK(ref dbItem, id, numChildLevels); - return Ok(_factory.Create(dbItem)); - } - catch (Exception ex) - { - Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); - - if (System.Diagnostics.Debugger.IsAttached) - System.Diagnostics.Debugger.Break(); - - return InternalServerError(); - } - } - - [HttpPatch] - [VersionedRoute(template: "ResourceSchedules/{id}", allowedVersion: 1)] - public async Task Patch(System.Guid id, [FromBody] JsonPatchDocument patchDocument) - { - try - { - if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } - - if (patchDocument == null) - { - return BadRequest(); - } - - var dbItem = await Repo.Get_ResourceScheduleAsync(id, numChildLevels: 0); - if (dbItem == null) - { - return NotFound(); - } - - var dtoItem = _factory.Create(dbItem); // map - - // apply changes to the DTO - patchDocument.ApplyTo(dtoItem); - dtoItem.Id = id; - - // map the DTO with applied changes to the entity, & update - var updatedDBItem = _factory.Create(dtoItem); // map - var result = await Repo.UpdateAsync(updatedDBItem); - RunCustomLogicAfterUpdatePatch(ref updatedDBItem, ref result); - - if (result.Status == cghEnums.RepositoryActionStatus.Updated) - { - // map to dto - var patchedDTOItem = _factory.Create(result.Entity); - return Ok(patchedDTOItem); - } - - Warn("Unable to patch object via Web API", LogMessageType.Instance.Warn_WebApi, result.Exception, httpResponseStatusCode: 400, url: Request.RequestUri.ToString()); - return BadRequest(); - } - catch (Exception ex) - { - Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); - - if (System.Diagnostics.Debugger.IsAttached) - System.Diagnostics.Debugger.Break(); - - return InternalServerError(); - } - } - - [HttpPost] - [VersionedRoute(template: "ResourceSchedules", allowedVersion: 1)] - public async Task Post([FromBody] dtoRS.ResourceSchedule dtoItem) - { - try - { - if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } - - if (dtoItem == null) - { - return BadRequest(); - } - - // try mapping & saving - var newDBItem = _factory.Create(dtoItem); - - var result = await Repo.InsertAsync(newDBItem); - RunCustomLogicAfterInsert(ref newDBItem, ref result); - - if (result.Status == cghEnums.RepositoryActionStatus.Created) - { // map to dto - var newDTOItem = _factory.Create(result.Entity); - var uriFormatted = Request.RequestUri.ToString().EndsWith("/") == true ? Request.RequestUri.ToString().Substring(0, Request.RequestUri.ToString().Length - 1) : Request.RequestUri.ToString(); - return Created($"{uriFormatted}/{newDTOItem.Id}", newDTOItem); - } - - Warn("Unable to create object via Web API", LogMessageType.Instance.Warn_WebApi, result.Exception, httpResponseStatusCode: 400, url: Request.RequestUri.ToString()); - return BadRequest(); - } - catch (Exception ex) - { - Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); - - if (System.Diagnostics.Debugger.IsAttached) - System.Diagnostics.Debugger.Break(); - - return InternalServerError(); - } - } - - [HttpPut] - [VersionedRoute(template: "ResourceSchedules/{id}", allowedVersion: 1)] - public async Task Put(System.Guid id, [FromBody] dtoRS.ResourceSchedule dtoItem) - { - try - { - if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } - - if (dtoItem == null) - { - return BadRequest(); - } - - dtoItem.Id = id; - - var updatedDBItem = _factory.Create(dtoItem); // map - var result = await Repo.UpdateAsync(updatedDBItem); - RunCustomLogicAfterUpdatePut(ref updatedDBItem, ref result); - - if (result.Status == cghEnums.RepositoryActionStatus.Updated) - { - // map to dto - var updatedDTOItem = _factory.Create(result.Entity); - return Ok(updatedDTOItem); - } - else if (result.Status == cghEnums.RepositoryActionStatus.NotFound) - { - return NotFound(); - } - - Warn("Unable to update object via Web API", LogMessageType.Instance.Warn_WebApi, result.Exception, httpResponseStatusCode: 400, url: Request.RequestUri.ToString()); - return BadRequest(); - } - catch (Exception ex) - { - Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); - - if (System.Diagnostics.Debugger.IsAttached) - System.Diagnostics.Debugger.Break(); - - return InternalServerError(); - } - } - - partial void RunCustomLogicAfterInsert(ref CodeGenHero.ResourceScheduler.Repository.Entities.RS.ResourceSchedule newDBItem, ref IRepositoryActionResult result); - - partial void RunCustomLogicAfterUpdatePatch(ref CodeGenHero.ResourceScheduler.Repository.Entities.RS.ResourceSchedule updatedDBItem, ref IRepositoryActionResult result); - - partial void RunCustomLogicAfterUpdatePut(ref CodeGenHero.ResourceScheduler.Repository.Entities.RS.ResourceSchedule updatedDBItem, ref IRepositoryActionResult result); - - partial void RunCustomLogicOnGetEntityByPK(ref entRS.ResourceSchedule dbItem, System.Guid id, int numChildLevels); - - partial void RunCustomLogicAfterGetQueryableList(ref IQueryable dbItems, ref List filterList); - } + public partial class ResourceSchedulesRSController : RSBaseApiController + { + private const string GET_LIST_ROUTE_NAME = "ResourceSchedulesRSList"; + private const int maxPageSize = 100; + + private GenericFactory _factory + = new GenericFactory(); + + public ResourceSchedulesRSController() : base() + { + } + + public ResourceSchedulesRSController(ILoggingService log, IRSRepository repository) + : base(log, repository) + { + } + + [HttpDelete] + [VersionedRoute(template: "ResourceSchedules/{id}", allowedVersion: 1)] + public async Task Delete(System.Guid id) + { + try + { + if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } + + var result = await Repo.Delete_ResourceScheduleAsync(id); + + if (result.Status == cghEnums.RepositoryActionStatus.Deleted) + { + return StatusCode(HttpStatusCode.NoContent); + } + else if (result.Status == cghEnums.RepositoryActionStatus.NotFound) + { + return NotFound(); + } + + Warn("Unable to delete object via Web API", LogMessageType.Instance.Warn_WebApi, result.Exception, httpResponseStatusCode: 400, url: Request.RequestUri.ToString()); + return BadRequest(); + } + catch (Exception ex) + { + Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); + + if (System.Diagnostics.Debugger.IsAttached) + System.Diagnostics.Debugger.Break(); + + return InternalServerError(); + } + } + + [HttpGet] + [VersionedRoute(template: "ResourceSchedules", allowedVersion: 1, Name = GET_LIST_ROUTE_NAME)] + public async Task Get(string sort = null, + string fields = null, string filter = null, int page = 1, int pageSize = maxPageSize) + { + try + { + if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } + + var fieldList = GetListByDelimiter(fields); + bool childrenRequested = false; // TODO: set this based upon actual fields requested. + + var filterList = GetListByDelimiter(filter); + var dbItems = Repo.GetQueryable_ResourceSchedule().AsNoTracking(); + RunCustomLogicAfterGetQueryableList(ref dbItems, ref filterList); + dbItems = dbItems.ApplyFilter(filterList); + dbItems = dbItems.ApplySort(sort ?? (typeof(entRS.ResourceSchedule).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)).First().Name); + + if (pageSize > maxPageSize) + { // ensure the page size isn't larger than the maximum. + pageSize = maxPageSize; + } + + var urlHelper = new UrlHelper(Request); + PageData paginationHeader = BuildPaginationHeader(urlHelper, GET_LIST_ROUTE_NAME, page: page, totalCount: dbItems.Count(), pageSize: pageSize, sort: sort); + HttpContext.Current.Response.Headers.Add("X-Pagination", Newtonsoft.Json.JsonConvert.SerializeObject(paginationHeader)); + + // return result + return Ok(dbItems + .Skip(pageSize * (page - 1)) + .Take(pageSize) + .ToList() + .Select(x => _factory.CreateDataShapedObject(x, fieldList, childrenRequested))); + } + catch (Exception ex) + { + Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); + + if (System.Diagnostics.Debugger.IsAttached) + System.Diagnostics.Debugger.Break(); + + return InternalServerError(); + } + } + + [HttpGet] + [VersionedRoute(template: "ResourceSchedules/{id}/{numChildLevels:int=0}", allowedVersion: 1)] + public async Task Get(System.Guid id, int numChildLevels) + { + try + { + if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } + var dbItem = await Repo.Get_ResourceScheduleAsync(id, numChildLevels); + + if (dbItem == null) + { + Warn("Unable to get object via Web API", LogMessageType.Instance.Warn_WebApi, httpResponseStatusCode: 404, url: Request.RequestUri.ToString()); + return NotFound(); + } + + RunCustomLogicOnGetEntityByPK(ref dbItem, id, numChildLevels); + return Ok(_factory.Create(dbItem)); + } + catch (Exception ex) + { + Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); + + if (System.Diagnostics.Debugger.IsAttached) + System.Diagnostics.Debugger.Break(); + + return InternalServerError(); + } + } + + [HttpPatch] + [VersionedRoute(template: "ResourceSchedules/{id}", allowedVersion: 1)] + public async Task Patch(System.Guid id, [FromBody] JsonPatchDocument patchDocument) + { + try + { + if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } + + if (patchDocument == null) + { + return BadRequest(); + } + + var dbItem = await Repo.Get_ResourceScheduleAsync(id, numChildLevels: 0); + if (dbItem == null) + { + return NotFound(); + } + + var dtoItem = _factory.Create(dbItem); // map + + // apply changes to the DTO + patchDocument.ApplyTo(dtoItem); + dtoItem.Id = id; + + // map the DTO with applied changes to the entity, & update + var updatedDBItem = _factory.Create(dtoItem); // map + var result = await Repo.UpdateAsync(updatedDBItem); + RunCustomLogicAfterUpdatePatch(ref updatedDBItem, ref result); + + if (result.Status == cghEnums.RepositoryActionStatus.Updated) + { + // map to dto + var patchedDTOItem = _factory.Create(result.Entity); + return Ok(patchedDTOItem); + } + + Warn("Unable to patch object via Web API", LogMessageType.Instance.Warn_WebApi, result.Exception, httpResponseStatusCode: 400, url: Request.RequestUri.ToString()); + return BadRequest(); + } + catch (Exception ex) + { + Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); + + if (System.Diagnostics.Debugger.IsAttached) + System.Diagnostics.Debugger.Break(); + + return InternalServerError(); + } + } + + [HttpPost] + [VersionedRoute(template: "ResourceSchedules", allowedVersion: 1)] + public async Task Post([FromBody] dtoRS.ResourceSchedule dtoItem) + { + try + { + if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } + + if (dtoItem == null) + { + return BadRequest(); + } + + RunCustomLogicBeforeInsert(ref dtoItem, ref httpStatusCode, ref message); + if (httpStatusCode == HttpStatusCode.PreconditionFailed) + { + Warn(message: message, logMessageType: LogMessageType.Instance.Warn_WebApi); + return Content(httpStatusCode, message); + } + + // try mapping & saving + var newDBItem = _factory.Create(dtoItem); + + var result = await Repo.InsertAsync(newDBItem); + RunCustomLogicAfterInsert(ref newDBItem, ref result); + + if (result.Status == cghEnums.RepositoryActionStatus.Created) + { // map to dto + var newDTOItem = _factory.Create(result.Entity); + var uriFormatted = Request.RequestUri.ToString().EndsWith("/") == true ? Request.RequestUri.ToString().Substring(0, Request.RequestUri.ToString().Length - 1) : Request.RequestUri.ToString(); + return Created($"{uriFormatted}/{newDTOItem.Id}", newDTOItem); + } + + Warn("Unable to create object via Web API", LogMessageType.Instance.Warn_WebApi, result.Exception, httpResponseStatusCode: 400, url: Request.RequestUri.ToString()); + return BadRequest(); + } + catch (Exception ex) + { + Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); + + if (System.Diagnostics.Debugger.IsAttached) + System.Diagnostics.Debugger.Break(); + + return InternalServerError(); + } + } + + [HttpPut] + [VersionedRoute(template: "ResourceSchedules/{id}", allowedVersion: 1)] + public async Task Put(System.Guid id, [FromBody] dtoRS.ResourceSchedule dtoItem) + { + try + { + if (!base.OnActionExecuting(out HttpStatusCode httpStatusCode, out string message)) { return Content(httpStatusCode, message); } + + if (dtoItem == null) + { + return BadRequest(); + } + + RunCustomLogicBeforeUpdate(ref dtoItem, ref httpStatusCode, ref message); + if (httpStatusCode == HttpStatusCode.PreconditionFailed) + { + Warn(message: message, logMessageType: LogMessageType.Instance.Warn_WebApi); + return Content(httpStatusCode, message); + } + + dtoItem.Id = id; + + var updatedDBItem = _factory.Create(dtoItem); // map + var result = await Repo.UpdateAsync(updatedDBItem); + RunCustomLogicAfterUpdatePut(ref updatedDBItem, ref result); + + if (result.Status == cghEnums.RepositoryActionStatus.Updated) + { + // map to dto + var updatedDTOItem = _factory.Create(result.Entity); + return Ok(updatedDTOItem); + } + else if (result.Status == cghEnums.RepositoryActionStatus.NotFound) + { + return NotFound(); + } + + Warn("Unable to update object via Web API", LogMessageType.Instance.Warn_WebApi, result.Exception, httpResponseStatusCode: 400, url: Request.RequestUri.ToString()); + return BadRequest(); + } + catch (Exception ex) + { + Error(message: ex.Message, logMessageType: LogMessageType.Instance.Exception_WebApi, ex: ex); + + if (System.Diagnostics.Debugger.IsAttached) + System.Diagnostics.Debugger.Break(); + + return InternalServerError(); + } + } + + partial void RunCustomLogicBeforeInsert(ref dtoRS.ResourceSchedule dtoItem, ref HttpStatusCode httpStatusCode, ref string message); + partial void RunCustomLogicBeforeUpdate(ref dtoRS.ResourceSchedule dtoItem, ref HttpStatusCode httpStatusCode, ref string message); + + partial void RunCustomLogicAfterInsert(ref CodeGenHero.ResourceScheduler.Repository.Entities.RS.ResourceSchedule newDBItem, ref IRepositoryActionResult result); + + partial void RunCustomLogicAfterUpdatePatch(ref CodeGenHero.ResourceScheduler.Repository.Entities.RS.ResourceSchedule updatedDBItem, ref IRepositoryActionResult result); + + partial void RunCustomLogicAfterUpdatePut(ref CodeGenHero.ResourceScheduler.Repository.Entities.RS.ResourceSchedule updatedDBItem, ref IRepositoryActionResult result); + + partial void RunCustomLogicOnGetEntityByPK(ref entRS.ResourceSchedule dbItem, System.Guid id, int numChildLevels); + + partial void RunCustomLogicAfterGetQueryableList(ref IQueryable dbItems, ref List filterList); + } } \ No newline at end of file diff --git a/src/CodeGenHero.ResourceScheduler.Xam/ResSched/Services/DataRetrievalService.cs b/src/CodeGenHero.ResourceScheduler.Xam/ResSched/Services/DataRetrievalService.cs index 53b640a..8942c01 100644 --- a/src/CodeGenHero.ResourceScheduler.Xam/ResSched/Services/DataRetrievalService.cs +++ b/src/CodeGenHero.ResourceScheduler.Xam/ResSched/Services/DataRetrievalService.cs @@ -313,9 +313,9 @@ private async Task RunQueuedResourceScheduleCreate(ModelData.Queue q) Debug.WriteLine($"Successfully Sent Queued PendingResourceSchedule Create Record"); return true; } - else if (result.StatusCode == System.Net.HttpStatusCode.Conflict) - { - //do something here with the conflict + else if (result.StatusCode == System.Net.HttpStatusCode.PreconditionFailed) + { // Do something here with the conflict + Debug.WriteLine($"Failure synchronizing PendingResourceSchedule Create record {q.RecordId}: {result.ReasonPhrase}"); } Analytics.TrackEvent($"Error Sending Queued PendingResourceSchedule Create record {q.RecordId}"); return false; @@ -336,9 +336,9 @@ private async Task RunQueuedResourceScheduleUpdate(ModelData.Queue q) Debug.WriteLine($"Successfully Sent Queued PendingResourceSchedule Update Record"); return true; } - else if (result.StatusCode == System.Net.HttpStatusCode.Conflict) - { - //do something here with the conflict + else if (result.StatusCode == System.Net.HttpStatusCode.PreconditionFailed) + { // Do something here with the conflict + Debug.WriteLine($"Failure synchronizing PendingResourceSchedule Update record {q.RecordId}: {result.ReasonPhrase}"); } Analytics.TrackEvent($"Error Sending Queued PendingResourceSchedule Update record {q.RecordId}"); return false;