using API.APIEndpointRecords;
using API.Schema.MangaContext;
using API.Workers;
using Asp.Versioning;
using log4net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using static Microsoft.AspNetCore.Http.StatusCodes;
// ReSharper disable InconsistentNaming
namespace API.Controllers;
[ApiVersion(2)]
[ApiController]
[Route("v{version:apiVersion}/[controller]")]
public class WorkerController(ILog Log) : Controller
{
///
/// Returns all
///
///
[HttpGet]
[ProducesResponseType(Status200OK, "application/json")]
public IActionResult GetAllWorkers()
{
return Ok(Tranga.Workers.ToArray());
}
///
/// Returns with requested
///
/// Array of .Key
///
[HttpPost("WithIDs")]
[ProducesResponseType(Status200OK, "application/json")]
public IActionResult GetJobs([FromBody]string[] WorkerIds)
{
return Ok(Tranga.Workers.Where(worker => WorkerIds.Contains(worker.Key)).ToArray());
}
///
/// Get all in requested
///
/// Requested
///
[HttpGet("State/{State}")]
[ProducesResponseType(Status200OK, "application/json")]
public IActionResult GetJobsInState(WorkerExecutionState State)
{
return Ok(Tranga.Workers.Where(worker => worker.State == State).ToArray());
}
///
/// Return with
///
/// .Key
///
/// with could not be found
[HttpGet("{WorkerId}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
public IActionResult GetJob(string WorkerId)
{
if(Tranga.Workers.FirstOrDefault(w => w.Key == WorkerId) is not { } worker)
return NotFound(nameof(WorkerId));
return Ok(worker);
}
///
/// Delete with and all child-s
///
/// .Key
///
/// with could not be found
[HttpDelete("{WorkerId}")]
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status404NotFound)]
public IActionResult DeleteJob(string WorkerId)
{
if(Tranga.Workers.FirstOrDefault(w => w.Key == WorkerId) is not { } worker)
return NotFound(nameof(WorkerId));
Tranga.RemoveWorker(worker);
return Ok();
}
///
/// Modify Job with ID
///
/// Job-ID
/// Fields to modify, set to null to keep previous value
/// Job modified
/// Malformed request
/// Job with ID not found
/// Error during Database Operation
[HttpPatch("{JobId}")]
[ProducesResponseType(Status202Accepted, "application/json")]
[ProducesResponseType(Status400BadRequest)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
public IActionResult ModifyJob(string JobId, [FromBody]ModifyJobRecord modifyJobRecord)
{
try
{
Job? ret = context.Jobs.Find(JobId);
if(ret is null)
return NotFound();
ret.RecurrenceMs = modifyJobRecord.RecurrenceMs ?? ret.RecurrenceMs;
ret.Enabled = modifyJobRecord.Enabled ?? ret.Enabled;
context.SaveChanges();
return new AcceptedResult(ret.Key, ret);
}
catch (Exception e)
{
Log.Error(e);
return StatusCode(500, e.Message);
}
}
///
/// Starts the Job with the requested ID
///
/// Job-ID
/// Start Jobs necessary for execution
/// Job started
/// Job with ID not found
/// Job was already running
/// Error during Database Operation
[HttpPost("{JobId}/Start")]
[ProducesResponseType(Status202Accepted)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status409Conflict)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
public IActionResult StartJob(string JobId, [FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)]bool startDependencies = false)
{
Job? ret = context.Jobs.Find(JobId);
if (ret is null)
return NotFound();
List dependencies = startDependencies ? ret.GetDependenciesAndSelf() : [ret];
try
{
if(dependencies.Any(d => d.state >= JobState.Running && d.state < JobState.Completed))
return new ConflictResult();
dependencies.ForEach(d =>
{
d.LastExecution = DateTime.UnixEpoch;
d.state = JobState.CompletedWaiting;
});
context.SaveChanges();
return Accepted();
}
catch (Exception e)
{
Log.Error(e);
return StatusCode(500, e.Message);
}
}
///
/// Stops the Job with the requested ID
///
/// Job-ID
/// NOT IMPLEMENTED
[HttpPost("{JobId}/Stop")]
[ProducesResponseType(Status501NotImplemented)]
public IActionResult StopJob(string JobId)
{
return StatusCode(Status501NotImplemented);
}
///
/// Removes failed and completed Jobs (that are not recurring)
///
/// Job started
/// Error during Database Operation
[HttpPost("Cleanup")]
public IActionResult CleanupJobs()
{
try
{
context.Jobs.RemoveRange(context.Jobs.Where(j => j.state == JobState.Failed || j.state == JobState.Completed));
context.SaveChanges();
return Ok();
}
catch (Exception e)
{
Log.Error(e);
return StatusCode(500, e.Message);
}
}
}