Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Src/Notion.Client/Api/ApiEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,10 @@ public static class AuthenticationUrls
public static string IntrospectToken() => "/v1/oauth/introspect";
public static string RefreshToken() => "/v1/oauth/token";
}

public static class FileUploadsApiUrls
{
public static string Create() => "/v1/file_uploads";
}
}
}
27 changes: 27 additions & 0 deletions Src/Notion.Client/Api/FileUploads/Create/FileUploadsClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Notion.Client
{
public sealed partial class FileUploadsClient : IFileUploadsClient
{
public async Task<CreateFileUploadResponse> CreateAsync(
CreateFileUploadRequest fileUploadObjectRequest,
CancellationToken cancellationToken = default)
{
if (fileUploadObjectRequest == null)
{
throw new ArgumentNullException(nameof(fileUploadObjectRequest));
}

ICreateFileUploadBodyParameters body = fileUploadObjectRequest;

return await _restClient.PostAsync<CreateFileUploadResponse>(
ApiEndpoints.FileUploadsApiUrls.Create(),
body,
cancellationToken: cancellationToken
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Notion.Client
{
public class CreateFileUploadRequest : ICreateFileUploadBodyParameters
{
public FileUploadMode Mode { get; set; }

public string Filename { get; set; }

public string ContentType { get; set; }

public int? NumberOfParts { get; set; }

public string ExternalUrl { get; set; }
}
}
16 changes: 16 additions & 0 deletions Src/Notion.Client/Api/FileUploads/Create/Request/FileUploadMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Runtime.Serialization;

namespace Notion.Client
{
public enum FileUploadMode
{
[EnumMember(Value = "single_part")]
SinglePart,

[EnumMember(Value = "multi_part")]
MultiPart,

[EnumMember(Value = "external_url")]
ExternalUrl
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace Notion.Client
{
public interface ICreateFileUploadBodyParameters
{
/// <summary>
/// How the file is being sent. Use multi_part for files larger than 20MB.
/// Use external_url for files that are temporarily hosted publicly elsewhere.
/// Default is single_part.
/// </summary>
[JsonProperty("mode")]
[JsonConverter(typeof(StringEnumConverter))]
FileUploadMode Mode { get; }

/// <summary>
/// Name of the file to be created. Required when mode is multi_part or external_url.
/// Otherwise optional, and used to override the filename. Must include an extension, or have one inferred
/// from the content_type parameter.
/// </summary>
[JsonProperty("filename")]
string Filename { get; }

/// <summary>
/// MIME type of the file to be created. Recommended when sending the file in multiple parts.
/// Must match the content type of the file that's sent, and the extension of the filename parameter if any.
/// </summary>
[JsonProperty("content_type")]
string ContentType { get; }

/// <summary>
/// When mode is multi_part, the number of parts you are uploading.
/// Must be between 1 and 1,000. This must match the number of parts as well as the final part_number you send.
/// </summary>
[JsonProperty("number_of_parts")]
int? NumberOfParts { get; }

/// <summary>
/// When mode is external_url, provide the HTTPS URL of a publicly accessible file to import into your workspace.
/// </summary>
[JsonProperty("external_url")]
string ExternalUrl { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Notion.Client
{
public class CreateFileUploadResponse : FileObjectResponse
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Newtonsoft.Json;

namespace Notion.Client
{
public class FileImportError
{
[JsonProperty("type")]
public string Type { get; set; }

[JsonProperty("code")]
public string Code { get; set; }

[JsonProperty("message")]
public string Message { get; set; }

[JsonProperty("parameter")]
public string Parameter { get; set; }

[JsonProperty("status_code")]
public int? StatusCode { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Newtonsoft.Json;

namespace Notion.Client
{
public class FileImportErrorResult : FileImportResult
{
public override string Type => "error";

[JsonProperty("error")]
public FileImportError Error { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using JsonSubTypes;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace Notion.Client
{
[JsonConverter(typeof(JsonSubtypes), "type")]
[JsonSubtypes.KnownSubTypeAttribute(typeof(FileImportSuccessResult), "success")]
[JsonSubtypes.KnownSubTypeAttribute(typeof(FileImportErrorResult), "error")]
[JsonSubtypes.FallBackSubTypeAttribute(typeof(FileImportResult))]
public abstract class FileImportResult
{
[JsonProperty("type")]
public virtual string Type { get; set; }

[JsonProperty("imported_time")]
[JsonConverter(typeof(IsoDateTimeConverter))]
public DateTime ImportedTime { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Notion.Client
{
public class FileImportSuccessResult : FileImportResult
{
public override string Type => "success";

[JsonProperty("success")]
public Dictionary<string, object> Success { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using Newtonsoft.Json;

namespace Notion.Client
{
public class FileObjectResponse : IObject
{
public string Id { get; set; }
public ObjectType Object => ObjectType.FileUpload;

[JsonProperty("created_time")]
public DateTime CreatedTime { get; set; }

[JsonProperty("created_by")]
public PartialUser CreatedBy { get; set; }

[JsonProperty("last_edited_time")]
public DateTime LastEditedTime { get; set; }

[JsonProperty("archived")]
public bool Archived { get; set; }

[JsonProperty("expiry_time")]
public DateTime? ExpiryTime { get; set; }

[JsonProperty("status")]
public string Status { get; set; }

[JsonProperty("filename")]
public string FileName { get; set; }

[JsonProperty("content_type")]
public string ContentType { get; set; }

[JsonProperty("content_length")]
public long? ContentLength { get; set; }

[JsonProperty("upload_url")]
public string UploadUrl { get; set; }

[JsonProperty("complete_url")]
public string CompleteUrl { get; set; }

[JsonProperty("file_import_result")]
public FileImportResult FileImportResult { get; set; }
}
}
12 changes: 12 additions & 0 deletions Src/Notion.Client/Api/FileUploads/FileUploadsClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Notion.Client
{
public sealed partial class FileUploadsClient : IFileUploadsClient
{
private readonly IRestClient _restClient;

public FileUploadsClient(IRestClient restClient)
{
_restClient = restClient;
}
}
}
19 changes: 19 additions & 0 deletions Src/Notion.Client/Api/FileUploads/IFileUploadsClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Threading;
using System.Threading.Tasks;

namespace Notion.Client
{
public interface IFileUploadsClient
{
/// <summary>
/// Use this API to initiate the process of uploading a file to your Notion workspace.
/// </summary>
/// <param name="fileUploadObjectRequest"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<CreateFileUploadResponse> CreateAsync(
CreateFileUploadRequest fileUploadObjectRequest,
CancellationToken cancellationToken = default
);
}
}
5 changes: 4 additions & 1 deletion Src/Notion.Client/Models/ObjectType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public enum ObjectType
User,

[EnumMember(Value = "comment")]
Comment
Comment,

[EnumMember(Value = "file_upload")]
FileUpload,
}
}
7 changes: 6 additions & 1 deletion Src/Notion.Client/NotionClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public interface INotionClient
IBlocksClient Blocks { get; }

ICommentsClient Comments { get; }
IFileUploadsClient FileUploads { get; }

IRestClient RestClient { get; }
}
Expand All @@ -32,7 +33,8 @@ public NotionClient(
ISearchClient search,
ICommentsClient comments,
IBlocksClient blocks,
IAuthenticationClient authenticationClient)
IAuthenticationClient authenticationClient,
IFileUploadsClient fileUploadsClient)
{
RestClient = restClient;
Users = users;
Expand All @@ -42,6 +44,7 @@ public NotionClient(
Comments = comments;
Blocks = blocks;
AuthenticationClient = authenticationClient;
FileUploads = fileUploadsClient;
}

public IAuthenticationClient AuthenticationClient { get; }
Expand All @@ -58,6 +61,8 @@ public NotionClient(

public ICommentsClient Comments { get; }

public IFileUploadsClient FileUploads { get; }

public IRestClient RestClient { get; }
}
}
1 change: 1 addition & 0 deletions Src/Notion.Client/NotionClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public static NotionClient Create(ClientOptions options)
, new CommentsClient(restClient)
, new BlocksClient(restClient)
, new AuthenticationClient(restClient)
, new FileUploadsClient(restClient)
);
}
}
Expand Down
29 changes: 29 additions & 0 deletions Test/Notion.IntegrationTests/FIleUploadsClientTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Threading.Tasks;
using Notion.Client;
using Xunit;

namespace Notion.IntegrationTests
{
public class FileUploadsClientTests : IntegrationTestBase
{
[Fact]
public async Task CreateAsync()
{
// Arrange
var request = new CreateFileUploadRequest
{
Mode = FileUploadMode.ExternalUrl,
ExternalUrl = "https://unsplash.com/photos/hOhlYhAiizc/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNzYwMTkxNzc3fA&force=true",
Filename = "sample-image.jpg",
};

// Act
var response = await Client.FileUploads.CreateAsync(request);

// Assert
Assert.NotNull(response);
Assert.NotNull(response.Status);
Assert.Equal("sample-image.jpg", response.FileName);
}
}
}
2 changes: 1 addition & 1 deletion Test/Notion.IntegrationTests/IntegrationTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ protected IntegrationTestBase()
ParentPageId = GetEnvironmentVariableRequired("NOTION_PARENT_PAGE_ID");
ParentDatabaseId = GetEnvironmentVariableRequired("NOTION_PARENT_DATABASE_ID");
}

protected static string GetEnvironmentVariableRequired(string envName)
{
return Environment.GetEnvironmentVariable(envName) ??
Expand Down
Loading