diff --git a/backend/api/Controllers/MissionController.cs b/backend/api/Controllers/MissionController.cs index 030b62e05..ea672e46d 100644 --- a/backend/api/Controllers/MissionController.cs +++ b/backend/api/Controllers/MissionController.cs @@ -49,69 +49,10 @@ ISourceService sourceService } /// - /// List all mission runs in the Flotilla database + /// List all mission definitions in the Flotilla database /// /// - /// This query gets all mission runs - /// - [HttpGet("runs")] - [Authorize(Roles = Role.Any)] - [ProducesResponseType(typeof(IList), StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status403Forbidden)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task>> GetMissionRuns( - [FromQuery] MissionRunQueryStringParameters parameters - ) - { - if (parameters.MaxDesiredStartTime < parameters.MinDesiredStartTime) - { - return BadRequest("Max DesiredStartTime cannot be less than min DesiredStartTime"); - } - if (parameters.MaxStartTime < parameters.MinStartTime) - { - return BadRequest("Max StartTime cannot be less than min StartTime"); - } - if (parameters.MaxEndTime < parameters.MinEndTime) - { - return BadRequest("Max EndTime cannot be less than min EndTime"); - } - - PagedList missionRuns; - try - { - missionRuns = await _missionRunService.ReadAll(parameters); - } - catch (InvalidDataException e) - { - _logger.LogError(e.Message); - return BadRequest(e.Message); - } - - var metadata = new - { - missionRuns.TotalCount, - missionRuns.PageSize, - missionRuns.CurrentPage, - missionRuns.TotalPages, - missionRuns.HasNext, - missionRuns.HasPrevious - }; - - Response.Headers.Add( - QueryStringParameters.PaginationHeader, - JsonSerializer.Serialize(metadata) - ); - - return Ok(missionRuns); - } - - /// - /// List all mission definitions in the Flotilla database - /// - /// - /// This query gets all mission definitions + /// This query gets all mission definitions /// [HttpGet("definitions")] [Authorize(Roles = Role.Any)] @@ -131,7 +72,7 @@ [FromQuery] MissionDefinitionQueryStringParameters parameters } catch (InvalidDataException e) { - _logger.LogError(e.Message); + _logger.LogError(e, "{ErrorMessage}", e.Message); return BadRequest(e.Message); } @@ -155,28 +96,7 @@ [FromQuery] MissionDefinitionQueryStringParameters parameters } /// - /// Lookup mission run by specified id. - /// - [HttpGet] - [Authorize(Roles = Role.Any)] - [Route("runs/{id}")] - [ProducesResponseType(typeof(MissionRun), StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status403Forbidden)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task> GetMissionRunById([FromRoute] string id) - { - var missioRun = await _missionRunService.ReadById(id); - if (missioRun == null) - { - return NotFound($"Could not find mission run with id {id}"); - } - return Ok(missioRun); - } - - /// - /// Lookup mission definition by specified id. + /// Lookup mission definition by specified id. /// [HttpGet] [Authorize(Roles = Role.Any)] @@ -190,13 +110,15 @@ public async Task> GetCondensed { var missionDefinition = await _missionDefinitionService.ReadById(id); if (missionDefinition == null) + { return NotFound($"Could not find mission definition with id {id}"); + } var missionDefinitionResponse = new CondensedMissionDefinitionResponse(missionDefinition); return Ok(missionDefinitionResponse); } /// - /// Lookup mission definition by specified id. + /// Lookup mission definition by specified id. /// [HttpGet] [Authorize(Roles = Role.Any)] @@ -210,7 +132,9 @@ public async Task> GetMissionDefinitionB { var missionDefinition = await _missionDefinitionService.ReadById(id); if (missionDefinition == null) + { return NotFound($"Could not find mission definition with id {id}"); + } var missionDefinitionResponse = new MissionDefinitionResponse(_missionDefinitionService, missionDefinition); return Ok(missionDefinitionResponse); } @@ -323,7 +247,7 @@ [FromBody] ScheduleMissionQuery scheduledMissionQuery var newMissionRun = await _missionRunService.Create(missionRun); - return CreatedAtAction(nameof(GetMissionRunById), new + return CreatedAtAction(nameof(Schedule), new { id = newMissionRun.Id }, newMissionRun); @@ -363,7 +287,7 @@ [FromBody] ScheduledMissionQuery scheduledMissionQuery if (e.StatusCode.HasValue && (int)e.StatusCode.Value == 404) { _logger.LogWarning( - "Could not find echo mission with id={id}", + "Could not find echo mission with id={Id}", scheduledMissionQuery.EchoMissionId ); return NotFound("Echo mission not found"); @@ -374,16 +298,16 @@ [FromBody] ScheduledMissionQuery scheduledMissionQuery } catch (JsonException e) { - string message = "Error deserializing mission from Echo"; - _logger.LogError(e, "{message}", message); - return StatusCode(StatusCodes.Status500InternalServerError, message); + const string Message = "Error deserializing mission from Echo"; + _logger.LogError(e, "{Message}", Message); + return StatusCode(StatusCodes.Status500InternalServerError, Message); } catch (InvalidDataException e) { - string message = - "Can not schedule mission because EchoMission is invalid. One or more tasks does not contain a robot pose."; - _logger.LogError(e, message); - return StatusCode(StatusCodes.Status502BadGateway, message); + const string Message = + "Can not schedule mission because EchoMission is invalid. One or more tasks does not contain a robot pose"; + _logger.LogError(e, "Message", Message); + return StatusCode(StatusCodes.Status502BadGateway, Message); } var missionTasks = echoMission.Tags @@ -460,7 +384,7 @@ [FromBody] ScheduledMissionQuery scheduledMissionQuery var newMissionRun = await _missionRunService.Create(missionRun); - return CreatedAtAction(nameof(GetMissionRunById), new + return CreatedAtAction(nameof(Create), new { id = newMissionRun.Id }, newMissionRun); @@ -497,10 +421,7 @@ [FromBody] CustomMissionQuery customMissionQuery return NotFound("Unable to retrieve plant information from Echo"); } - var installationResult = installationResults - .Where( - installation => installation.PlantCode.ToUpperInvariant() == customMissionQuery.InstallationCode.ToUpperInvariant() - ).FirstOrDefault(); + var installationResult = installationResults.FirstOrDefault(installation => installation.PlantCode.ToUpperInvariant() == customMissionQuery.InstallationCode.ToUpperInvariant()); if (installationResult == null) { return NotFound($"Could not find installation with id {customMissionQuery.InstallationCode}"); @@ -518,10 +439,10 @@ [FromBody] CustomMissionQuery customMissionQuery MissionDefinition? existingMissionDefinition = null; if (source == null) { - string sourceURL = _customMissionService.UploadSource(missionTasks); + string sourceUrl = _customMissionService.UploadSource(missionTasks); source = new Source { - SourceId = sourceURL, + SourceId = sourceUrl, Type = MissionSourceType.Custom }; } @@ -573,14 +494,14 @@ [FromBody] CustomMissionQuery customMissionQuery var newMissionRun = await _missionRunService.Create(scheduledMission); - return CreatedAtAction(nameof(GetMissionRunById), new + return CreatedAtAction(nameof(Create), new { id = newMissionRun.Id }, newMissionRun); } /// - /// Updates a mission definition in the database based on id + /// Updates a mission definition in the database based on id /// /// The mission definition was successfully updated /// The mission definition data is invalid @@ -599,17 +520,23 @@ public async Task> UpdateMissio [FromBody] UpdateMissionDefinitionQuery missionDefinitionQuery ) { - _logger.LogInformation("Updating mission definition with id '{id}'", id); + _logger.LogInformation("Updating mission definition with id '{Id}'", id); if (!ModelState.IsValid) + { return BadRequest("Invalid data."); + } var missionDefinition = await _missionDefinitionService.ReadById(id); if (missionDefinition == null) + { return NotFound($"Could not find mission definition with id '{id}'"); + } if (missionDefinitionQuery.Name == null) + { return BadRequest("Name cannot be null."); + } missionDefinition.Name = missionDefinitionQuery.Name; missionDefinition.Comment = missionDefinitionQuery.Comment; @@ -620,7 +547,7 @@ [FromBody] UpdateMissionDefinitionQuery missionDefinitionQuery } /// - /// Deletes the mission definition with the specified id from the database. + /// Deletes the mission definition with the specified id from the database. /// [HttpDelete] [Authorize(Roles = Role.Admin)] @@ -634,30 +561,11 @@ public async Task> DeleteMissionDefiniti { var missionDefinition = await _missionDefinitionService.Delete(id); if (missionDefinition is null) + { return NotFound($"Mission definition with id {id} not found"); + } var missionDefinitionResponse = new MissionDefinitionResponse(_missionDefinitionService, missionDefinition); return Ok(missionDefinitionResponse); } - - /// - /// Deletes the mission run with the specified id from the database. - /// - [HttpDelete] - [Authorize(Roles = Role.Admin)] - [Route("runs/{id}")] - [ProducesResponseType(typeof(MissionRun), StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - [ProducesResponseType(StatusCodes.Status403Forbidden)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task> DeleteMissionRun([FromRoute] string id) - { - var missionRun = await _missionRunService.Delete(id); - if (missionRun is null) - { - return NotFound($"Mission run with id {id} not found"); - } - return Ok(missionRun); - } } } diff --git a/backend/api/Controllers/MissionRunController.cs b/backend/api/Controllers/MissionRunController.cs new file mode 100644 index 000000000..257153100 --- /dev/null +++ b/backend/api/Controllers/MissionRunController.cs @@ -0,0 +1,122 @@ +using System.Text.Json; +using Api.Controllers.Models; +using Api.Database.Models; +using Api.Services; +using Api.Utilities; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +namespace Api.Controllers +{ + [ApiController] + [Route("missions/runs")] + public class MissionRunController : ControllerBase + { + private readonly ILogger _logger; + private readonly IMissionRunService _missionRunService; + + public MissionRunController(ILogger logger, IMissionRunService missionRunService) + { + _logger = logger; + _missionRunService = missionRunService; + } + + /// + /// List all mission runs in the Flotilla database + /// + /// + /// This query gets all mission runs + /// + [HttpGet("")] + [Authorize(Roles = Role.Any)] + [ProducesResponseType(typeof(IList), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task>> GetMissionRuns( + [FromQuery] MissionRunQueryStringParameters parameters + ) + { + if (parameters.MaxDesiredStartTime < parameters.MinDesiredStartTime) + { + return BadRequest("Max DesiredStartTime cannot be less than min DesiredStartTime"); + } + if (parameters.MaxStartTime < parameters.MinStartTime) + { + return BadRequest("Max StartTime cannot be less than min StartTime"); + } + if (parameters.MaxEndTime < parameters.MinEndTime) + { + return BadRequest("Max EndTime cannot be less than min EndTime"); + } + + PagedList missionRuns; + try + { + missionRuns = await _missionRunService.ReadAll(parameters); + } + catch (InvalidDataException e) + { + _logger.LogError(e, "Message", e.Message); + return BadRequest(e.Message); + } + + var metadata = new + { + missionRuns.TotalCount, + missionRuns.PageSize, + missionRuns.CurrentPage, + missionRuns.TotalPages, + missionRuns.HasNext, + missionRuns.HasPrevious + }; + + Response.Headers.Add( + QueryStringParameters.PaginationHeader, + JsonSerializer.Serialize(metadata) + ); + + return Ok(missionRuns); + } + /// + /// Lookup mission run by specified id. + /// + [HttpGet] + [Authorize(Roles = Role.Any)] + [Route("{id}")] + [ProducesResponseType(typeof(MissionRun), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task> GetMissionRunById([FromRoute] string id) + { + var missionRun = await _missionRunService.ReadById(id); + if (missionRun == null) + { + return NotFound($"Could not find mission run with id {id}"); + } + return Ok(missionRun); + } + /// + /// Deletes the mission run with the specified id from the database. + /// + [HttpDelete] + [Authorize(Roles = Role.Admin)] + [Route("{id}")] + [ProducesResponseType(typeof(MissionRun), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task> DeleteMissionRun([FromRoute] string id) + { + var missionRun = await _missionRunService.Delete(id); + if (missionRun is null) + { + return NotFound($"Mission run with id {id} not found"); + } + return Ok(missionRun); + } + } +}