feat: implement TorBoxSDK core — client hierarchy, models, all 107 API endpoints, unit tests#1
Conversation
…archy, response models, DI, error handling Agent-Logs-Url: https://github.com/devRael1/TorBoxSDK/sessions/5aba6cc8-4469-4c9f-b732-9797eb3d4604 Co-authored-by: devRael1 <91017912+devRael1@users.noreply.github.com>
…source domains Agent-Logs-Url: https://github.com/devRael1/TorBoxSDK/sessions/5aba6cc8-4469-4c9f-b732-9797eb3d4604 Co-authored-by: devRael1 <91017912+devRael1@users.noreply.github.com>
…resource clients Agent-Logs-Url: https://github.com/devRael1/TorBoxSDK/sessions/5aba6cc8-4469-4c9f-b732-9797eb3d4604 Co-authored-by: devRael1 <91017912+devRael1@users.noreply.github.com>
…y API — 2 endpoints) Agent-Logs-Url: https://github.com/devRael1/TorBoxSDK/sessions/5aba6cc8-4469-4c9f-b732-9797eb3d4604 Co-authored-by: devRael1 <91017912+devRael1@users.noreply.github.com>
Agent-Logs-Url: https://github.com/devRael1/TorBoxSDK/sessions/5aba6cc8-4469-4c9f-b732-9797eb3d4604 Co-authored-by: devRael1 <91017912+devRael1@users.noreply.github.com>
|
@copilot assure toi que la totalité des APIs pour TorBox est couverte. Si ce n'est pas le cas, poursuit le développement. N'oublie pas de faire une review du code avant de le valider. |
…th, torznab/newznab, magnet-to-file) and fix 2 test assertions Agent-Logs-Url: https://github.com/devRael1/TorBoxSDK/sessions/89be6b24-94a8-4113-bf5a-4d949d8ef8b8 Co-authored-by: devRael1 <91017912+devRael1@users.noreply.github.com>
… code review feedback Agent-Logs-Url: https://github.com/devRael1/TorBoxSDK/sessions/89be6b24-94a8-4113-bf5a-4d949d8ef8b8 Co-authored-by: devRael1 <91017912+devRael1@users.noreply.github.com>
J'ai audité toute la couverture API par rapport à
Total : 107 endpoints couvrant la totalité des APIs TorBox (Main ~95, Search 12, Relay 2). Code review passée (CodeQL : 0 alertes), build 0 warnings/0 errors, 52 tests unitaires OK. Aussi corrigé 2 assertions de tests qui échouaient ( |
|
@copilot recommence la review afin de déterminer si des choses sont manquantes ou bien s'il y a des erreurs. |
…ution, fix root endpoint paths Agent-Logs-Url: https://github.com/devRael1/TorBoxSDK/sessions/66dfa255-22e7-490d-a2d1-418216e1a536 Co-authored-by: devRael1 <91017912+devRael1@users.noreply.github.com>
Review complète effectuée. Voici les résultats : Couverture API : 107/~106 endpoints — ✅ complète (Torrents 14, Usenet 8, WebDownloads 9, User 16, General 4, Notifications 8, RSS 5, Stream 2, Integrations 17, Vendors 8, Queued 2, Search 12, Relay 2). Bug critique corrigé dans Qualité : Build 0 warnings/0 errors sur les 5 cibles, 52 tests unitaires OK, CodeQL 0 alertes. |
There was a problem hiding this comment.
Pull request overview
Implements the TorBoxSDK core as a multi-targeted C# library, including the client hierarchy (Main/Search/Relay), shared HTTP/auth infrastructure, response/error models, and accompanying unit-test scaffolding.
Changes:
- Added multi-target TorBoxSDK package project with NuGet metadata and shared build settings.
- Implemented core clients (Main aggregate + selected resource clients, Search, Relay), HTTP helper utilities, auth handler, and options/DI registration.
- Added/expanded unit tests and test infrastructure; removed template test stubs.
Reviewed changes
Copilot reviewed 131 out of 131 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/TorboxSDK.UnitTests/UnitTest1.cs | Removed template test stub. |
| tests/TorboxSDK.UnitTests/TorboxSDK.UnitTests.csproj | Added SDK project reference and DI/options packages for tests. |
| tests/TorboxSDK.UnitTests/Search/SearchApiClientTests.cs | Added Search API unit tests. |
| tests/TorboxSDK.UnitTests/Relay/RelayApiClientTests.cs | Added Relay API unit tests. |
| tests/TorboxSDK.UnitTests/Models/TorBoxResponseTests.cs | Added serialization/deserialization tests for response envelopes. |
| tests/TorboxSDK.UnitTests/Models/TorBoxErrorCodeTests.cs | Added enum definition tests for expected error codes. |
| tests/TorboxSDK.UnitTests/Http/TorBoxApiHelperTests.cs | Added tests for query building and response handling/error mapping. |
| tests/TorboxSDK.UnitTests/Http/AuthHandlerTests.cs | Added tests for auth header injection behavior. |
| tests/TorboxSDK.UnitTests/Helpers/MockHttpMessageHandler.cs | Added mock HTTP handler for unit tests. |
| tests/TorboxSDK.UnitTests/Helpers/ClientTestBase.cs | Added test client factory helper. |
| tests/TorboxSDK.UnitTests/DependencyInjection/TorBoxServiceCollectionExtensionsTests.cs | Added DI registration tests for AddTorBox(). |
| tests/TorBoxSDK.PerformanceTests/UnitTest1.cs | Removed template test stub. |
| tests/TorBoxSDK.PerformanceTests/TorBoxSDK.PerformanceTests.csproj | Added SDK project reference. |
| tests/TorBoxSDK.IntegrationTests/UnitTest1.cs | Removed template test stub. |
| tests/TorBoxSDK.IntegrationTests/TorBoxSDK.IntegrationTests.csproj | Added SDK project reference. |
| src/TorBoxSDK/TorBoxSDK.csproj | Switched to multi-targeting and added NuGet/SourceLink packaging metadata. |
| src/TorBoxSDK/TorBoxClientOptions.cs | Added configurable SDK options (API key, base URLs, timeout). |
| src/TorBoxSDK/TorBoxClient.cs | Added root client facade aggregating Main/Search/Relay clients. |
| src/TorBoxSDK/Search/SearchApiClient.cs | Implemented Search API client methods. |
| src/TorBoxSDK/Search/ISearchApiClient.cs | Added Search API client interface and XML docs. |
| src/TorBoxSDK/Relay/RelayApiClient.cs | Implemented Relay API client methods. |
| src/TorBoxSDK/Relay/IRelayApiClient.cs | Added Relay API client interface and XML docs. |
| src/TorBoxSDK/Properties/AssemblyInfo.cs | Exposed internals to unit test assembly. |
| src/TorBoxSDK/Models/WebDownloads/WebDownload.cs | Added WebDownloads response model. |
| src/TorBoxSDK/Models/WebDownloads/RequestWebDownloadOptions.cs | Added web download request options model. |
| src/TorBoxSDK/Models/WebDownloads/Hoster.cs | Added hoster model. |
| src/TorBoxSDK/Models/WebDownloads/EditWebDownloadRequest.cs | Added edit request model. |
| src/TorBoxSDK/Models/WebDownloads/CreateWebDownloadRequest.cs | Added create request model. |
| src/TorBoxSDK/Models/WebDownloads/ControlWebDownloadRequest.cs | Added control request model. |
| src/TorBoxSDK/Models/WebDownloads/CheckWebCachedRequest.cs | Added cache-check request model. |
| src/TorBoxSDK/Models/Vendors/VendorAccount.cs | Added vendor account model. |
| src/TorBoxSDK/Models/Vendors/UpdateVendorAccountRequest.cs | Added vendor update request model. |
| src/TorBoxSDK/Models/Vendors/RemoveVendorUserRequest.cs | Added vendor user removal request model. |
| src/TorBoxSDK/Models/Vendors/RegisterVendorUserRequest.cs | Added vendor user registration request model. |
| src/TorBoxSDK/Models/Vendors/RegisterVendorRequest.cs | Added vendor registration request model. |
| src/TorBoxSDK/Models/User/UserSettings.cs | Added user settings model. |
| src/TorBoxSDK/Models/User/User.cs | Added user profile model. |
| src/TorBoxSDK/Models/User/Transaction.cs | Added transaction model. |
| src/TorBoxSDK/Models/User/Subscription.cs | Added subscription model. |
| src/TorBoxSDK/Models/User/SearchEngine.cs | Added search engine model. |
| src/TorBoxSDK/Models/User/RefreshTokenRequest.cs | Added refresh token request model. |
| src/TorBoxSDK/Models/User/ReferralData.cs | Added referral data model. |
| src/TorBoxSDK/Models/User/ModifySearchEnginesRequest.cs | Added modify search engines request model. |
| src/TorBoxSDK/Models/User/EditSettingsRequest.cs | Added edit settings request model. |
| src/TorBoxSDK/Models/User/DeviceTokenRequest.cs | Added device token request model. |
| src/TorBoxSDK/Models/User/DeviceCodeResponse.cs | Added device code response model. |
| src/TorBoxSDK/Models/User/DeleteAccountRequest.cs | Added delete account request model. |
| src/TorBoxSDK/Models/User/ControlSearchEnginesRequest.cs | Added control search engines request model. |
| src/TorBoxSDK/Models/User/AddSearchEnginesRequest.cs | Added add search engines request model. |
| src/TorBoxSDK/Models/User/AddReferralRequest.cs | Added add referral request model. |
| src/TorBoxSDK/Models/Usenet/UsenetDownload.cs | Added Usenet download model. |
| src/TorBoxSDK/Models/Usenet/RequestUsenetDownloadOptions.cs | Added Usenet request download options model. |
| src/TorBoxSDK/Models/Usenet/EditUsenetDownloadRequest.cs | Added Usenet edit request model. |
| src/TorBoxSDK/Models/Usenet/CreateUsenetDownloadRequest.cs | Added Usenet create request model. |
| src/TorBoxSDK/Models/Usenet/ControlUsenetDownloadRequest.cs | Added Usenet control request model. |
| src/TorBoxSDK/Models/Usenet/CheckUsenetCachedRequest.cs | Added Usenet cache-check request model. |
| src/TorBoxSDK/Models/Torrents/TorrentInfo.cs | Added torrent info model. |
| src/TorBoxSDK/Models/Torrents/TorrentFile.cs | Added torrent file model. |
| src/TorBoxSDK/Models/Torrents/Torrent.cs | Added torrent model. |
| src/TorBoxSDK/Models/Torrents/SeedPreference.cs | Added torrent seed preference enum. |
| src/TorBoxSDK/Models/Torrents/RequestDownloadOptions.cs | Added torrent request download options model. |
| src/TorBoxSDK/Models/Torrents/MagnetToFileRequest.cs | Added magnet-to-file request model. |
| src/TorBoxSDK/Models/Torrents/ExportDataOptions.cs | Added export options model. |
| src/TorBoxSDK/Models/Torrents/EditTorrentRequest.cs | Added edit torrent request model. |
| src/TorBoxSDK/Models/Torrents/CreateTorrentRequest.cs | Added create torrent request model. |
| src/TorBoxSDK/Models/Torrents/ControlTorrentRequest.cs | Added control torrent request model. |
| src/TorBoxSDK/Models/Torrents/CheckCachedRequest.cs | Added torrent cache-check request model. |
| src/TorBoxSDK/Models/Search/UsenetSearchResult.cs | Added Usenet search result model. |
| src/TorBoxSDK/Models/Search/TorrentSearchResult.cs | Added torrent search result model. |
| src/TorBoxSDK/Models/Search/SearchType.cs | Added search type enum. |
| src/TorBoxSDK/Models/Search/MetaSearchResult.cs | Added meta search result model. |
| src/TorBoxSDK/Models/Search/MediaType.cs | Added media type enum. |
| src/TorBoxSDK/Models/Rss/RssFeedItem.cs | Added RSS feed item model. |
| src/TorBoxSDK/Models/Rss/RssFeed.cs | Added RSS feed model. |
| src/TorBoxSDK/Models/Rss/ModifyRssRequest.cs | Added RSS modify request model. |
| src/TorBoxSDK/Models/Rss/ControlRssRequest.cs | Added RSS control request model. |
| src/TorBoxSDK/Models/Rss/AddRssRequest.cs | Added RSS add request model. |
| src/TorBoxSDK/Models/Relay/RelayStatus.cs | Added relay status model. |
| src/TorBoxSDK/Models/Relay/InactiveCheckResult.cs | Added relay inactivity check result model. |
| src/TorBoxSDK/Models/Queued/QueuedDownload.cs | Added queued download model. |
| src/TorBoxSDK/Models/Queued/ControlQueuedRequest.cs | Added queued control request model. |
| src/TorBoxSDK/Models/Notifications/Stats.cs | Added stats model. |
| src/TorBoxSDK/Models/Notifications/Notification.cs | Added notification model. |
| src/TorBoxSDK/Models/Notifications/IntercomHash.cs | Added intercom hash model. |
| src/TorBoxSDK/Models/Notifications/Changelog.cs | Added changelog model. |
| src/TorBoxSDK/Models/Integrations/OAuthRegisterRequest.cs | Added OAuth register request model. |
| src/TorBoxSDK/Models/Integrations/OAuthIntegration.cs | Added OAuth integration model. |
| src/TorBoxSDK/Models/Integrations/IntegrationJob.cs | Added integration job model. |
| src/TorBoxSDK/Models/Integrations/CreateIntegrationJobRequest.cs | Added integration job creation request model. |
| src/TorBoxSDK/Models/General/SpeedtestOptions.cs | Added speedtest options model. |
| src/TorBoxSDK/Models/Common/TorBoxResponse.cs | Added standard response envelopes (generic + non-generic). |
| src/TorBoxSDK/Models/Common/TorBoxException.cs | Added API exception type carrying error code/detail. |
| src/TorBoxSDK/Models/Common/TorBoxErrorCode.cs | Added known API error code enum. |
| src/TorBoxSDK/Models/Common/DownloadType.cs | Added download type enum. |
| src/TorBoxSDK/Models/Common/DownloadStatus.cs | Added download status enum. |
| src/TorBoxSDK/Models/Common/DownloadFile.cs | Added download file model. |
| src/TorBoxSDK/Models/Common/ControlOperation.cs | Added control operation enum. |
| src/TorBoxSDK/Main/WebDownloads/WebDownloadsClient.cs | Implemented WebDownloads resource client. |
| src/TorBoxSDK/Main/WebDownloads/IWebDownloadsClient.cs | Added WebDownloads interface and XML docs. |
| src/TorBoxSDK/Main/Vendors/VendorsClient.cs | Implemented Vendors resource client. |
| src/TorBoxSDK/Main/Vendors/IVendorsClient.cs | Added Vendors interface and XML docs. |
| src/TorBoxSDK/Main/User/UserClient.cs | Implemented User resource client. |
| src/TorBoxSDK/Main/User/IUserClient.cs | Added User interface and XML docs. |
| src/TorBoxSDK/Main/Usenet/UsenetClient.cs | Implemented Usenet resource client. |
| src/TorBoxSDK/Main/Usenet/IUsenetClient.cs | Added Usenet interface and XML docs. |
| src/TorBoxSDK/Main/Torrents/ITorrentsClient.cs | Added Torrents interface and XML docs. |
| src/TorBoxSDK/Main/Stream/StreamClient.cs | Implemented Stream resource client. |
| src/TorBoxSDK/Main/Stream/IStreamClient.cs | Added Stream interface and XML docs. |
| src/TorBoxSDK/Main/Rss/RssClient.cs | Implemented RSS resource client. |
| src/TorBoxSDK/Main/Rss/IRssClient.cs | Added RSS interface and XML docs. |
| src/TorBoxSDK/Main/Queued/QueuedClient.cs | Implemented Queued resource client. |
| src/TorBoxSDK/Main/Queued/IQueuedClient.cs | Added Queued interface and XML docs. |
| src/TorBoxSDK/Main/Notifications/NotificationsClient.cs | Implemented Notifications resource client. |
| src/TorBoxSDK/Main/Notifications/INotificationsClient.cs | Added Notifications interface and XML docs. |
| src/TorBoxSDK/Main/MainApiClient.cs | Added Main API aggregate client. |
| src/TorBoxSDK/Main/IMainApiClient.cs | Added Main API aggregate interface. |
| src/TorBoxSDK/Main/General/IGeneralClient.cs | Added General resource interface. |
| src/TorBoxSDK/Main/General/GeneralClient.cs | Implemented General resource client. |
| src/TorBoxSDK/ITorBoxClient.cs | Added root client interface. |
| src/TorBoxSDK/Http/TorBoxJsonOptions.cs | Added shared JSON options (snake_case policy + enum converter). |
| src/TorBoxSDK/Http/TorBoxApiHelper.cs | Added HTTP helper for sending/deserializing envelope responses and query building. |
| src/TorBoxSDK/Http/Guard.cs | Added internal guard utility for null/empty strings. |
| src/TorBoxSDK/Http/AuthHandler.cs | Added delegating handler for Bearer token injection. |
| src/TorBoxSDK/DependencyInjection/TorBoxServiceCollectionExtensions.cs | Added AddTorBox() DI registration for clients + handlers. |
| src/TorBoxSDK/Class1.cs | Removed template placeholder class. |
| Directory.Build.props | Added repo-wide build settings (nullable, implicit usings, warnings-as-errors, metadata). |
| return error.ToUpperInvariant().Replace(" ", "").Replace("_", "") switch | ||
| { | ||
| "DATABASE_ERROR" or "DATABASEERROR" => TorBoxErrorCode.DatabaseError, | ||
| "BAD_TOKEN" or "BADTOKEN" => TorBoxErrorCode.BadToken, | ||
| "NO_AUTH" or "NOAUTH" => TorBoxErrorCode.NoAuth, | ||
| "INVALID_OPTION" or "INVALIDOPTION" => TorBoxErrorCode.InvalidOption, | ||
| "PERMISSION_DENIED" or "PERMISSIONDENIED" => TorBoxErrorCode.PermissionDenied, | ||
| "PLAN_RESTRICTED_FEATURE" or "PLANRESTRICTEDFEATURE" => TorBoxErrorCode.PlanRestrictedFeature, | ||
| "DUPLICATE_ITEM" or "DUPLICATEITEM" => TorBoxErrorCode.DuplicateItem, | ||
| "BREACH_OF_TOS" or "BREACHOFTOS" => TorBoxErrorCode.BreachOfTos, | ||
| "ACTIVE_LIMIT" or "ACTIVELIMIT" => TorBoxErrorCode.ActiveLimit, | ||
| "SEEDING_LIMIT" or "SEEDINGLIMIT" => TorBoxErrorCode.SeedingLimit, | ||
| "BANNED_CONTENT_DETECTED" or "BANNEDCONTENTDETECTED" => TorBoxErrorCode.BannedContentDetected, | ||
| "COULD_NOT_PERFORM_ACTION" or "COULDNOTPERFORMACTION" => TorBoxErrorCode.CouldNotPerformAction, | ||
| "ITEM_NOT_FOUND" or "ITEMNOTFOUND" => TorBoxErrorCode.ItemNotFound, | ||
| "INVALID_DEVICE" or "INVALIDDEVICE" => TorBoxErrorCode.InvalidDevice, | ||
| "DEVICE_ALREADY_AUTHED" or "DEVICEALREADYAUTHED" => TorBoxErrorCode.DeviceAlreadyAuthed, | ||
| "TOO_MANY_REQUESTS" or "TOOMANYREQUESTS" => TorBoxErrorCode.TooManyRequests, | ||
| "DOWNLOAD_TOO_LARGE" or "DOWNLOADTOOLARGE" => TorBoxErrorCode.DownloadTooLarge, | ||
| "MISSING_REQUIRED_OPTION" or "MISSINGREQUIREDOPTION" => TorBoxErrorCode.MissingRequiredOption, | ||
| "BANNED_USER" or "BANNEDUSER" => TorBoxErrorCode.BannedUser, | ||
| "SEARCH_ERROR" or "SEARCHERROR" => TorBoxErrorCode.SearchError, | ||
| "SERVER_ERROR" or "SERVERERROR" => TorBoxErrorCode.ServerError, |
There was a problem hiding this comment.
ParseErrorCode() never maps the API value for an unknown server error to TorBoxErrorCode.UnknownError even though the enum defines it. This will misclassify responses like UNKNOWN_ERROR (or similar) as Unknown, reducing the usefulness of TorBoxException.ErrorCode. Consider adding an explicit mapping for the API’s unknown-error code(s) and aligning the normalization logic/patterns so the switch cases match the normalized input consistently.
| return error.ToUpperInvariant().Replace(" ", "").Replace("_", "") switch | |
| { | |
| "DATABASE_ERROR" or "DATABASEERROR" => TorBoxErrorCode.DatabaseError, | |
| "BAD_TOKEN" or "BADTOKEN" => TorBoxErrorCode.BadToken, | |
| "NO_AUTH" or "NOAUTH" => TorBoxErrorCode.NoAuth, | |
| "INVALID_OPTION" or "INVALIDOPTION" => TorBoxErrorCode.InvalidOption, | |
| "PERMISSION_DENIED" or "PERMISSIONDENIED" => TorBoxErrorCode.PermissionDenied, | |
| "PLAN_RESTRICTED_FEATURE" or "PLANRESTRICTEDFEATURE" => TorBoxErrorCode.PlanRestrictedFeature, | |
| "DUPLICATE_ITEM" or "DUPLICATEITEM" => TorBoxErrorCode.DuplicateItem, | |
| "BREACH_OF_TOS" or "BREACHOFTOS" => TorBoxErrorCode.BreachOfTos, | |
| "ACTIVE_LIMIT" or "ACTIVELIMIT" => TorBoxErrorCode.ActiveLimit, | |
| "SEEDING_LIMIT" or "SEEDINGLIMIT" => TorBoxErrorCode.SeedingLimit, | |
| "BANNED_CONTENT_DETECTED" or "BANNEDCONTENTDETECTED" => TorBoxErrorCode.BannedContentDetected, | |
| "COULD_NOT_PERFORM_ACTION" or "COULDNOTPERFORMACTION" => TorBoxErrorCode.CouldNotPerformAction, | |
| "ITEM_NOT_FOUND" or "ITEMNOTFOUND" => TorBoxErrorCode.ItemNotFound, | |
| "INVALID_DEVICE" or "INVALIDDEVICE" => TorBoxErrorCode.InvalidDevice, | |
| "DEVICE_ALREADY_AUTHED" or "DEVICEALREADYAUTHED" => TorBoxErrorCode.DeviceAlreadyAuthed, | |
| "TOO_MANY_REQUESTS" or "TOOMANYREQUESTS" => TorBoxErrorCode.TooManyRequests, | |
| "DOWNLOAD_TOO_LARGE" or "DOWNLOADTOOLARGE" => TorBoxErrorCode.DownloadTooLarge, | |
| "MISSING_REQUIRED_OPTION" or "MISSINGREQUIREDOPTION" => TorBoxErrorCode.MissingRequiredOption, | |
| "BANNED_USER" or "BANNEDUSER" => TorBoxErrorCode.BannedUser, | |
| "SEARCH_ERROR" or "SEARCHERROR" => TorBoxErrorCode.SearchError, | |
| "SERVER_ERROR" or "SERVERERROR" => TorBoxErrorCode.ServerError, | |
| string normalizedError = error.ToUpperInvariant().Replace(" ", "").Replace("_", ""); | |
| return normalizedError switch | |
| { | |
| "UNKNOWNERROR" or "UNKNOWN" => TorBoxErrorCode.UnknownError, | |
| "DATABASEERROR" => TorBoxErrorCode.DatabaseError, | |
| "BADTOKEN" => TorBoxErrorCode.BadToken, | |
| "NOAUTH" => TorBoxErrorCode.NoAuth, | |
| "INVALIDOPTION" => TorBoxErrorCode.InvalidOption, | |
| "PERMISSIONDENIED" => TorBoxErrorCode.PermissionDenied, | |
| "PLANRESTRICTEDFEATURE" => TorBoxErrorCode.PlanRestrictedFeature, | |
| "DUPLICATEITEM" => TorBoxErrorCode.DuplicateItem, | |
| "BREACHOFTOS" => TorBoxErrorCode.BreachOfTos, | |
| "ACTIVELIMIT" => TorBoxErrorCode.ActiveLimit, | |
| "SEEDINGLIMIT" => TorBoxErrorCode.SeedingLimit, | |
| "BANNEDCONTENTDETECTED" => TorBoxErrorCode.BannedContentDetected, | |
| "COULDNOTPERFORMACTION" => TorBoxErrorCode.CouldNotPerformAction, | |
| "ITEMNOTFOUND" => TorBoxErrorCode.ItemNotFound, | |
| "INVALIDDEVICE" => TorBoxErrorCode.InvalidDevice, | |
| "DEVICEALREADYAUTHED" => TorBoxErrorCode.DeviceAlreadyAuthed, | |
| "TOOMANYREQUESTS" => TorBoxErrorCode.TooManyRequests, | |
| "DOWNLOADTOOLARGE" => TorBoxErrorCode.DownloadTooLarge, | |
| "MISSINGREQUIREDOPTION" => TorBoxErrorCode.MissingRequiredOption, | |
| "BANNEDUSER" => TorBoxErrorCode.BannedUser, | |
| "SEARCHERROR" => TorBoxErrorCode.SearchError, | |
| "SERVERERROR" => TorBoxErrorCode.ServerError, |
| var handler = new MockHttpMessageHandler(json, statusCode); | ||
| var httpClient = new HttpClient(handler) { BaseAddress = new Uri("https://api.torbox.app/v1/api/") }; | ||
| TClient client = (TClient)Activator.CreateInstance(typeof(TClient), httpClient)!; | ||
| return (client, handler); |
There was a problem hiding this comment.
ClientTestBase.CreateClient<TClient>() hardcodes the Main API base address (https://api.torbox.app/v1/api/), but it’s used to construct SearchApiClient and RelayApiClient in the tests. This can hide URI-composition bugs (Search/Relay use different base addresses and path shapes), and makes the URL assertions less meaningful. Consider taking a baseAddress parameter (or inferring per client type) so Search tests use https://search-api.torbox.app/ and Relay tests use https://relay.torbox.app/.
| { | ||
| var handler = new MockHttpMessageHandler(json, statusCode); | ||
| var httpClient = new HttpClient(handler) { BaseAddress = new Uri("https://api.torbox.app/v1/api/") }; | ||
| TClient client = (TClient)Activator.CreateInstance(typeof(TClient), httpClient)!; |
There was a problem hiding this comment.
The null-forgiving operator on Activator.CreateInstance(... )! suppresses possible null returns without justification, which can mask a failing test setup (e.g., missing HttpClient constructor). Prefer throwing a clearer exception if the instance can’t be created (or use a helper that guarantees non-null) instead of !.
| public async Task SendAsync_WithEmptyApiKey_SetsEmptyBearerToken() | ||
| { | ||
| // Arrange | ||
| var options = Options.Create(new TorBoxClientOptions { ApiKey = string.Empty }); | ||
| var innerHandler = new MockHttpMessageHandler("""{"success":true,"error":null,"detail":"OK"}"""); | ||
| var authHandler = new AuthHandler(options) { InnerHandler = innerHandler }; | ||
| using var httpClient = new HttpClient(authHandler); | ||
| using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.torbox.app/v1/api/torrents/mylist"); | ||
|
|
||
| // Act | ||
| await httpClient.SendAsync(request); | ||
|
|
||
| // Assert | ||
| Assert.NotNull(innerHandler.LastRequest); | ||
| Assert.Null(innerHandler.LastRequest.Headers.Authorization); | ||
| } |
There was a problem hiding this comment.
Test name is misleading: when the API key is empty the handler does not set an Authorization header (asserted as null). Rename the test to reflect the behavior (e.g., “DoesNotAddAuthorizationHeader”) or adjust the behavior/assertion so the name matches.
| ArgumentNullException.ThrowIfNull(services); | ||
| ArgumentNullException.ThrowIfNull(configure); | ||
|
|
||
| services.Configure(configure); |
There was a problem hiding this comment.
TorBoxClientOptions.ApiKey is marked [Required], but AddTorBox() doesn’t register any options validation, so missing/empty API keys won’t fail fast and the data annotation is effectively ignored. Consider adding services.AddOptions<TorBoxClientOptions>().ValidateDataAnnotations() (and optionally a custom validator for base URL formats / trailing slashes) or removing [Required] if you don’t intend to validate via DI.
| services.Configure(configure); | |
| services | |
| .AddOptions<TorBoxClientOptions>() | |
| .Configure(configure) | |
| .ValidateDataAnnotations(); |
| public enum SeedPreference | ||
| { | ||
| /// <summary>Automatically determine seeding behavior based on user settings.</summary> | ||
| Auto = 1, | ||
|
|
||
| /// <summary>Seed the torrent after download completion.</summary> | ||
| Seed = 2, | ||
|
|
||
| /// <summary>Do not seed the torrent after download completion.</summary> | ||
| NoSeed = 3, |
There was a problem hiding this comment.
SeedPreference is missing an Unknown = 0 member. Other SDK enums include an Unknown value for forward compatibility, and the SDK’s enum design guideline expects a catch-all unknown member. Adding Unknown = 0 also prevents default(enum) from serializing to an unintended value.
| ArgumentNullException.ThrowIfNull(request); | ||
|
|
||
| var content = new MultipartFormDataContent(); | ||
| if (request.Link is not null) | ||
| { | ||
| content.Add(new StringContent(request.Link), "link"); | ||
| } | ||
|
|
||
| if (request.File is not null) | ||
| { | ||
| content.Add(new ByteArrayContent(request.File), "file", "download.nzb"); | ||
| } |
There was a problem hiding this comment.
CreateUsenetDownloadAsync does not enforce the request contract described by CreateUsenetDownloadRequest (“Either Link or File must be provided”). As written, it can send an empty multipart form body when both are null, producing a late API error. Add boundary validation to ensure exactly one (or at least one, depending on API rules) of Link/File is provided before sending the request.
| /// <summary>Retrieves the authenticated user's profile.</summary> | ||
| /// <param name="settings">Whether to include account settings in the response.</param> | ||
| /// <param name="ct">Cancellation token.</param> | ||
| /// <returns>The user profile data.</returns> | ||
| /// <exception cref="TorBoxException">Thrown when the API returns an error.</exception> | ||
| Task<TorBoxResponse<Models.User.User>> GetMeAsync(bool? settings = null, CancellationToken ct = default); | ||
|
|
There was a problem hiding this comment.
Using TorBoxResponse<Models.User.User> is a readability smell caused by the model type name colliding with the User namespace. Consider introducing a type alias (using UserProfile = TorBoxSDK.Models.User.User;) or renaming the model (e.g., UserProfile) to avoid requiring fully-qualified names in the public API surface.
| /// <summary>Checks whether a torrent is inactive on the relay.</summary> | ||
| /// <param name="authId">The authentication identifier of the user.</param> | ||
| /// <param name="torrentId">The unique identifier of the torrent to check.</param> | ||
| /// <param name="ct">Cancellation token.</param> | ||
| /// <returns>The inactivity check result.</returns> | ||
| /// <exception cref="ArgumentException">Thrown when <paramref name="authId"/> is null or empty.</exception> | ||
| /// <exception cref="TorBoxException">Thrown when the API returns an error.</exception> | ||
| Task<TorBoxResponse<InactiveCheckResult>> CheckForInactiveAsync(string authId, long torrentId, CancellationToken ct = default); |
There was a problem hiding this comment.
The interface documents ArgumentException for a null-or-empty authId, but the implementation uses Guard.ThrowIfNullOrEmpty(...), which throws ArgumentNullException when authId is null. Update the XML docs to include ArgumentNullException so consumers get an accurate exception contract.
| /// <summary>Creates a stream for a download item.</summary> | ||
| /// <param name="id">The identifier of the download.</param> | ||
| /// <param name="fileId">The identifier of the file within the download.</param> | ||
| /// <param name="type">The type of download (e.g., torrent, usenet).</param> | ||
| /// <param name="ct">Cancellation token.</param> | ||
| /// <returns>The stream URL or data as a string.</returns> | ||
| /// <exception cref="ArgumentException">Thrown when <paramref name="type"/> is null or empty.</exception> | ||
| /// <exception cref="TorBoxException">Thrown when the API returns an error.</exception> | ||
| Task<TorBoxResponse<string>> CreateStreamAsync(long id, long fileId, string type, CancellationToken ct = default); |
There was a problem hiding this comment.
The interface documents ArgumentException for a null-or-empty type, but the implementation uses Guard.ThrowIfNullOrEmpty(...), which throws ArgumentNullException when type is null. Update the XML docs to include ArgumentNullException (or change the guard behavior) to keep the documented contract accurate.
|
@copilot apply changes based on the comments in this thread |
…ntTestBase base address per client type, test rename, DI validation, XML docs ArgumentNullException, SeedPreference Unknown=0, create request validation, User→UserProfile rename Agent-Logs-Url: https://github.com/devRael1/TorBoxSDK/sessions/0d3877b1-323d-4a52-a9fa-1becc13312be Co-authored-by: devRael1 <91017912+devRael1@users.noreply.github.com>
Les 11 commentaires de review ont été appliqués dans
Build 0 warnings/0 errors, 52 tests OK, CodeQL 0 alertes. |
Full SDK implementation covering Phases 1–6 of the development roadmap in
docs/TODO.md. Ships the complete TorBox API surface (Main, Search, Relay) as a multi-target C# library (net6.0–net10.0).Project Infrastructure
net6.0;net7.0;net8.0;net9.0;net10.0withDirectory.Build.props,.editorconfig, NuGet metadata, SourceLinkTreatWarningsAsErrorsenabled, nullable reference types enforced,GenerateDocumentationFileactiveClient Architecture
TorBoxClient→Main/Search/Relayfacade hierarchyMainApiClientexposes 11 resource clients:Torrents,Usenet,WebDownloads,User,General,Notifications,Rss,Stream,Integrations,Vendors,QueuedAuthHandler(DelegatingHandler) for ****** injectionTorBoxApiHelperinternal helper for response envelope processing, error mapping, query buildingAddTorBox()DI extension withIHttpClientFactorytyped client registration andValidateDataAnnotations()for fail-fast options validationHttpClientData Models (67 files)
sealed recordtypes with[JsonPropertyName],initproperties,IReadOnlyList<T>collectionsTorBoxResponse<T>/TorBoxResponseenvelope,TorBoxException,TorBoxErrorCodeenumSnakeCaseLowerpolyfill for net6.0/net7.0 via conditional compilationUsermodel renamed toUserProfileto avoid namespace/type collisionUnknown = 0for forward compatibility (includingSeedPreference)API Endpoints (107 methods — full coverage)
Torrents(14): create, async-create, control, queued, request download, list, check cached, export, magnet-to-file, torrent info, editUsenet(8): create, async-create, control, request download, list, check cached, editWebDownloads(9): create, async-create, control, request download, list, check cached, hosters, editUser(16): auth (refresh, device code), profile, referrals, subscriptions, transactions, search engines, settingsGeneral(4): status, stats, 30-day stats, speedtestNotifications(8): RSS/JSON feeds, list, clear, test, intercom, changelogsRSS(5): add, control, modify, get feeds/itemsStream(2): create stream, get stream dataIntegrations(17): OAuth (redirect, callback, success, register, unregister, Discord roles), cloud storage jobs (Google Drive, Dropbox, OneDrive, Gofile, 1Fichier, Pixeldrain), job managementVendors(8): register, account management, user managementQueued(2): get queued, control queuedInput Validation
Magnet/FileorLink/Fileis provided before sending the requestArgumentNullException(for null) andArgumentException(for empty) on all interfaces usingGuard.ThrowIfNullOrEmptyBug Fixes
MainApiBaseUrl,SearchApiBaseUrl,RelayApiBaseUrl) now include trailing slashes, which is required for correct relative URI resolution withHttpClient.BaseAddress. Without the trailing slash, relative paths like"torrents/mylist"would resolve to"/v1/torrents/mylist"instead of"/v1/api/torrents/mylist".GeneralClient.GetUpStatusAsyncandRelayApiClient.GetStatusAsyncwhich used absolute path"/"— this bypassedBaseAddressentirely. Now usesstring.Emptyto correctly resolve to the base address.ParseErrorCode()normalization: input is now normalized once before matching, added explicitUNKNOWNERROR/UNKNOWNmapping toTorBoxErrorCode.UnknownError.Unit Tests (52 tests, all passing)
MockHttpMessageHandler+ClientTestBasetest infrastructure with per-client-type base address resolution (Search →search-api.torbox.app, Relay →relay.torbox.app)TorrentsClient(9 tests),SearchApiClient,RelayApiClient, DI registration