diff --git a/Controllers/ProfilerController.cs b/Controllers/V1/ProfilerController.cs
similarity index 98%
rename from Controllers/ProfilerController.cs
rename to Controllers/V1/ProfilerController.cs
index 34e469b..deab530 100644
--- a/Controllers/ProfilerController.cs
+++ b/Controllers/V1/ProfilerController.cs
@@ -4,10 +4,11 @@
using ParadisePublicAPI.ProfilerDatabase;
using Swashbuckle.AspNetCore.Annotations;
-namespace ParadisePublicAPI.Controllers {
+namespace ParadisePublicAPI.Controllers.V1 {
///
/// Profiler
///
+ [ApiExplorerSettings(GroupName = "v1")]
[SwaggerTag("Query proc times from the profiler. Old data may be cleared with no notice")]
[Route("profiler")]
public class ProfilerController : Controller {
diff --git a/Controllers/StatsController.cs b/Controllers/V1/StatsController.cs
similarity index 98%
rename from Controllers/StatsController.cs
rename to Controllers/V1/StatsController.cs
index 314d798..adc9aea 100644
--- a/Controllers/StatsController.cs
+++ b/Controllers/V1/StatsController.cs
@@ -10,10 +10,11 @@
using ParadisePublicAPI.Models;
using Swashbuckle.AspNetCore.Annotations;
-namespace ParadisePublicAPI.Controllers {
+namespace ParadisePublicAPI.Controllers.V1 {
///
/// Controller for querying statistics from game rounds
///
+ [ApiExplorerSettings(GroupName = "v1")]
[SwaggerTag("Query statistics from game rounds")]
[Route("stats")]
public class StatsController : Controller {
diff --git a/Controllers/V2/StatsController.cs b/Controllers/V2/StatsController.cs
new file mode 100644
index 0000000..c1c5794
--- /dev/null
+++ b/Controllers/V2/StatsController.cs
@@ -0,0 +1,62 @@
+using System.ComponentModel.DataAnnotations;
+using Microsoft.AspNetCore.Mvc;
+using ParadisePublicAPI.Database;
+using Swashbuckle.AspNetCore.Annotations;
+
+namespace ParadisePublicAPI.Controllers.V2
+{
+ ///
+ /// Controller for querying statistics from game rounds
+ ///
+ [ApiExplorerSettings(GroupName = "v2")]
+ [SwaggerTag("Query statistics from game rounds")]
+ [Route("v2/stats")]
+ public class StatsController : Controller {
+ private readonly paradise_gamedbContext _context;
+
+ public StatsController(paradise_gamedbContext context) {
+ _context = context;
+ }
+
+ ///
+ /// Gets the data of a specific feedback key for the specified rounds.
+ ///
+ /// The name of the desired feedback key.
+ /// The start date to retrieve data for.
+ /// The end date to retrieve data for.
+ /// A list of key-value objects, where "data" is the feedback data and "round_id" is the round ID the data was recorded.
+ /// Round data successfully retrieved
+ /// Rate limited by server
+ [HttpGet("feedback")]
+ public IActionResult GetFeedbackRow([FromQuery, Required] string key_name, [FromQuery, Required] DateOnly start_date, [FromQuery, Required] DateOnly end_date) {
+ if (key_name == null) {
+ return BadRequest("No feedback key_name specified.");
+ }
+ if (start_date > end_date) {
+ return BadRequest($"start_date {start_date} is later than end_date {end_date}");
+ }
+ if (start_date.AddMonths(2) < end_date) {
+ return BadRequest("Only two months of data may be requested in one query.");
+ }
+ var start_datetime = start_date.ToDateTime(TimeOnly.MinValue);
+ var end_datetime = end_date.ToDateTime(TimeOnly.MaxValue);
+ var feedbacks = (from feedback in _context.Feedbacks
+ join round in _context.Rounds on feedback.RoundId equals round.Id
+ orderby round.Id
+ where feedback.KeyName == key_name
+ && round.ShutdownDatetime != null
+ && round.InitializeDatetime >= start_datetime
+ && round.InitializeDatetime <= end_datetime
+ // feedback.JSON begins with `{"data": ...` so we strip the first curly brace
+ // in order to interpolate the rest of the JSON data into the resultant string
+ select $"{{\"round_id\": {round.Id}, {feedback.Json.Substring(1)}");
+
+ return new ContentResult()
+ {
+ Content = "[" + string.Join(", ", feedbacks) + "]",
+ ContentType = "application/json",
+ StatusCode = 200
+ };
+ }
+ }
+}
diff --git a/Program.cs b/Program.cs
index 22af195..a19750d 100644
--- a/Program.cs
+++ b/Program.cs
@@ -21,6 +21,12 @@
Title = "Paradise Public API",
Description = "Paradise Station public API for data querying. This API may change with no notice.
Source: https://github.com/ParadiseSS13/ParadisePublicAPI
Requests are limited to 500 every minute, and 3600 every hour."
});
+ options.SwaggerDoc("v2", new OpenApiInfo
+ {
+ Version = "v2",
+ Title = "Paradise Public API",
+ Description = "Paradise Station public API for data querying. This API may change with no notice.
Source: https://github.com/ParadiseSS13/ParadisePublicAPI
Requests are limited to 500 every minute, and 3600 every hour."
+ });
});
// Setup Game DB
@@ -71,6 +77,7 @@
app.UseSwagger();
app.UseSwaggerUI(options => {
options.SwaggerEndpoint("swagger/v1/swagger.json", "v1");
+ options.SwaggerEndpoint("swagger/v2/swagger.json", "v2");
options.RoutePrefix = String.Empty;
});