From 0862c7130f5193c42648f632a1dcaa48c06574dd Mon Sep 17 00:00:00 2001
From: Cucumberrbob <128094686+Cucumberrbob@users.noreply.github.com>
Date: Thu, 6 Mar 2025 21:10:53 +0000
Subject: [PATCH] Add openapi compatible xmldoc for `TorrentsController`
---
.../Controllers/TorrentsController.cs | 209 ++++++++++++++++--
1 file changed, 194 insertions(+), 15 deletions(-)
diff --git a/server/RdtClient.Web/Controllers/TorrentsController.cs b/server/RdtClient.Web/Controllers/TorrentsController.cs
index d6c6ec0..1783c05 100644
--- a/server/RdtClient.Web/Controllers/TorrentsController.cs
+++ b/server/RdtClient.Web/Controllers/TorrentsController.cs
@@ -1,4 +1,5 @@
-using System.Text.RegularExpressions;
+using System.ComponentModel.DataAnnotations;
+using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MonoTorrent;
@@ -6,15 +7,26 @@ using RdtClient.Data.Models.TorrentClient;
using RdtClient.Service.Helpers;
using RdtClient.Service.Services;
using Torrent = RdtClient.Data.Models.Data.Torrent;
+using System.Text.Json.Serialization;
+using NSwag.Annotations;
namespace RdtClient.Web.Controllers;
+///
+/// Controller for managing torrents and their downloads
+///
[Authorize(Policy = "AuthSetting")]
[Route("Api/Torrents")]
public class TorrentsController(ILogger logger, Torrents torrents, TorrentRunner torrentRunner) : Controller
{
+ ///
+ /// Retrieves all torrents and their associated downloads
+ ///
+ /// List of all torrents with their download status
+ /// Returns the list of torrents
[HttpGet]
[Route("")]
+ [ProducesResponseType(typeof(IList), StatusCodes.Status200OK)]
public async Task>> GetAll()
{
var results = await torrents.Get();
@@ -28,8 +40,17 @@ public class TorrentsController(ILogger logger, Torrents tor
return Ok(results);
}
+ ///
+ /// Retrieves a specific torrent by its ID
+ ///
+ /// The unique identifier of the torrent
+ /// The requested torrent details
+ /// Returns the requested torrent
+ /// Torrent not found
[HttpGet]
[Route("Get/{torrentId:guid}")]
+ [ProducesResponseType(typeof(Torrent), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task> GetById(Guid torrentId)
{
var torrent = await torrents.GetById(torrentId);
@@ -46,11 +67,13 @@ public class TorrentsController(ILogger logger, Torrents tor
}
///
- /// Used for debugging only. Force a tick.
+ /// Forces an immediate processing cycle for debugging purposes
///
- ///
+ /// Success status
+ /// Processing cycle completed successfully
[HttpGet]
[Route("Tick")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
public async Task Tick()
{
await torrentRunner.Tick();
@@ -58,11 +81,21 @@ public class TorrentsController(ILogger logger, Torrents tor
return Ok();
}
+ ///
+ /// Adds a new torrent file with configuration
+ ///
+ /// The .torrent file to add
+ /// Configuration for the torrent download
+ /// Success status
+ /// Torrent added successfully
+ /// Invalid file or configuration provided
[HttpPost]
[Route("UploadFile")]
- public async Task UploadFile([FromForm] IFormFile? file,
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(String), StatusCodes.Status400BadRequest)]
+ public async Task UploadFile([OpenApiFile] IFormFile? file,
[ModelBinder(BinderType = typeof(JsonModelBinder))]
- TorrentControllerUploadFileRequest? formData)
+ [FromForm] TorrentControllerUploadFileRequest? formData)
{
if (file == null || file.Length <= 0)
{
@@ -89,15 +122,24 @@ public class TorrentsController(ILogger logger, Torrents tor
return Ok();
}
+ ///
+ /// Adds a new torrent using a magnet link
+ ///
+ /// The magnet link and torrent configuration
+ /// Success status
+ /// Magnet link processed successfully
+ /// Invalid magnet link or configuration
[HttpPost]
[Route("UploadMagnet")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(String), StatusCodes.Status400BadRequest)]
public async Task UploadMagnet([FromBody] TorrentControllerUploadMagnetRequest? request)
{
if (request == null)
{
return BadRequest();
}
-
+
if (String.IsNullOrEmpty(request.MagnetLink))
{
return BadRequest("Invalid magnet link");
@@ -115,9 +157,18 @@ public class TorrentsController(ILogger logger, Torrents tor
return Ok();
}
+ ///
+ /// Checks available files in a torrent file
+ ///
+ /// The .torrent file to analyze
+ /// List of available files in the torrent
+ /// Returns the list of available files
+ /// Invalid torrent file provided
[HttpPost]
[Route("CheckFiles")]
- public async Task CheckFiles([FromForm] IFormFile? file)
+ [ProducesResponseType(typeof(IList), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(String), StatusCodes.Status400BadRequest)]
+ public async Task>> CheckFiles([FromForm] IFormFile? file)
{
if (file == null || file.Length <= 0)
{
@@ -139,9 +190,18 @@ public class TorrentsController(ILogger logger, Torrents tor
return Ok(result);
}
+ ///
+ /// Checks available files from a magnet link
+ ///
+ /// The magnet link to analyze
+ /// List of available files in the torrent
+ /// Returns the list of available files
+ /// Invalid magnet link provided
[HttpPost]
[Route("CheckFilesMagnet")]
- public async Task CheckFilesMagnet([FromBody] TorrentControllerCheckFilesRequest? request)
+ [ProducesResponseType(typeof(IList), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(String), StatusCodes.Status400BadRequest)]
+ public async Task>> CheckFilesMagnet([FromBody] TorrentControllerCheckFilesRequest? request)
{
if (request == null)
{
@@ -160,8 +220,18 @@ public class TorrentsController(ILogger logger, Torrents tor
return Ok(result);
}
+ ///
+ /// Deletes a torrent and optionally its associated data
+ ///
+ /// The unique identifier of the torrent to delete
+ /// Delete options specifying what should be removed
+ /// Success status
+ /// Torrent deleted successfully
+ /// Invalid request parameters
[HttpPost]
[Route("Delete/{torrentId:guid}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task Delete(Guid torrentId, [FromBody] TorrentControllerDeleteRequest? request)
{
if (request == null)
@@ -176,8 +246,15 @@ public class TorrentsController(ILogger logger, Torrents tor
return Ok();
}
+ ///
+ /// Retries a failed torrent download
+ ///
+ /// The unique identifier of the torrent to retry
+ /// Success status
+ /// Retry initiated successfully
[HttpPost]
[Route("Retry/{torrentId:guid}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
public async Task Retry(Guid torrentId)
{
logger.LogDebug("Retry {torrentId}", torrentId);
@@ -188,8 +265,15 @@ public class TorrentsController(ILogger logger, Torrents tor
return Ok();
}
+ ///
+ /// Retries a failed download within a torrent
+ ///
+ /// The unique identifier of the download to retry
+ /// Success status
+ /// Retry initiated successfully
[HttpPost]
[Route("RetryDownload/{downloadId:guid}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
public async Task RetryDownload(Guid downloadId)
{
logger.LogDebug("Retry download {downloadId}", downloadId);
@@ -198,9 +282,18 @@ public class TorrentsController(ILogger logger, Torrents tor
return Ok();
}
-
+
+ ///
+ /// Updates torrent configuration
+ ///
+ /// The updated torrent configuration
+ /// Success status
+ /// Torrent updated successfully
+ /// Invalid torrent configuration
[HttpPut]
[Route("Update")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task Update([FromBody] Torrent? torrent)
{
if (torrent == null)
@@ -213,9 +306,17 @@ public class TorrentsController(ILogger logger, Torrents tor
return Ok();
}
+ ///
+ /// Tests regex patterns against torrent files
+ ///
+ /// The regex patterns and magnet link to test
+ /// Matching files and any regex errors
+ /// Returns the regex test results
+ /// Invalid request parameters
[HttpPost]
[Route("VerifyRegex")]
- public async Task VerifyRegex([FromForm] IFormFile? file, [FromBody] TorrentControllerVerifyRegexRequest? request)
+ [ProducesResponseType(typeof(RegexVerificationResult), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task> VerifyRegex([FromBody] TorrentControllerVerifyRegexRequest? request)
{
if (request == null)
@@ -280,41 +381,119 @@ public class TorrentsController(ILogger logger, Torrents tor
selectedFiles = [.. availableFiles];
}
- return Ok(new
+ return Ok(new RegexVerificationResult
{
- includeError,
- excludeError,
- selectedFiles
+ IncludeError = includeError,
+ ExcludeError = excludeError,
+ SelectedFiles = selectedFiles
});
}
}
+///
+/// Request model for uploading a torrent file
+///
public class TorrentControllerUploadFileRequest
{
+ ///
+ /// Configuration for the torrent download
+ ///
+ [Required]
public Torrent? Torrent { get; set; }
}
+///
+/// Request model for adding a magnet link
+///
public class TorrentControllerUploadMagnetRequest
{
+ ///
+ /// The magnet URI to process
+ ///
+ [Required]
public String? MagnetLink { get; set; }
+
+ ///
+ /// Configuration for the torrent download
+ ///
+ [Required]
public Torrent? Torrent { get; set; }
}
+///
+/// Request model for deleting a torrent
+///
public class TorrentControllerDeleteRequest
{
+ ///
+ /// Whether to delete the downloaded data
+ ///
public Boolean DeleteData { get; set; }
+
+ ///
+ /// Whether to remove the torrent from the Debrid service
+ ///
public Boolean DeleteRdTorrent { get; set; }
+
+ ///
+ /// Whether to delete local torrent files
+ ///
public Boolean DeleteLocalFiles { get; set; }
}
+///
+/// Request model for checking files in a magnet link
+///
public class TorrentControllerCheckFilesRequest
{
+ ///
+ /// The magnet URI to analyze
+ ///
+ [Required]
public String? MagnetLink { get; set; }
}
+///
+/// Request model for verifying regex patterns
+///
public class TorrentControllerVerifyRegexRequest
{
+ ///
+ /// Pattern for including files
+ ///
public String? IncludeRegex { get; set; }
+
+ ///
+ /// Pattern for excluding files
+ ///
public String? ExcludeRegex { get; set; }
- public String? MagnetLink { get; set;}
+
+ ///
+ /// Magnet link to test patterns against
+ ///
+ public String? MagnetLink { get; set; }
+}
+
+///
+/// Response model for regex verification results
+///
+public class RegexVerificationResult
+{
+ ///
+ /// Error message for the include regex pattern, if any
+ ///
+ [JsonPropertyName("includeError")]
+ public String IncludeError { get; set; } = String.Empty;
+
+ ///
+ /// Error message for the exclude regex pattern, if any
+ ///
+ [JsonPropertyName("excludeError")]
+ public String ExcludeError { get; set; } = String.Empty;
+
+ ///
+ /// Files that match the specified patterns
+ ///
+ [JsonPropertyName("selectedFiles")]
+ public IList SelectedFiles { get; set; } = new List();
}
\ No newline at end of file