diff --git a/Src/Notion.Client/Api/ApiEndpoints.cs b/Src/Notion.Client/Api/ApiEndpoints.cs index a788b8f..300c248 100644 --- a/Src/Notion.Client/Api/ApiEndpoints.cs +++ b/Src/Notion.Client/Api/ApiEndpoints.cs @@ -146,6 +146,7 @@ public static class FileUploadsApiUrls public static string Send(string fileUploadId) => $"/v1/file_uploads/{fileUploadId}/send"; public static string Complete(string fileUploadId) => $"/v1/file_uploads/{fileUploadId}/complete"; public static string List => "/v1/file_uploads"; + public static string Retrieve(IRetrieveFileUploadPathParameters pathParameters) => $"/v1/file_uploads/{pathParameters.FileUploadId}"; } } } diff --git a/Src/Notion.Client/Api/FileUploads/IFileUploadsClient.cs b/Src/Notion.Client/Api/FileUploads/IFileUploadsClient.cs index 2e63f14..21450db 100644 --- a/Src/Notion.Client/Api/FileUploads/IFileUploadsClient.cs +++ b/Src/Notion.Client/Api/FileUploads/IFileUploadsClient.cs @@ -51,5 +51,16 @@ Task ListAsync( ListFileUploadsRequest request, CancellationToken cancellationToken = default ); + + /// + /// Retrieve a specific File Upload by its ID. + /// + /// + /// + /// + Task RetrieveAsync( + RetrieveFileUploadRequest request, + CancellationToken cancellationToken = default + ); } } \ No newline at end of file diff --git a/Src/Notion.Client/Api/FileUploads/Retrieve/FileUploadsClient.cs b/Src/Notion.Client/Api/FileUploads/Retrieve/FileUploadsClient.cs new file mode 100644 index 0000000..ea30cd4 --- /dev/null +++ b/Src/Notion.Client/Api/FileUploads/Retrieve/FileUploadsClient.cs @@ -0,0 +1,28 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class FileUploadsClient + { + public async Task RetrieveAsync( + RetrieveFileUploadRequest request, + CancellationToken cancellationToken = default) + { + IRetrieveFileUploadPathParameters pathParameters = request; + + if (pathParameters == null || string.IsNullOrEmpty(pathParameters.FileUploadId)) + { + throw new ArgumentNullException(nameof(pathParameters.FileUploadId), "FileUploadId cannot be null or empty."); + } + + var endpoint = ApiEndpoints.FileUploadsApiUrls.Retrieve(pathParameters); + + return await _restClient.GetAsync( + endpoint, + cancellationToken: cancellationToken + ); + } + } +} diff --git a/Src/Notion.Client/Api/FileUploads/Retrieve/Request/IRetrieveFileUploadQueryParameters.cs b/Src/Notion.Client/Api/FileUploads/Retrieve/Request/IRetrieveFileUploadQueryParameters.cs new file mode 100644 index 0000000..900dbd4 --- /dev/null +++ b/Src/Notion.Client/Api/FileUploads/Retrieve/Request/IRetrieveFileUploadQueryParameters.cs @@ -0,0 +1,10 @@ +namespace Notion.Client +{ + public interface IRetrieveFileUploadPathParameters + { + /// + /// The ID of the File Upload to retrieve. + /// + string FileUploadId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/FileUploads/Retrieve/Request/RetrieveFileUploadRequest.cs b/Src/Notion.Client/Api/FileUploads/Retrieve/Request/RetrieveFileUploadRequest.cs new file mode 100644 index 0000000..f435302 --- /dev/null +++ b/Src/Notion.Client/Api/FileUploads/Retrieve/Request/RetrieveFileUploadRequest.cs @@ -0,0 +1,7 @@ +namespace Notion.Client +{ + public class RetrieveFileUploadRequest : IRetrieveFileUploadPathParameters + { + public string FileUploadId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/FileUploads/Retrieve/Response/RetrieveFileUploadResponse.cs b/Src/Notion.Client/Api/FileUploads/Retrieve/Response/RetrieveFileUploadResponse.cs new file mode 100644 index 0000000..38bdd01 --- /dev/null +++ b/Src/Notion.Client/Api/FileUploads/Retrieve/Response/RetrieveFileUploadResponse.cs @@ -0,0 +1,6 @@ +namespace Notion.Client +{ + public class RetrieveFileUploadResponse : FileObjectResponse + { + } +} diff --git a/Test/Notion.IntegrationTests/FileUploadsClientTests.cs b/Test/Notion.IntegrationTests/FileUploadsClientTests.cs index f91e981..ba2e1f3 100644 --- a/Test/Notion.IntegrationTests/FileUploadsClientTests.cs +++ b/Test/Notion.IntegrationTests/FileUploadsClientTests.cs @@ -139,5 +139,41 @@ public async Task ListAsync() Assert.NotNull(response.Results); Assert.True(response.Results.Count <= 5); } + + [Fact] + public async Task RetrieveAsync() + { + // Arrange + var createRequest = new CreateFileUploadRequest + { + Mode = FileUploadMode.ExternalUrl, + ExternalUrl = "https://unsplash.com/photos/hOhlYhAiizc/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNzYwMTkxNzc3fA&force=true", + FileName = "sample-image.jpg", + }; + + var createResponse = await Client.FileUploads.CreateAsync(createRequest); + + Assert.NotNull(createResponse); + Assert.NotNull(createResponse.Id); + Assert.Equal("sample-image.jpg", createResponse.FileName); + Assert.Equal("image/jpeg", createResponse.ContentType); + Assert.Equal("pending", createResponse.Status); + + // Act + var retrieveRequest = new RetrieveFileUploadRequest + { + FileUploadId = createResponse.Id + }; + + var retrieveResponse = await Client.FileUploads.RetrieveAsync(retrieveRequest); + + // Assert + Assert.NotNull(retrieveResponse); + Assert.Equal(createResponse.Id, retrieveResponse.Id); + Assert.Equal("sample-image.jpg", retrieveResponse.FileName); + Assert.Equal("image/jpeg", retrieveResponse.ContentType); + // The status might have changed from "pending" to "uploaded" depending on Notion's processing time + Assert.Contains(retrieveResponse.Status, new[] { "pending", "uploaded" }); + } } -} \ No newline at end of file +} diff --git a/Test/Notion.UnitTests/FileUploadsClientTests.cs b/Test/Notion.UnitTests/FileUploadsClientTests.cs index 3d80d7d..b29f26d 100644 --- a/Test/Notion.UnitTests/FileUploadsClientTests.cs +++ b/Test/Notion.UnitTests/FileUploadsClientTests.cs @@ -219,4 +219,61 @@ public async Task ListAsync_CallsRestClientGetAsync_WithCorrectParameters() } #endregion ListAsync Tests + + #region RetrieveAsync Tests + + // Add tests for RetrieveAsync method + [Fact] + public async Task RetrieveAsync_ThrowsArgumentNullException_WhenFileUploadIdIsNullOrEmpty() + { + // Arrange + var request = new RetrieveFileUploadRequest + { + FileUploadId = null + }; + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => _fileUploadClient.RetrieveAsync(request)); + Assert.Equal("FileUploadId", exception.ParamName); + Assert.Equal("FileUploadId cannot be null or empty. (Parameter 'FileUploadId')", exception.Message); + } + + [Fact] + public async Task RetrieveAsync_CallsRestClientGetAsync_WithCorrectParameters() + { + // Arrange + var fileUploadId = Guid.NewGuid().ToString(); + var request = new RetrieveFileUploadRequest + { + FileUploadId = fileUploadId + }; + + var expectedResponse = new RetrieveFileUploadResponse + { + Id = fileUploadId, + FileName = "testfile.txt", + Status = "completed" + }; + + _restClientMock + .Setup(client => client.GetAsync( + It.Is(url => url == ApiEndpoints.FileUploadsApiUrls.Retrieve(request)), + It.IsAny>(), + null, + null, + It.IsAny() + )) + .ReturnsAsync(expectedResponse); + + // Act + var response = await _fileUploadClient.RetrieveAsync(request); + + // Assert + Assert.Equal(expectedResponse.Id, response.Id); + Assert.Equal(expectedResponse.FileName, response.FileName); + Assert.Equal(expectedResponse.Status, response.Status); + _restClientMock.VerifyAll(); + } + + #endregion RetrieveAsync Tests }