Compare commits

...

4 commits

Author SHA1 Message Date
Roger Far
858bd7c95c no message
Some checks failed
dotnet test / build (push) Has been cancelled
Create GitHub Release / Test, Build, and Bundle (push) Has been cancelled
Release Docker Image / build (map[arch:amd64 platform:linux/amd64 runs-on:ubuntu-latest]) (push) Has been cancelled
Release Docker Image / build (map[arch:arm64 platform:linux/arm64 runs-on:ubuntu-24.04-arm]) (push) Has been cancelled
Create GitHub Release / Create GitHub release (push) Has been cancelled
Release Docker Image / push-images (push) Has been cancelled
2026-06-05 20:32:20 -06:00
Roger Far
2822653d3b Merge branch 'main' of https://github.com/rogerfar/rdt-client 2026-06-05 20:16:42 -06:00
Roger Far
38530cd6fd
Merge pull request #991 from omgbeez/work/sabnzdb-delete
fix(sabnzbd): Fix delete implementation to respect finished action
2026-05-31 16:06:39 -06:00
omgbeez
a7fb1e3e9d
fix(sabnzbd): Fix delete implementation to respect finished action 2026-05-31 17:12:13 -04:00
5 changed files with 150 additions and 23 deletions

View file

@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased
## [2.0.138] - 2026-06-05
### Fixed
- SABnzbd fixes.
## [2.0.137] - 2026-06-05
### Fixed
- Fix torbox save path mapping for single file downloads.

View file

