using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using AyaNova.Models; using AyaNova.Api.ControllerHelpers; using AyaNova.Biz; namespace AyaNova.Api.Controllers { [ApiController] [ApiVersion("8.0")] [Route("api/v{version:apiVersion}/workorders")] [Produces("application/json")] [Authorize] public class WorkOrderController : ControllerBase { private readonly AyContext ct; private readonly ILogger log; private readonly ApiServerState serverState; /// /// ctor /// /// /// /// public WorkOrderController(AyContext dbcontext, ILogger logger, ApiServerState apiServerState) { ct = dbcontext; log = logger; serverState = apiServerState; } #region WorkOrder top level routes /// /// Create WorkOrder "header" /// /// WorkOrder top level only, no descendents are evaluated /// From route path /// WorkOrder "header" object [HttpPost] public async Task PostWorkOrder([FromBody] WorkOrder newObject, ApiVersion apiVersion) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); WorkOrder o = await biz.CreateAsync(newObject); if (o == null) return BadRequest(new ApiErrorResponse(biz.Errors)); else return CreatedAtAction(nameof(WorkOrderController.GetWorkOrder), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); } /// /// Duplicate WorkOrder /// (Wiki and Attachments are not duplicated) /// /// Source object id /// From route path /// Full WorkOrder object including all descendents [HttpPost("duplicate/{id}")] public async Task DuplicateWorkOrder([FromRoute] long id, ApiVersion apiVersion) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); WorkOrder o = await biz.DuplicateAsync(id); if (o == null) return BadRequest(new ApiErrorResponse(biz.Errors)); else return CreatedAtAction(nameof(WorkOrderController.GetWorkOrder), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); } /// /// Get full WorkOrder object /// /// /// Entire WorkOrder object including all descendents [HttpGet("{id}")] public async Task GetWorkOrder([FromRoute] long id) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); var o = await biz.GetAsync(id); if (o == null) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); return Ok(ApiOkResponse.Response(o, !Authorized.HasModifyRole(HttpContext.Items, biz.BizType))); } /// /// Put (update) WorkOrder /// This route does not evaluate nor update nor return the entire WorkOrder object graph /// only the "header" or top level /// Descendent objects must be updated via their individual routes seperately /// /// WorkOrder id /// WorkOrder top level only, no descendents are evaluated /// New concurrency token [HttpPut("{id}")] public async Task PutWorkOrder([FromRoute] long id, [FromBody] WorkOrder updatedObject) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); var o = await biz.PutAsync(id, updatedObject); if (o == null) { if (biz.Errors.Exists(m => m.Code == ApiErrorCode.CONCURRENCY_CONFLICT)) return StatusCode(409, new ApiErrorResponse(biz.Errors)); else return BadRequest(new ApiErrorResponse(biz.Errors)); } return Ok(ApiOkResponse.Response(new { ConcurrencyToken = o.ConcurrencyToken }, true)); } //TODO: will need to traverse, don't need it now for PROPOSAL testing so not coding it yet // /// // /// Delete WorkOrder // /// // /// // /// Ok // [HttpDelete("{id}")] // public async Task DeleteWorkOrder([FromRoute] long id) // { // if (!serverState.IsOpen) // return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); // if (!ModelState.IsValid) // return BadRequest(new ApiErrorResponse(ModelState)); // //Instantiate the business object handler // WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); // var o = await biz.GetAsync(id, false); // if (o == null) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // if (!Authorized.HasDeleteRole(HttpContext.Items, biz.BizType)) // return StatusCode(403, new ApiNotAuthorizedResponse()); // if (!await biz.DeleteAsync(o)) // return BadRequest(new ApiErrorResponse(biz.Errors)); // return NoContent(); // } #endregion WorkOrderTopLevel routes #region WorkOrderItem /// /// Create WorkOrderItem /// /// WorkOrderItem level only no descendents /// /// WorkOrderItem object (no descendents) [HttpPost("items")] public async Task PostWorkOrderItem([FromBody] WorkOrderItem newObject, ApiVersion apiVersion) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); if (!Authorized.HasCreateRole(HttpContext.Items, AyaType.WorkOrderItem)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); WorkOrderItem o = await biz.CreateItemAsync(newObject); if (o == null) return BadRequest(new ApiErrorResponse(biz.Errors)); else return CreatedAtAction(nameof(WorkOrderController.GetWorkOrderItem), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); } /// /// Get WorkOrderItem object /// /// /// A single WorkOrderItem [HttpGet("items/{WorkOrderItemId}")] public async Task GetWorkOrderItem([FromRoute] long WorkOrderItemId) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); var o = await biz.GetItemAsync(WorkOrderItemId); if (o == null) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); return Ok(ApiOkResponse.Response(o, !Authorized.HasModifyRole(HttpContext.Items, AyaType.WorkOrderItem))); } // /// // /// Put (update) WorkOrderItem // /// // /// // /// // /// // [HttpPut("items/{WorkOrderItemId}")] // public async Task PutWorkOrderItem([FromRoute] long id, [FromBody] WorkOrderItem updatedObject) // { // if (!serverState.IsOpen) // return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); // if (!ModelState.IsValid) // return BadRequest(new ApiErrorResponse(ModelState)); // //Instantiate the business object handler // WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); // var o = await biz.GetAsync(id, false); // if (o == null) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType)) // return StatusCode(403, new ApiNotAuthorizedResponse()); // // try // // { // // if (!await biz.PutAsync(o, updatedObject)) // // return BadRequest(new ApiErrorResponse(biz.Errors)); // // } // // catch (DbUpdateConcurrencyException) // // { // // if (!await biz.ExistsAsync(id)) // // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // // else // // return StatusCode(409, new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT)); // // } // // return Ok(ApiOkResponse.Response(new { ConcurrencyToken = o.ConcurrencyToken }, true)); // return StatusCode(501); // } /// /// Delete WorkOrderItem /// /// /// Ok-no content [HttpDelete("items/{WorkOrderItemId}")] public async Task DeleteWorkOrderItem([FromRoute] long workOrderItemId) { //NOTE: we don't need the workorder id in the route because the workorder item must contain the workorder id anyway //WorkOrder/{woid}/WorkOrderItems <- all workorderitems, post to add new, put to update all as a collection //WorkOrder/{WorkOrderId}/WorkOrderItems if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); //Instantiate the business object handler WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); if (!Authorized.HasDeleteRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); //******************************************************************************* //NOTE: I'm thinking there should be no db access in controller //let the biz object return not found if necessary //******************************************************************************* // var o = await biz.GetAsync(workOrderId, false); // if (o == null) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // //Make sure the item exists first before getting into it // if (!o.WorkOrderItems.Exists(m => m.Id == workOrderItemId)) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); //stubbed out for now just to see routes // if (!await biz.DeleteItemsAsync(o)) // return BadRequest(new ApiErrorResponse(biz.Errors)); // return NoContent(); return StatusCode(501); } #endregion workorderitem #region WorkOrderItemLabor /// /// Create WorkOrderItemLabor /// /// /// From route path /// [HttpPost("items/labors")] public async Task PostWorkOrderItemLabor([FromBody] WorkOrderItemLabor newObject, ApiVersion apiVersion) { //NOTE: we don't need the workorder id in the route because the workorder item must contain the workorder id anyway if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); //Instantiate the business object handler WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); //If a user has change roles if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); // //Create and validate // WorkOrderItemLabor o = await biz.CreateAsync(newObject); // if (o == null) // return BadRequest(new ApiErrorResponse(biz.Errors)); // else // return CreatedAtAction(nameof(WorkOrderController.GetWorkOrder), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); return StatusCode(501); } /// /// Get WorkOrderItemLabor object /// /// /// A single WorkOrderItemLabor [HttpGet("items/labors/{WorkOrderItemLaborId}")] public async Task GetWorkOrderItemLabor([FromRoute] long WorkOrderItemLaborId) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); //Instantiate the business object handler WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); //NOTE: This is the first check and often the only check but in some cases with some objects this will also need to check biz object rules if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); // var o = await biz.GetAsync(id); // if (o == null) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // // NOTE: HERE would be the second check of biz rules before returning the object // // in cases where there is also a business rule to affect retrieval on top of basic rights // return Ok(ApiOkResponse.Response(o, !Authorized.HasModifyRole(HttpContext.Items, biz.BizType))); return StatusCode(501); } /// /// Put (update) WorkOrderItemLabor /// /// /// /// [HttpPut("items/labors/{WorkOrderItemLaborId}")] public async Task PutWorkOrderItemLabor([FromRoute] long id, [FromBody] WorkOrderItemLabor updatedObject) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); //Instantiate the business object handler WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); var o = await biz.GetAsync(id, false); if (o == null) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); // try // { // if (!await biz.PutAsync(o, updatedObject)) // return BadRequest(new ApiErrorResponse(biz.Errors)); // } // catch (DbUpdateConcurrencyException) // { // if (!await biz.ExistsAsync(id)) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // else // return StatusCode(409, new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT)); // } // return Ok(ApiOkResponse.Response(new { ConcurrencyToken = o.ConcurrencyToken }, true)); return StatusCode(501); } /// /// Delete WorkOrderItemLabor /// /// /// Ok-no content [HttpDelete("items/labors/{WorkOrderItemLaborId}")] public async Task DeleteWorkOrderItemLabor([FromRoute] long workOrderItemLaborId) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); //Instantiate the business object handler WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); if (!Authorized.HasDeleteRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); //******************************************************************************* //NOTE: I'm thinking there should be no db access in controller //let the biz object return not found if necessary //******************************************************************************* // var o = await biz.GetAsync(workOrderId, false); // if (o == null) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // //Get WorkOrderItem // var woitem = o.WorkOrderItems.FirstOrDefault(m => m.Id == workOrderItemId); // if (woitem == null) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // //Get WorkOrderItemLabor // var woitemlabor = woitem.WorkOrderItemLabors.FirstOrDefault(m => m.Id == workOrderItemLaborId); // if (woitem == null) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); //stubbed out for now just to see routes // if (!await biz.DeleteWorkOrderItemLaborAsync(woitemlabor))//may need more info, not sure // return BadRequest(new ApiErrorResponse(biz.Errors)); //return NoContent(); return StatusCode(501); } #endregion WorkOrderItemLabor #region WorkOrderItemPart /// /// Create WorkOrderItemPart /// /// /// From route path /// [HttpPost("items/parts")] public async Task PostWorkOrderItemPart([FromBody] WorkOrderItemPart newObject, ApiVersion apiVersion) { //NOTE: we don't need the workorder id in the route because the workorder item must contain the workorder id anyway if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); //Instantiate the business object handler WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); //If a user has change roles if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); // //Create and validate // WorkOrderItemPart o = await biz.CreateAsync(newObject); // if (o == null) // return BadRequest(new ApiErrorResponse(biz.Errors)); // else // return CreatedAtAction(nameof(WorkOrderController.GetWorkOrder), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); return StatusCode(501); } /// /// Get WorkOrderItemPart object /// /// /// A single WorkOrderItemPart [HttpGet("items/parts/{WorkOrderItemPartId}")] public async Task GetWorkOrderItemPart([FromRoute] long WorkOrderItemPartId) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); //Instantiate the business object handler WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); //NOTE: This is the first check and often the only check but in some cases with some objects this will also need to check biz object rules if (!Authorized.HasReadFullRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); // var o = await biz.GetAsync(id); // if (o == null) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // // NOTE: HERE would be the second check of biz rules before returning the object // // in cases where there is also a business rule to affect retrieval on top of basic rights // return Ok(ApiOkResponse.Response(o, !Authorized.HasModifyRole(HttpContext.Items, biz.BizType))); return StatusCode(501); } /// /// Put (update) WorkOrderItemPart /// /// /// /// [HttpPut("items/parts/{WorkOrderItemPartId}")] public async Task PutWorkOrderItemPart([FromRoute] long id, [FromBody] WorkOrderItemPart updatedObject) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); //Instantiate the business object handler WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); var o = await biz.GetAsync(id, false); if (o == null) return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); // try // { // if (!await biz.PutAsync(o, updatedObject)) // return BadRequest(new ApiErrorResponse(biz.Errors)); // } // catch (DbUpdateConcurrencyException) // { // if (!await biz.ExistsAsync(id)) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // else // return StatusCode(409, new ApiErrorResponse(ApiErrorCode.CONCURRENCY_CONFLICT)); // } // return Ok(ApiOkResponse.Response(new { ConcurrencyToken = o.ConcurrencyToken }, true)); return StatusCode(501); } /// /// Delete WorkOrderItemPart /// /// /// Ok-no content [HttpDelete("items/parts/{WorkOrderItemPartId}")] public async Task DeleteWorkOrderItemPart([FromRoute] long workOrderItemPartId) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason)); if (!ModelState.IsValid) return BadRequest(new ApiErrorResponse(ModelState)); //Instantiate the business object handler WorkOrderBiz biz = WorkOrderBiz.GetBiz(ct, HttpContext); if (!Authorized.HasDeleteRole(HttpContext.Items, biz.BizType)) return StatusCode(403, new ApiNotAuthorizedResponse()); //******************************************************************************* //NOTE: I'm thinking there should be no db access in controller //let the biz object return not found if necessary //******************************************************************************* // var o = await biz.GetAsync(workOrderId, false); // if (o == null) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); // //Make sure the item exists first before getting into it // if (!o.WorkOrderItems.Exists(m => m.Id == workOrderItemId)) // return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND)); //stubbed out for now just to see routes // if (!await biz.DeleteItemsAsync(o)) // return BadRequest(new ApiErrorResponse(biz.Errors)); //return NoContent(); return StatusCode(501); } #endregion WorkOrderItemPart //------------ }//eoc }//eons