@ -366,6 +366,64 @@ public class SabnzbdTest
Assert.Equal("Failed", result.Slots[0].Status);
}
[Theory]
[InlineData(TorrentFinishedAction.RemoveAllTorrents, true, true, true, true)]
[InlineData(TorrentFinishedAction.RemoveAllTorrents, false, true, true, false)]
[InlineData(TorrentFinishedAction.RemoveRealDebrid, true, false, true, true)]
[InlineData(TorrentFinishedAction.RemoveRealDebrid, false, false, true, false)]
[InlineData(TorrentFinishedAction.RemoveClient, true, true, false, true)]
[InlineData(TorrentFinishedAction.RemoveClient, false, true, false, false)]
public async Task Delete_ShouldRespectFinishedActionAndDeleteFiles(
TorrentFinishedAction finishedAction,
Boolean deleteFiles,
Boolean expectedDeleteData,
Boolean expectedDeleteRdTorrent,
Boolean expectedDeleteLocalFiles)
{
// Arrange
var torrentId = Guid.NewGuid();
_settings.Current.Integrations.Default.FinishedAction = finishedAction;
_torrentsMock.Setup(t => t.GetByHash("hash1"))
.ReturnsAsync(new Torrent
{
TorrentId = torrentId,
Hash = "hash1",
Type = DownloadType.Nzb
});
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act
await sabnzbd.Delete("hash1", deleteFiles);
// Assert
_torrentsMock.Verify(t => t.Delete(torrentId, expectedDeleteData, expectedDeleteRdTorrent, expectedDeleteLocalFiles), Times.Once);
}
[Fact]
public async Task Delete_ShouldNotDelete_WhenFinishedActionIsNone()
{
// Arrange
_settings.Current.Integrations.Default.FinishedAction = TorrentFinishedAction.None;
_torrentsMock.Setup(t => t.GetByHash("hash1"))
.ReturnsAsync(new Torrent
{
TorrentId = Guid.NewGuid(),
Hash = "hash1",
Type = DownloadType.Nzb
});
var sabnzbd = new Sabnzbd(_loggerMock.Object, _torrentsMock.Object, _appSettings, _settings);
// Act
await sabnzbd.Delete("hash1", true);
// Assert
_torrentsMock.Verify(t => t.Delete(It.IsAny<Guid>(), It.IsAny<Boolean>(), It.IsAny<Boolean>(), It.IsAny<Boolean>()), Times.Never);
}
[Fact]
public void GetConfig_ShouldReturnCorrectConfig()
{

View file

@ -177,7 +177,7 @@ public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings app
return result.Hash;
}
public virtual async Task Delete(String hash)
public virtual async Task Delete(String hash, Boolean deleteFiles = false)
{
var torrent = await torrents.GetByHash(hash);
@ -189,18 +189,18 @@ public class Sabnzbd(ILogger<Sabnzbd> logger, Torrents torrents, AppSettings app
switch (settings.Current.Integrations.Default.FinishedAction)
{
case TorrentFinishedAction.RemoveAllTorrents:
logger.LogDebug("Removing nzb from debrid provider and RDT-Client, no files");
await torrents.Delete(torrent.TorrentId, true, true, true);
logger.LogDebug("Removing nzb from debrid provider and RDT-Client, {Files}", deleteFiles ? "with files" : "no files");
await torrents.Delete(torrent.TorrentId, true, true, deleteFiles);
break;
case TorrentFinishedAction.RemoveRealDebrid:
logger.LogDebug("Removing nzb from debrid provider, no files");
await torrents.Delete(torrent.TorrentId, false, true, true);
logger.LogDebug("Removing nzb from debrid provider, {Files}", deleteFiles ? "with files" : "no files");
await torrents.Delete(torrent.TorrentId, false, true, deleteFiles);
break;
case TorrentFinishedAction.RemoveClient:
logger.LogDebug("Removing nzb from client, no files");
await torrents.Delete(torrent.TorrentId, true, false, true);
logger.LogDebug("Removing nzb from client, {Files}", deleteFiles ? "with files" : "no files");
await torrents.Delete(torrent.TorrentId, true, false, deleteFiles);
break;
case TorrentFinishedAction.None:

View file

@ -108,6 +108,30 @@ public class SabnzbdControllerTest
Assert.IsType<OkObjectResult>(result);
}
[Theory]
[InlineData("?name=delete&value=hash1&del_files=1", true)]
[InlineData("?name=delete&value=hash1&del_files=true", true)]
[InlineData("?name=delete&value=hash1&del_files=0", false)]
[InlineData("?name=delete&value=hash1", false)]
public async Task Queue_Delete_PassesDeleteFilesFlag(String queryString, Boolean expectedDeleteFiles)
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.QueryString = new(queryString);
_controller.ControllerContext.HttpContext = httpContext;
_sabnzbdMock.Setup(s => s.Delete("hash1", expectedDeleteFiles)).Returns(Task.CompletedTask);
// Act
var result = await _controller.Queue();
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var response = Assert.IsType<SabnzbdResponse>(okResult.Value);
Assert.True(response.Status);
_sabnzbdMock.Verify(s => s.Delete("hash1", expectedDeleteFiles), Times.Once);
}
[Fact]
public async Task GetHistory_ReturnsOk()
{
@ -129,6 +153,26 @@ public class SabnzbdControllerTest
Assert.Equal(1, response.History.NoOfSlots);
}
[Fact]
public async Task History_Delete_PassesDeleteFilesFlag()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.QueryString = new("?name=delete&value=hash1&del_files=1");
_controller.ControllerContext.HttpContext = httpContext;
_sabnzbdMock.Setup(s => s.Delete("hash1", true)).Returns(Task.CompletedTask);
// Act
var result = await _controller.History();
// Assert
var okResult = Assert.IsType<OkObjectResult>(result);
var response = Assert.IsType<SabnzbdResponse>(okResult.Value);
Assert.True(response.Status);
_sabnzbdMock.Verify(s => s.Delete("hash1", true), Times.Once);
}
[Fact]
public void GetVersion_HasAllowAnonymousAttribute()
{

View file

@ -56,22 +56,7 @@ public class SabnzbdController(ILogger<SabnzbdController> logger, Sabnzbd sabnzb
if (name == "delete")
{
var value = GetParam("value");
if (String.IsNullOrWhiteSpace(value))
{
return BadRequest(new SabnzbdResponse
{
Error = "No value specified for delete operation"
});
}
await sabnzbd.Delete(value ?? "");
return Ok(new SabnzbdResponse
{
Status = true
});
return await DeleteDownloads();
}
return Ok(new SabnzbdResponse
@ -85,6 +70,12 @@ public class SabnzbdController(ILogger<SabnzbdController> logger, Sabnzbd sabnzb
public async Task<ActionResult> History()
{
logger.LogDebug("Sabnzbd mode: history");
var name = GetParam("name");
if (name == "delete")
{
return await DeleteDownloads();
}
return Ok(new SabnzbdResponse
{
@ -183,6 +174,31 @@ public class SabnzbdController(ILogger<SabnzbdController> logger, Sabnzbd sabnzb
});
}
private async Task<ActionResult> DeleteDownloads()
{
var value = GetParam("value");
if (String.IsNullOrWhiteSpace(value))
{
return BadRequest(new SabnzbdResponse
{
Error = "No value specified for delete operation"
});
}
var deleteFiles = IsTrue(GetParam("del_files"));
foreach (var hash in value.Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
await sabnzbd.Delete(hash, deleteFiles);
}
return Ok(new SabnzbdResponse
{
Status = true
});
}
private String? GetParam(String name)
{
var value = Request.Query[name].ToString();
@ -194,4 +210,9 @@ public class SabnzbdController(ILogger<SabnzbdController> logger, Sabnzbd sabnzb
return value;
}
private static Boolean IsTrue(String? value)
{
return value is "1" || Boolean.TryParse(value, out var result) && result;
}
}