From 1b3a00ce48299dc56e7ce602fcf974ca133f58d4 Mon Sep 17 00:00:00 2001 From: Herman Schoenfeld Date: Sun, 12 Mar 2023 01:27:56 +1000 Subject: [PATCH 01/89] Fix serialization exception on sync blocks --- Src/Notion.Client/Models/Blocks/IBlock.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/Notion.Client/Models/Blocks/IBlock.cs b/Src/Notion.Client/Models/Blocks/IBlock.cs index df625cf6..bbe5d6e6 100644 --- a/Src/Notion.Client/Models/Blocks/IBlock.cs +++ b/Src/Notion.Client/Models/Blocks/IBlock.cs @@ -29,6 +29,7 @@ namespace Notion.Client [JsonSubtypes.KnownSubTypeAttribute(typeof(ParagraphBlock), BlockType.Paragraph)] [JsonSubtypes.KnownSubTypeAttribute(typeof(PDFBlock), BlockType.PDF)] [JsonSubtypes.KnownSubTypeAttribute(typeof(QuoteBlock), BlockType.Quote)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(UnsupportedBlock), BlockType.SyncedBlock)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TableBlock), BlockType.Table)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TableRowBlock), BlockType.TableRow)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TableOfContentsBlock), BlockType.TableOfContents)] From 6cfcbcf1e797f613d719fb407fa52516c43ed1f9 Mon Sep 17 00:00:00 2001 From: Herman Schoenfeld Date: Mon, 13 Mar 2023 02:11:01 +1000 Subject: [PATCH 02/89] Fix heading blocks to support toggles --- Src/Notion.Client/Models/Blocks/HeadingOneBlock.cs | 5 +++-- .../Blocks/{HeadingThreeeBlock.cs => HeadingThreeBlock.cs} | 5 +++-- Src/Notion.Client/Models/Blocks/HeadingTwoBlock.cs | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) rename Src/Notion.Client/Models/Blocks/{HeadingThreeeBlock.cs => HeadingThreeBlock.cs} (88%) diff --git a/Src/Notion.Client/Models/Blocks/HeadingOneBlock.cs b/Src/Notion.Client/Models/Blocks/HeadingOneBlock.cs index b0753122..1e8474a4 100644 --- a/Src/Notion.Client/Models/Blocks/HeadingOneBlock.cs +++ b/Src/Notion.Client/Models/Blocks/HeadingOneBlock.cs @@ -13,8 +13,6 @@ public class HeadingOneBlock : Block, IColumnChildrenBlock, INonColumnBlock public override BlockType Type => BlockType.Heading_1; - public override bool HasChildren => false; - public class Info { [JsonProperty("rich_text")] @@ -23,6 +21,9 @@ public class Info [JsonProperty("color")] [JsonConverter(typeof(StringEnumConverter))] public Color? Color { get; set; } + + [JsonProperty("is_toggleable")] + public bool IsToggleable { get; set; } } } } diff --git a/Src/Notion.Client/Models/Blocks/HeadingThreeeBlock.cs b/Src/Notion.Client/Models/Blocks/HeadingThreeBlock.cs similarity index 88% rename from Src/Notion.Client/Models/Blocks/HeadingThreeeBlock.cs rename to Src/Notion.Client/Models/Blocks/HeadingThreeBlock.cs index deada7de..e300a511 100644 --- a/Src/Notion.Client/Models/Blocks/HeadingThreeeBlock.cs +++ b/Src/Notion.Client/Models/Blocks/HeadingThreeBlock.cs @@ -13,8 +13,6 @@ public class HeadingThreeBlock : Block, IColumnChildrenBlock, INonColumnBlock public override BlockType Type => BlockType.Heading_3; - public override bool HasChildren => false; - public class Info { [JsonProperty("rich_text")] @@ -23,6 +21,9 @@ public class Info [JsonProperty("color")] [JsonConverter(typeof(StringEnumConverter))] public Color? Color { get; set; } + + [JsonProperty("is_toggleable")] + public bool IsToggleable { get; set; } } } } diff --git a/Src/Notion.Client/Models/Blocks/HeadingTwoBlock.cs b/Src/Notion.Client/Models/Blocks/HeadingTwoBlock.cs index f5ffd7ea..3be849a8 100644 --- a/Src/Notion.Client/Models/Blocks/HeadingTwoBlock.cs +++ b/Src/Notion.Client/Models/Blocks/HeadingTwoBlock.cs @@ -13,8 +13,6 @@ public class HeadingTwoBlock : Block, IColumnChildrenBlock, INonColumnBlock public override BlockType Type => BlockType.Heading_2; - public override bool HasChildren => false; - public class Info { [JsonProperty("rich_text")] @@ -23,6 +21,9 @@ public class Info [JsonProperty("color")] [JsonConverter(typeof(StringEnumConverter))] public Color? Color { get; set; } + + [JsonProperty("is_toggleable")] + public bool IsToggleable { get; set; } } } } From 1c929fcba203a904b24710e01f0ace4b07b7800d Mon Sep 17 00:00:00 2001 From: romain vergnory Date: Wed, 17 May 2023 11:22:19 +0200 Subject: [PATCH 03/89] feat : Make calls cancellable --- Src/Notion.Client/Api/Blocks/BlocksClient.cs | 21 ++++++++++--------- Src/Notion.Client/Api/Blocks/IBlocksClient.cs | 13 ++++++------ .../Api/Comments/Create/CommentsClient.cs | 8 ++++--- .../Api/Comments/ICommentsClient.cs | 5 +++-- .../Api/Comments/Retrieve/CommentsClient.cs | 6 ++++-- .../Api/Databases/DatabasesClient.cs | 19 +++++++++-------- .../Api/Databases/IDatabasesClient.cs | 11 +++++----- Src/Notion.Client/Api/Pages/IPagesClient.cs | 11 +++++----- Src/Notion.Client/Api/Pages/PagesClient.cs | 21 ++++++++++--------- Src/Notion.Client/Api/Search/ISearchClient.cs | 3 ++- Src/Notion.Client/Api/Search/SearchClient.cs | 7 ++++--- Src/Notion.Client/Api/Users/IUsersClient.cs | 9 ++++---- Src/Notion.Client/Api/Users/UsersClient.cs | 15 ++++++------- 13 files changed, 82 insertions(+), 67 deletions(-) diff --git a/Src/Notion.Client/Api/Blocks/BlocksClient.cs b/Src/Notion.Client/Api/Blocks/BlocksClient.cs index 1282a346..068ce969 100644 --- a/Src/Notion.Client/Api/Blocks/BlocksClient.cs +++ b/Src/Notion.Client/Api/Blocks/BlocksClient.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; @@ -16,7 +17,7 @@ public BlocksClient(IRestClient client) public async Task> RetrieveChildrenAsync( string blockId, - BlocksRetrieveChildrenParameters parameters = null) + BlocksRetrieveChildrenParameters parameters = null, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(blockId)) { @@ -33,12 +34,12 @@ public async Task> RetrieveChildrenAsync( { "page_size", queryParameters?.PageSize?.ToString() } }; - return await _client.GetAsync>(url, queryParams); + return await _client.GetAsync>(url, queryParams, cancellationToken: cancellationToken); } public async Task> AppendChildrenAsync( string blockId, - BlocksAppendChildrenParameters parameters = null) + BlocksAppendChildrenParameters parameters = null, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(blockId)) { @@ -49,10 +50,10 @@ public async Task> AppendChildrenAsync( var body = (IBlocksAppendChildrenBodyParameters)parameters; - return await _client.PatchAsync>(url, body); + return await _client.PatchAsync>(url, body, cancellationToken: cancellationToken); } - public async Task RetrieveAsync(string blockId) + public async Task RetrieveAsync(string blockId, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(blockId)) { @@ -61,10 +62,10 @@ public async Task RetrieveAsync(string blockId) var url = BlocksApiUrls.Retrieve(blockId); - return await _client.GetAsync(url); + return await _client.GetAsync(url, cancellationToken: cancellationToken); } - public async Task UpdateAsync(string blockId, IUpdateBlock updateBlock) + public async Task UpdateAsync(string blockId, IUpdateBlock updateBlock, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(blockId)) { @@ -73,10 +74,10 @@ public async Task UpdateAsync(string blockId, IUpdateBlock updateBlock) var url = BlocksApiUrls.Update(blockId); - return await _client.PatchAsync(url, updateBlock); + return await _client.PatchAsync(url, updateBlock, cancellationToken: cancellationToken); } - public async Task DeleteAsync(string blockId) + public async Task DeleteAsync(string blockId, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(blockId)) { @@ -85,7 +86,7 @@ public async Task DeleteAsync(string blockId) var url = BlocksApiUrls.Delete(blockId); - await _client.DeleteAsync(url); + await _client.DeleteAsync(url, cancellationToken: cancellationToken); } } } diff --git a/Src/Notion.Client/Api/Blocks/IBlocksClient.cs b/Src/Notion.Client/Api/Blocks/IBlocksClient.cs index f45611b7..252a218d 100644 --- a/Src/Notion.Client/Api/Blocks/IBlocksClient.cs +++ b/Src/Notion.Client/Api/Blocks/IBlocksClient.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; namespace Notion.Client { @@ -9,7 +10,7 @@ public interface IBlocksClient /// /// /// Block - Task RetrieveAsync(string blockId); + Task RetrieveAsync(string blockId, CancellationToken cancellationToken = default); /// /// Updates the content for the specified block_id based on the block type. @@ -17,11 +18,11 @@ public interface IBlocksClient /// /// /// Block - Task UpdateAsync(string blockId, IUpdateBlock updateBlock); + Task UpdateAsync(string blockId, IUpdateBlock updateBlock, CancellationToken cancellationToken = default); Task> RetrieveChildrenAsync( string blockId, - BlocksRetrieveChildrenParameters parameters = null); + BlocksRetrieveChildrenParameters parameters = null, CancellationToken cancellationToken = default); /// /// Creates and appends new children blocks to the parent block_id specified. @@ -31,12 +32,12 @@ Task> RetrieveChildrenAsync( /// A paginated list of newly created first level children block objects. Task> AppendChildrenAsync( string blockId, - BlocksAppendChildrenParameters parameters = null); + BlocksAppendChildrenParameters parameters = null, CancellationToken cancellationToken = default); /// /// Sets a Block object, including page blocks, to archived: true using the ID specified. /// /// Identifier for a Notion block - Task DeleteAsync(string blockId); + Task DeleteAsync(string blockId, CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/Api/Comments/Create/CommentsClient.cs b/Src/Notion.Client/Api/Comments/Create/CommentsClient.cs index cb3b9bd1..ac2244ea 100644 --- a/Src/Notion.Client/Api/Comments/Create/CommentsClient.cs +++ b/Src/Notion.Client/Api/Comments/Create/CommentsClient.cs @@ -1,16 +1,18 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; namespace Notion.Client { public partial class CommentsClient { - public async Task CreateAsync(CreateCommentParameters parameters) + public async Task CreateAsync(CreateCommentParameters parameters, CancellationToken cancellationToken = default) { var body = (ICreateCommentsBodyParameters)parameters; return await _client.PostAsync( ApiEndpoints.CommentsApiUrls.Create(), - body + body, + cancellationToken: cancellationToken ); } } diff --git a/Src/Notion.Client/Api/Comments/ICommentsClient.cs b/Src/Notion.Client/Api/Comments/ICommentsClient.cs index 98ec3faf..7b7af943 100644 --- a/Src/Notion.Client/Api/Comments/ICommentsClient.cs +++ b/Src/Notion.Client/Api/Comments/ICommentsClient.cs @@ -1,11 +1,12 @@ +using System.Threading; using System.Threading.Tasks; namespace Notion.Client { public interface ICommentsClient { - Task CreateAsync(CreateCommentParameters createCommentParameters); + Task CreateAsync(CreateCommentParameters createCommentParameters, CancellationToken cancellationToken = default); - Task RetrieveAsync(RetrieveCommentsParameters parameters); + Task RetrieveAsync(RetrieveCommentsParameters parameters, CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/Api/Comments/Retrieve/CommentsClient.cs b/Src/Notion.Client/Api/Comments/Retrieve/CommentsClient.cs index 22964c5f..45c64f00 100644 --- a/Src/Notion.Client/Api/Comments/Retrieve/CommentsClient.cs +++ b/Src/Notion.Client/Api/Comments/Retrieve/CommentsClient.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Threading; using System.Threading.Tasks; namespace Notion.Client @@ -7,7 +8,7 @@ namespace Notion.Client public partial class CommentsClient { [SuppressMessage("ReSharper", "UnusedMember.Global")] - public async Task RetrieveAsync(RetrieveCommentsParameters parameters) + public async Task RetrieveAsync(RetrieveCommentsParameters parameters, CancellationToken cancellationToken = default) { var qp = (IRetrieveCommentsQueryParameters)parameters; @@ -20,7 +21,8 @@ public async Task RetrieveAsync(RetrieveCommentsParame return await _client.GetAsync( ApiEndpoints.CommentsApiUrls.Retrieve(), - queryParams + queryParams, + cancellationToken: cancellationToken ); } } diff --git a/Src/Notion.Client/Api/Databases/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/DatabasesClient.cs index 5157dee9..4412b8bb 100644 --- a/Src/Notion.Client/Api/Databases/DatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/DatabasesClient.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; namespace Notion.Client @@ -12,32 +13,32 @@ public DatabasesClient(IRestClient client) _client = client; } - public async Task RetrieveAsync(string databaseId) + public async Task RetrieveAsync(string databaseId, CancellationToken cancellationToken = default) { - return await _client.GetAsync(DatabasesApiUrls.Retrieve(databaseId)); + return await _client.GetAsync(DatabasesApiUrls.Retrieve(databaseId), cancellationToken: cancellationToken); } public async Task> QueryAsync( string databaseId, - DatabasesQueryParameters databasesQueryParameters) + DatabasesQueryParameters databasesQueryParameters, CancellationToken cancellationToken = default) { var body = (IDatabaseQueryBodyParameters)databasesQueryParameters; - return await _client.PostAsync>(DatabasesApiUrls.Query(databaseId), body); + return await _client.PostAsync>(DatabasesApiUrls.Query(databaseId), body, cancellationToken: cancellationToken); } - public async Task CreateAsync(DatabasesCreateParameters databasesCreateParameters) + public async Task CreateAsync(DatabasesCreateParameters databasesCreateParameters, CancellationToken cancellationToken = default) { var body = (IDatabasesCreateBodyParameters)databasesCreateParameters; - return await _client.PostAsync(DatabasesApiUrls.Create, body); + return await _client.PostAsync(DatabasesApiUrls.Create, body, cancellationToken: cancellationToken); } - public async Task UpdateAsync(string databaseId, DatabasesUpdateParameters databasesUpdateParameters) + public async Task UpdateAsync(string databaseId, DatabasesUpdateParameters databasesUpdateParameters, CancellationToken cancellationToken = default) { var body = (IDatabasesUpdateBodyParameters)databasesUpdateParameters; - return await _client.PatchAsync(DatabasesApiUrls.Update(databaseId), body); + return await _client.PatchAsync(DatabasesApiUrls.Update(databaseId), body, cancellationToken: cancellationToken); } } } diff --git a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs index 9c245ce3..c7e1c21a 100644 --- a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; namespace Notion.Client { @@ -11,7 +12,7 @@ public interface IDatabasesClient /// /// /// - Task RetrieveAsync(string databaseId); + Task RetrieveAsync(string databaseId, CancellationToken cancellationToken = default); /// /// Gets a list of Pages contained in the database, filtered and ordered according to the @@ -23,7 +24,7 @@ public interface IDatabasesClient /// /// /// - Task> QueryAsync(string databaseId, DatabasesQueryParameters databasesQueryParameters); + Task> QueryAsync(string databaseId, DatabasesQueryParameters databasesQueryParameters, CancellationToken cancellationToken = default); /// /// Creates a database as a subpage in the specified parent page, with the specified properties schema. @@ -32,7 +33,7 @@ public interface IDatabasesClient /// /// /// - Task CreateAsync(DatabasesCreateParameters databasesCreateParameters); + Task CreateAsync(DatabasesCreateParameters databasesCreateParameters, CancellationToken cancellationToken = default); /// /// Updates an existing database as specified by the parameters. @@ -42,6 +43,6 @@ public interface IDatabasesClient /// /// /// - Task UpdateAsync(string databaseId, DatabasesUpdateParameters databasesUpdateParameters); + Task UpdateAsync(string databaseId, DatabasesUpdateParameters databasesUpdateParameters, CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/Api/Pages/IPagesClient.cs b/Src/Notion.Client/Api/Pages/IPagesClient.cs index 755b385f..8dc8f5ce 100644 --- a/Src/Notion.Client/Api/Pages/IPagesClient.cs +++ b/Src/Notion.Client/Api/Pages/IPagesClient.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; namespace Notion.Client @@ -15,7 +16,7 @@ public interface IPagesClient /// /// Create page parameters /// Created object. - Task CreateAsync(PagesCreateParameters pagesCreateParameters); + Task CreateAsync(PagesCreateParameters pagesCreateParameters, CancellationToken cancellationToken = default); /// /// Retrieves a Page object using the ID specified. @@ -24,7 +25,7 @@ public interface IPagesClient /// /// /// - Task RetrieveAsync(string pageId); + Task RetrieveAsync(string pageId, CancellationToken cancellationToken = default); /// /// Updates page property values for the specified page. @@ -38,7 +39,7 @@ public interface IPagesClient /// Updated object Task UpdatePropertiesAsync( string pageId, - IDictionary updatedProperties); + IDictionary updatedProperties, CancellationToken cancellationToken = default); /// /// Updates page property values for the specified page. @@ -47,7 +48,7 @@ Task UpdatePropertiesAsync( /// Identifier for a Notion page /// Update property parameters /// Updated object - Task UpdateAsync(string pageId, PagesUpdateParameters pagesUpdateParameters); + Task UpdateAsync(string pageId, PagesUpdateParameters pagesUpdateParameters, CancellationToken cancellationToken = default); /// /// Retrieves a property_item object for a given pageId and propertyId. Depending on the property type, the object @@ -58,6 +59,6 @@ Task UpdatePropertiesAsync( /// /// Task RetrievePagePropertyItemAsync( - RetrievePropertyItemParameters retrievePropertyItemParameters); + RetrievePropertyItemParameters retrievePropertyItemParameters, CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/Api/Pages/PagesClient.cs b/Src/Notion.Client/Api/Pages/PagesClient.cs index 43fe143e..76b3e41a 100644 --- a/Src/Notion.Client/Api/Pages/PagesClient.cs +++ b/Src/Notion.Client/Api/Pages/PagesClient.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Threading; using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; @@ -25,7 +26,7 @@ public PagesClient(IRestClient client) /// /// Create page parameters /// Created page. - public async Task CreateAsync(PagesCreateParameters pagesCreateParameters) + public async Task CreateAsync(PagesCreateParameters pagesCreateParameters, CancellationToken cancellationToken = default) { if (pagesCreateParameters is null) { @@ -44,18 +45,18 @@ public async Task CreateAsync(PagesCreateParameters pagesCreateParameters) throw new ArgumentNullException(nameof(bodyParameters.Properties), "Properties are required!"); } - return await _client.PostAsync(PagesApiUrls.Create(), bodyParameters); + return await _client.PostAsync(PagesApiUrls.Create(), bodyParameters, cancellationToken: cancellationToken); } - public async Task RetrieveAsync(string pageId) + public async Task RetrieveAsync(string pageId, CancellationToken cancellationToken = default) { var url = PagesApiUrls.Retrieve(pageId); - return await _client.GetAsync(url); + return await _client.GetAsync(url, cancellationToken: cancellationToken); } public async Task RetrievePagePropertyItemAsync( - RetrievePropertyItemParameters retrievePropertyItemParameters) + RetrievePropertyItemParameters retrievePropertyItemParameters, CancellationToken cancellationToken = default) { var pathParameters = (IRetrievePropertyItemPathParameters)retrievePropertyItemParameters; var queryParameters = (IRetrievePropertyQueryParameters)retrievePropertyItemParameters; @@ -68,27 +69,27 @@ public async Task RetrievePagePropertyItemAsync( { "page_size", queryParameters?.PageSize?.ToString() } }; - return await _client.GetAsync(url, queryParams); + return await _client.GetAsync(url, queryParams, cancellationToken: cancellationToken); } - public async Task UpdateAsync(string pageId, PagesUpdateParameters pagesUpdateParameters) + public async Task UpdateAsync(string pageId, PagesUpdateParameters pagesUpdateParameters, CancellationToken cancellationToken = default) { var url = PagesApiUrls.Update(pageId); var body = (IPagesUpdateBodyParameters)pagesUpdateParameters; - return await _client.PatchAsync(url, body); + return await _client.PatchAsync(url, body, cancellationToken: cancellationToken); } [Obsolete("This method is obsolete. Use UpdateAsync instead. This API will be removed in future release")] public async Task UpdatePropertiesAsync( string pageId, - IDictionary updatedProperties) + IDictionary updatedProperties, CancellationToken cancellationToken = default) { var url = PagesApiUrls.UpdateProperties(pageId); var body = new UpdatePropertiesParameters { Properties = updatedProperties }; - return await _client.PatchAsync(url, body); + return await _client.PatchAsync(url, body, cancellationToken: cancellationToken); } [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")] diff --git a/Src/Notion.Client/Api/Search/ISearchClient.cs b/Src/Notion.Client/Api/Search/ISearchClient.cs index 835c14e4..a1e05990 100644 --- a/Src/Notion.Client/Api/Search/ISearchClient.cs +++ b/Src/Notion.Client/Api/Search/ISearchClient.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Threading; using System.Threading.Tasks; namespace Notion.Client @@ -14,6 +15,6 @@ public interface ISearchClient /// /// /// - Task> SearchAsync(SearchParameters parameters); + Task> SearchAsync(SearchParameters parameters, CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/Api/Search/SearchClient.cs b/Src/Notion.Client/Api/Search/SearchClient.cs index bd73acfc..cebe6aa3 100644 --- a/Src/Notion.Client/Api/Search/SearchClient.cs +++ b/Src/Notion.Client/Api/Search/SearchClient.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; namespace Notion.Client @@ -12,13 +13,13 @@ public SearchClient(IRestClient client) _client = client; } - public async Task> SearchAsync(SearchParameters parameters) + public async Task> SearchAsync(SearchParameters parameters, CancellationToken cancellationToken = default) { var url = SearchApiUrls.Search(); var body = (ISearchBodyParameters)parameters; - return await _client.PostAsync>(url, body); + return await _client.PostAsync>(url, body, cancellationToken: cancellationToken); } } } diff --git a/Src/Notion.Client/Api/Users/IUsersClient.cs b/Src/Notion.Client/Api/Users/IUsersClient.cs index 69981022..dc86ce12 100644 --- a/Src/Notion.Client/Api/Users/IUsersClient.cs +++ b/Src/Notion.Client/Api/Users/IUsersClient.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; namespace Notion.Client { @@ -11,7 +12,7 @@ public interface IUsersClient /// /// /// - Task RetrieveAsync(string userId); + Task RetrieveAsync(string userId, CancellationToken cancellationToken = default); /// /// Returns a paginated list of Users for the workspace. @@ -20,7 +21,7 @@ public interface IUsersClient /// /// /// - Task> ListAsync(); + Task> ListAsync(CancellationToken cancellationToken = default); /// /// Retrieves the bot User associated with the API token provided in the authorization header. @@ -29,6 +30,6 @@ public interface IUsersClient /// object of type bot having an owner field with information about the person who authorized /// the integration. /// - Task MeAsync(); + Task MeAsync(CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/Api/Users/UsersClient.cs b/Src/Notion.Client/Api/Users/UsersClient.cs index 957ac45e..66c18d3d 100644 --- a/Src/Notion.Client/Api/Users/UsersClient.cs +++ b/Src/Notion.Client/Api/Users/UsersClient.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; namespace Notion.Client @@ -12,14 +13,14 @@ public UsersClient(IRestClient client) _client = client; } - public async Task RetrieveAsync(string userId) + public async Task RetrieveAsync(string userId, CancellationToken cancellationToken = default) { - return await _client.GetAsync(UsersApiUrls.Retrieve(userId)); + return await _client.GetAsync(UsersApiUrls.Retrieve(userId), cancellationToken: cancellationToken); } - public async Task> ListAsync() + public async Task> ListAsync(CancellationToken cancellationToken = default) { - return await _client.GetAsync>(UsersApiUrls.List()); + return await _client.GetAsync>(UsersApiUrls.List(), cancellationToken: cancellationToken); } /// @@ -29,9 +30,9 @@ public async Task> ListAsync() /// User object of type bot having an owner field with information about the person who authorized the /// integration. /// - public async Task MeAsync() + public async Task MeAsync(CancellationToken cancellationToken = default) { - return await _client.GetAsync(UsersApiUrls.Me()); + return await _client.GetAsync(UsersApiUrls.Me(), cancellationToken: cancellationToken); } } } From aec461478f451050a7e1bd1161d8035fb8b330a5 Mon Sep 17 00:00:00 2001 From: romain vergnory Date: Wed, 17 May 2023 18:37:16 +0200 Subject: [PATCH 04/89] fix : syncedblock could not be deserialized --- Src/Notion.Client/Models/Blocks/IBlock.cs | 1 + Test/Notion.UnitTests/BlocksClientTests.cs | 2 +- .../blocks/RetrieveBlockChildrenResponse.json | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Src/Notion.Client/Models/Blocks/IBlock.cs b/Src/Notion.Client/Models/Blocks/IBlock.cs index df625cf6..24d6a12a 100644 --- a/Src/Notion.Client/Models/Blocks/IBlock.cs +++ b/Src/Notion.Client/Models/Blocks/IBlock.cs @@ -29,6 +29,7 @@ namespace Notion.Client [JsonSubtypes.KnownSubTypeAttribute(typeof(ParagraphBlock), BlockType.Paragraph)] [JsonSubtypes.KnownSubTypeAttribute(typeof(PDFBlock), BlockType.PDF)] [JsonSubtypes.KnownSubTypeAttribute(typeof(QuoteBlock), BlockType.Quote)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(SyncedBlockBlock), BlockType.SyncedBlock)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TableBlock), BlockType.Table)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TableRowBlock), BlockType.TableRow)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TableOfContentsBlock), BlockType.TableOfContents)] diff --git a/Test/Notion.UnitTests/BlocksClientTests.cs b/Test/Notion.UnitTests/BlocksClientTests.cs index 5d436b97..0d6b2c01 100644 --- a/Test/Notion.UnitTests/BlocksClientTests.cs +++ b/Test/Notion.UnitTests/BlocksClientTests.cs @@ -38,7 +38,7 @@ public async Task RetrieveBlockChildren() // Assert var children = childrenResult.Results; - children.Should().HaveCount(8); + children.Should().HaveCount(9); } [Fact] diff --git a/Test/Notion.UnitTests/data/blocks/RetrieveBlockChildrenResponse.json b/Test/Notion.UnitTests/data/blocks/RetrieveBlockChildrenResponse.json index 649185e7..7b0ae104 100644 --- a/Test/Notion.UnitTests/data/blocks/RetrieveBlockChildrenResponse.json +++ b/Test/Notion.UnitTests/data/blocks/RetrieveBlockChildrenResponse.json @@ -155,6 +155,33 @@ "expiry_time": "2022-05-11T17:55:32.613Z" } } + }, + { + "object": "block", + "id": "570d1df0-56c9-42f7-b8b8-5315323f82de", + "parent": { + "type": "page_id", + "page_id": "9b02f058-bd87-46c2-95d2-7496fb9075bb" + }, + "created_time": "2023-02-03T13:59:00.000Z", + "last_edited_time": "2023-02-03T13:59:00.000Z", + "created_by": { + "object": "user", + "id": "92e803ec-193c-4bcd-b28e-88365858d562" + }, + "last_edited_by": { + "object": "user", + "id": "92e803ec-193c-4bcd-b28e-88365858d562" + }, + "has_children": true, + "archived": false, + "type": "synced_block", + "synced_block": { + "synced_from": { + "type": "block_id", + "block_id": "d2f7e3f3-c553-410d-a5f9-dfc0c335b169" + } + } } ], "next_cursor": null, From 06ea4f40cf5172e32632ed63a0ec2c4f1a989dd8 Mon Sep 17 00:00:00 2001 From: Herman Schoenfeld Date: Thu, 18 May 2023 10:44:55 +1000 Subject: [PATCH 05/89] Fixed synced block serialization (#1) Fix synced block serialization --- Src/Notion.Client/Models/Blocks/IBlock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Notion.Client/Models/Blocks/IBlock.cs b/Src/Notion.Client/Models/Blocks/IBlock.cs index bbe5d6e6..24d6a12a 100644 --- a/Src/Notion.Client/Models/Blocks/IBlock.cs +++ b/Src/Notion.Client/Models/Blocks/IBlock.cs @@ -29,7 +29,7 @@ namespace Notion.Client [JsonSubtypes.KnownSubTypeAttribute(typeof(ParagraphBlock), BlockType.Paragraph)] [JsonSubtypes.KnownSubTypeAttribute(typeof(PDFBlock), BlockType.PDF)] [JsonSubtypes.KnownSubTypeAttribute(typeof(QuoteBlock), BlockType.Quote)] - [JsonSubtypes.KnownSubTypeAttribute(typeof(UnsupportedBlock), BlockType.SyncedBlock)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(SyncedBlockBlock), BlockType.SyncedBlock)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TableBlock), BlockType.Table)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TableRowBlock), BlockType.TableRow)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TableOfContentsBlock), BlockType.TableOfContents)] From c4b52ee8e2fe56886eb8638b9ed3ec3a11012938 Mon Sep 17 00:00:00 2001 From: RandomUser14 Date: Mon, 17 Jul 2023 12:19:41 +0200 Subject: [PATCH 06/89] fix: UniqueId property support --- .../Models/Database/Properties/Property.cs | 1 + .../Models/Database/Properties/PropertyType.cs | 5 ++++- .../Database/Properties/UniqueIdProperty.cs | 15 +++++++++++++++ Test/Notion.UnitTests/PropertyTests.cs | 2 ++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Src/Notion.Client/Models/Database/Properties/UniqueIdProperty.cs diff --git a/Src/Notion.Client/Models/Database/Properties/Property.cs b/Src/Notion.Client/Models/Database/Properties/Property.cs index 163b7ef0..fa0dac50 100644 --- a/Src/Notion.Client/Models/Database/Properties/Property.cs +++ b/Src/Notion.Client/Models/Database/Properties/Property.cs @@ -25,6 +25,7 @@ namespace Notion.Client [JsonSubtypes.KnownSubTypeAttribute(typeof(StatusProperty), PropertyType.Status)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TitleProperty), PropertyType.Title)] [JsonSubtypes.KnownSubTypeAttribute(typeof(UrlProperty), PropertyType.Url)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(UniqueIdProperty), PropertyType.UniqueId)] public class Property { [JsonProperty("id")] diff --git a/Src/Notion.Client/Models/Database/Properties/PropertyType.cs b/Src/Notion.Client/Models/Database/Properties/PropertyType.cs index e4db339a..1d53b2a8 100644 --- a/Src/Notion.Client/Models/Database/Properties/PropertyType.cs +++ b/Src/Notion.Client/Models/Database/Properties/PropertyType.cs @@ -67,6 +67,9 @@ public enum PropertyType LastEditedTime, [EnumMember(Value = "status")] - Status + Status, + + [EnumMember(Value = "unique_id")] + UniqueId, } } diff --git a/Src/Notion.Client/Models/Database/Properties/UniqueIdProperty.cs b/Src/Notion.Client/Models/Database/Properties/UniqueIdProperty.cs new file mode 100644 index 00000000..8b56b462 --- /dev/null +++ b/Src/Notion.Client/Models/Database/Properties/UniqueIdProperty.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class UniqueIdProperty : Property + { + public override PropertyType Type => PropertyType.UniqueId; + + [JsonProperty("unique_id")] + public Dictionary UniqueId { get; set; } + } +} + diff --git a/Test/Notion.UnitTests/PropertyTests.cs b/Test/Notion.UnitTests/PropertyTests.cs index 07949131..fc748413 100644 --- a/Test/Notion.UnitTests/PropertyTests.cs +++ b/Test/Notion.UnitTests/PropertyTests.cs @@ -26,6 +26,7 @@ public class PropertyTests [InlineData(typeof(SelectProperty), PropertyType.Select)] [InlineData(typeof(TitleProperty), PropertyType.Title)] [InlineData(typeof(UrlProperty), PropertyType.Url)] + [InlineData(typeof(UniqueIdProperty), PropertyType.UniqueId)] public void TestPropertyType(Type type, PropertyType expectedPropertyType) { var typeInstance = (Property)Activator.CreateInstance(type); @@ -54,6 +55,7 @@ public void TestPropertyType(Type type, PropertyType expectedPropertyType) [InlineData(typeof(SelectProperty), "select")] [InlineData(typeof(TitleProperty), "title")] [InlineData(typeof(UrlProperty), "url")] + [InlineData(typeof(UniqueIdProperty), "unique_id")] public void TestPropertyTypeText(Type type, string expectedPropertyType) { var typeInstance = (Property)Activator.CreateInstance(type); From a298ec89837f3f786de6e41640d1ef74d6db100e Mon Sep 17 00:00:00 2001 From: RandomUser14 Date: Mon, 17 Jul 2023 13:17:08 +0200 Subject: [PATCH 07/89] fix: Unique Id property parsing --- .../Models/PropertyValue/PropertyValue.cs | 1 + .../Models/PropertyValue/PropertyValueType.cs | 5 +++- .../PropertyValue/UniqueIdPropertyValue.cs | 29 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs diff --git a/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs index c423be82..5f7a6b05 100644 --- a/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs @@ -29,6 +29,7 @@ namespace Notion.Client [JsonSubtypes.KnownSubTypeAttribute(typeof(StatusPropertyValue), PropertyValueType.Status)] [JsonSubtypes.KnownSubTypeAttribute(typeof(TitlePropertyValue), PropertyValueType.Title)] [JsonSubtypes.KnownSubTypeAttribute(typeof(UrlPropertyValue), PropertyValueType.Url)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(UniqueIdPropertyValue), PropertyValueType.UniqueId)] [SuppressMessage("ReSharper", "UnusedMember.Global")] [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] public class PropertyValue diff --git a/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs b/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs index 96ddaf77..ca6759c0 100644 --- a/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs +++ b/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs @@ -70,6 +70,9 @@ public enum PropertyValueType LastEditedBy, [EnumMember(Value = "status")] - Status + Status, + + [EnumMember(Value = "unique_id")] + UniqueId, } } diff --git a/Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs new file mode 100644 index 00000000..716d9cce --- /dev/null +++ b/Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs @@ -0,0 +1,29 @@ +using System; +using Newtonsoft.Json; + +namespace Notion.Client +{ + /// + /// Unique Id property value object. + /// + public class UniqueIdPropertyValue : PropertyValue + { + public override PropertyValueType Type => PropertyValueType.UniqueId; + + /// + /// Unique Id property of database item + /// + [JsonProperty("unique_id")] + public UniqueIdValue UniqueId { get; set; } + } + + public class UniqueIdValue + { + [JsonProperty("prefix")] + public string Prefix { get; set; } + + [JsonProperty("number")] + public double? Number { get; set; } + } +} + From 366c5a408fde510940e211781d90bf2975f11fce Mon Sep 17 00:00:00 2001 From: Dmitry Fomenko Date: Thu, 7 Sep 2023 14:29:40 +0300 Subject: [PATCH 08/89] Fix Timestamp property value --- .../Models/Filters/TimestampLastEditedTimeFilter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Notion.Client/Models/Filters/TimestampLastEditedTimeFilter.cs b/Src/Notion.Client/Models/Filters/TimestampLastEditedTimeFilter.cs index 695183cc..1cd22974 100644 --- a/Src/Notion.Client/Models/Filters/TimestampLastEditedTimeFilter.cs +++ b/Src/Notion.Client/Models/Filters/TimestampLastEditedTimeFilter.cs @@ -39,7 +39,7 @@ public TimestampLastEditedTimeFilter( } [JsonProperty("timestamp")] - public string Timestamp => "last_modified_time"; + public string Timestamp => "last_edited_time"; [JsonProperty("last_edited_time")] public DateFilter.Condition LastEditedTime { get; set; } From b3f859134b4e5f82a2739bbcd4db8c9e18d923fc Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 17 Sep 2023 03:09:52 +0530 Subject: [PATCH 09/89] Add support to pagination query params to List Users --- Src/Notion.Client/Api/Users/IUsersClient.cs | 6 ++++ .../Users/List/Request/ListUsersParameters.cs | 13 ++++++++ .../Api/Users/List/UsersClient.cs | 30 +++++++++++++++++++ Src/Notion.Client/Api/Users/UsersClient.cs | 2 +- 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 Src/Notion.Client/Api/Users/List/Request/ListUsersParameters.cs create mode 100644 Src/Notion.Client/Api/Users/List/UsersClient.cs diff --git a/Src/Notion.Client/Api/Users/IUsersClient.cs b/Src/Notion.Client/Api/Users/IUsersClient.cs index dc86ce12..0f9f18ac 100644 --- a/Src/Notion.Client/Api/Users/IUsersClient.cs +++ b/Src/Notion.Client/Api/Users/IUsersClient.cs @@ -1,5 +1,6 @@ using System.Threading; using System.Threading.Tasks; +using Notion.Client.List.Request; namespace Notion.Client { @@ -23,6 +24,11 @@ public interface IUsersClient /// Task> ListAsync(CancellationToken cancellationToken = default); + Task> ListAsync( + ListUsersParameters listUsersParameters, + CancellationToken cancellationToken = default + ); + /// /// Retrieves the bot User associated with the API token provided in the authorization header. /// diff --git a/Src/Notion.Client/Api/Users/List/Request/ListUsersParameters.cs b/Src/Notion.Client/Api/Users/List/Request/ListUsersParameters.cs new file mode 100644 index 00000000..046a0c5b --- /dev/null +++ b/Src/Notion.Client/Api/Users/List/Request/ListUsersParameters.cs @@ -0,0 +1,13 @@ +namespace Notion.Client.List.Request +{ + public interface IListUsersQueryParameters : IPaginationParameters + { + } + + public class ListUsersParameters : IListUsersQueryParameters + { + public string StartCursor { get; set; } + + public int? PageSize { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Users/List/UsersClient.cs b/Src/Notion.Client/Api/Users/List/UsersClient.cs new file mode 100644 index 00000000..57c40ea3 --- /dev/null +++ b/Src/Notion.Client/Api/Users/List/UsersClient.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Notion.Client.List.Request; + +namespace Notion.Client +{ + public partial class UsersClient + { + public async Task> ListAsync( + ListUsersParameters listUsersParameters, + CancellationToken cancellationToken = default + ) + { + var queryParameters = (IListUsersQueryParameters)listUsersParameters; + + var queryParams = new Dictionary + { + { "start_cursor", queryParameters?.StartCursor }, + { "page_size", queryParameters?.PageSize?.ToString() } + }; + + return await _client.GetAsync>( + ApiEndpoints.UsersApiUrls.List(), + queryParams, + cancellationToken: cancellationToken + ); + } + } +} diff --git a/Src/Notion.Client/Api/Users/UsersClient.cs b/Src/Notion.Client/Api/Users/UsersClient.cs index 66c18d3d..f40299ee 100644 --- a/Src/Notion.Client/Api/Users/UsersClient.cs +++ b/Src/Notion.Client/Api/Users/UsersClient.cs @@ -4,7 +4,7 @@ namespace Notion.Client { - public class UsersClient : IUsersClient + public partial class UsersClient : IUsersClient { private readonly IRestClient _client; From 2c2b9f3404497fef17ca7cd5a8d18d882932ba44 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 17 Sep 2023 03:10:20 +0530 Subject: [PATCH 10/89] Run dotnet format --- .../Models/Database/Properties/PropertyType.cs | 2 +- .../Database/Properties/UniqueIdProperty.cs | 5 ++--- .../PropertyValue/UniqueIdPropertyValue.cs | 3 +-- .../IBlocksClientTests.cs | 16 ++++++++-------- Test/Notion.IntegrationTests/IPageClientTests.cs | 4 ++-- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Src/Notion.Client/Models/Database/Properties/PropertyType.cs b/Src/Notion.Client/Models/Database/Properties/PropertyType.cs index 1d53b2a8..6391308c 100644 --- a/Src/Notion.Client/Models/Database/Properties/PropertyType.cs +++ b/Src/Notion.Client/Models/Database/Properties/PropertyType.cs @@ -70,6 +70,6 @@ public enum PropertyType Status, [EnumMember(Value = "unique_id")] - UniqueId, + UniqueId, } } diff --git a/Src/Notion.Client/Models/Database/Properties/UniqueIdProperty.cs b/Src/Notion.Client/Models/Database/Properties/UniqueIdProperty.cs index 8b56b462..4a9e9d5d 100644 --- a/Src/Notion.Client/Models/Database/Properties/UniqueIdProperty.cs +++ b/Src/Notion.Client/Models/Database/Properties/UniqueIdProperty.cs @@ -1,9 +1,8 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Newtonsoft.Json; namespace Notion.Client -{ +{ public class UniqueIdProperty : Property { public override PropertyType Type => PropertyType.UniqueId; diff --git a/Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs index 716d9cce..0ce1c704 100644 --- a/Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs @@ -1,5 +1,4 @@ -using System; -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Notion.Client { diff --git a/Test/Notion.IntegrationTests/IBlocksClientTests.cs b/Test/Notion.IntegrationTests/IBlocksClientTests.cs index 6f10189c..3f616cfa 100644 --- a/Test/Notion.IntegrationTests/IBlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/IBlocksClientTests.cs @@ -211,7 +211,7 @@ private static IEnumerable BlockData() new Action((block, client) => { block.Should().NotBeNull(); - + block.Should().BeOfType().Subject .Audio.Should().BeOfType().Subject .External.Url.Should().Be("https://www.soundhelix.com/examples/mp3/SoundHelix-Song-3.mp3"); @@ -252,7 +252,7 @@ private static IEnumerable BlockData() { Assert.NotNull(block); var calloutBlock = Assert.IsType(block); - + Assert.Equal("Test 2", calloutBlock.Callout.RichText.OfType().First().Text.Content); }) }, @@ -282,7 +282,7 @@ private static IEnumerable BlockData() { Assert.NotNull(block); var quoteBlock = Assert.IsType(block); - + Assert.Equal("Test 2", quoteBlock.Quote.RichText.OfType().First().Text.Content); }) }, @@ -314,7 +314,7 @@ private static IEnumerable BlockData() Assert.NotNull(block); var imageBlock = Assert.IsType(block); var imageFile = Assert.IsType(imageBlock.Image); - + Assert.Equal("https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg", imageFile.External.Url); }) @@ -339,7 +339,7 @@ private static IEnumerable BlockData() { Assert.NotNull(block); var embedBlock = Assert.IsType(block); - + Assert.Equal("https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg", embedBlock.Embed.Url); }) @@ -381,10 +381,10 @@ private static IEnumerable BlockData() { Assert.NotNull(block); var templateBlock = Assert.IsType(block); - + Assert.Single(templateBlock.Template.RichText); Assert.Null(templateBlock.Template.Children); - + Assert.Equal("Test Template 2", templateBlock.Template.RichText.OfType().First().Text.Content); }) @@ -407,7 +407,7 @@ private static IEnumerable BlockData() { Assert.NotNull(block); var linkToPageBlock = Assert.IsType(block); - + var pageParent = Assert.IsType(linkToPageBlock.LinkToPage); // TODO: Currently the api doesn't allow to update the link_to_page block type diff --git a/Test/Notion.IntegrationTests/IPageClientTests.cs b/Test/Notion.IntegrationTests/IPageClientTests.cs index f0833be5..84ac493e 100644 --- a/Test/Notion.IntegrationTests/IPageClientTests.cs +++ b/Test/Notion.IntegrationTests/IPageClientTests.cs @@ -330,11 +330,11 @@ public async Task Bug_exception_when_attempting_to_set_select_property_to_nothin }; var updatedPage = await Client.Pages.UpdateAsync(page.Id, updatePageRequest); - + // Assert page.Properties["Colors1"].As().Select.Name.Should().Be("Red"); page.Properties["Colors2"].As().Select.Name.Should().Be("Green"); - + updatedPage.Properties["Colors1"].As().Select.Name.Should().Be("Blue"); updatedPage.Properties["Colors2"].As().Select.Should().BeNull(); From 2eff28f78263de0ee8c9c6b433cb600ee1c21a46 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 17 Sep 2023 03:32:04 +0530 Subject: [PATCH 11/89] Add support for Verification Property --- .../Models/PropertyValue/PropertyValue.cs | 1 + .../Models/PropertyValue/PropertyValueType.cs | 3 ++ .../VerificationPropertyValue.cs | 39 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 Src/Notion.Client/Models/PropertyValue/VerificationPropertyValue.cs diff --git a/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs index 5f7a6b05..a74b11da 100644 --- a/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs @@ -30,6 +30,7 @@ namespace Notion.Client [JsonSubtypes.KnownSubTypeAttribute(typeof(TitlePropertyValue), PropertyValueType.Title)] [JsonSubtypes.KnownSubTypeAttribute(typeof(UrlPropertyValue), PropertyValueType.Url)] [JsonSubtypes.KnownSubTypeAttribute(typeof(UniqueIdPropertyValue), PropertyValueType.UniqueId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(VerificationPropertyValue), PropertyValueType.Verification)] [SuppressMessage("ReSharper", "UnusedMember.Global")] [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] public class PropertyValue diff --git a/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs b/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs index ca6759c0..d77a564c 100644 --- a/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs +++ b/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs @@ -74,5 +74,8 @@ public enum PropertyValueType [EnumMember(Value = "unique_id")] UniqueId, + + [EnumMember(Value = "verification")] + Verification, } } diff --git a/Src/Notion.Client/Models/PropertyValue/VerificationPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/VerificationPropertyValue.cs new file mode 100644 index 00000000..8cdb9bae --- /dev/null +++ b/Src/Notion.Client/Models/PropertyValue/VerificationPropertyValue.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + /// + /// Verification property value. + /// + public class VerificationPropertyValue : PropertyValue + { + public override PropertyValueType Type => PropertyValueType.Verification; + + /// + /// Object containing verification type-specific data. + /// + [JsonProperty("verification")] + public Info Verification { get; set; } + + public class Info + { + /// + /// The state of verification. Possible values are "verified" and "unverified". + /// + [JsonProperty("state")] + public string State { get; set; } + + /// + /// Describes the user who verified this page. + /// + [JsonProperty("verified_by")] + public User VerifiedBy { get; set; } + + /// + /// Date verification property values contain a date property value. + /// + [JsonProperty("date")] + public Date Date { get; set; } + } + } +} From 0c2df505fc82d807f0295dece0a930cf6252a3b1 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 17 Sep 2023 03:40:33 +0530 Subject: [PATCH 12/89] Add new notion api error codes --- Src/Notion.Client/NotionAPIErrorCode.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Src/Notion.Client/NotionAPIErrorCode.cs b/Src/Notion.Client/NotionAPIErrorCode.cs index 1dc822bd..e0264ae7 100644 --- a/Src/Notion.Client/NotionAPIErrorCode.cs +++ b/Src/Notion.Client/NotionAPIErrorCode.cs @@ -15,6 +15,9 @@ public enum NotionAPIErrorCode [EnumMember(Value = "invalid_request")] InvalidRequest, + [EnumMember(Value = "invalid_grant")] + InvalidGrant, + [EnumMember(Value = "validation_error")] ValidationError, @@ -40,6 +43,12 @@ public enum NotionAPIErrorCode InternalServerError, [EnumMember(Value = "service_unavailable")] - ServiceUnavailable + ServiceUnavailable, + + [EnumMember(Value = "database_connection_unavailable")] + DatabaseConnectionUnavailable, + + [EnumMember(Value = "gateway_timeout")] + GetewayTimeout } } From 9a393508a6c04e6b01f2828f72daefb5b80f4f80 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 17 Sep 2023 03:47:01 +0530 Subject: [PATCH 13/89] Add public_url on Page and Database --- Src/Notion.Client/Models/Database/Database.cs | 6 ++++++ Src/Notion.Client/Models/Page/Page.cs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/Src/Notion.Client/Models/Database/Database.cs b/Src/Notion.Client/Models/Database/Database.cs index 33da29b7..f83d3316 100644 --- a/Src/Notion.Client/Models/Database/Database.cs +++ b/Src/Notion.Client/Models/Database/Database.cs @@ -52,5 +52,11 @@ public class Database : IObject, IObjectModificationData public PartialUser CreatedBy { get; set; } public PartialUser LastEditedBy { get; set; } + + /// + /// The public page URL if the page has been published to the web. Otherwise, null. + /// + [JsonProperty("public_url")] + public string PublicUrl { get; set; } } } diff --git a/Src/Notion.Client/Models/Page/Page.cs b/Src/Notion.Client/Models/Page/Page.cs index 996bdd46..cd81c411 100644 --- a/Src/Notion.Client/Models/Page/Page.cs +++ b/Src/Notion.Client/Models/Page/Page.cs @@ -67,5 +67,11 @@ public class Page : IObject, IObjectModificationData public PartialUser CreatedBy { get; set; } public PartialUser LastEditedBy { get; set; } + + /// + /// The public page URL if the page has been published to the web. Otherwise, null. + /// + [JsonProperty("public_url")] + public string PublicUrl { get; set; } } } From 6ee3e6364780704f4bf29aa2c6d43c2d528a921c Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 17 Sep 2023 03:51:39 +0530 Subject: [PATCH 14/89] A support for `after` parameter to the Append block children API --- .../Blocks/RequestParams/BlocksAppendChildrenParameters.cs | 2 ++ .../RequestParams/IBlocksAppendChildrenBodyParameters.cs | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksAppendChildrenParameters.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksAppendChildrenParameters.cs index e78899bb..0d5574dd 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksAppendChildrenParameters.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksAppendChildrenParameters.cs @@ -5,5 +5,7 @@ namespace Notion.Client public class BlocksAppendChildrenParameters : IBlocksAppendChildrenBodyParameters { public IEnumerable Children { get; set; } + + public string After { get; set; } } } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksAppendChildrenBodyParameters.cs b/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksAppendChildrenBodyParameters.cs index bdd4d324..ef1321aa 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksAppendChildrenBodyParameters.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksAppendChildrenBodyParameters.cs @@ -8,5 +8,11 @@ public interface IBlocksAppendChildrenBodyParameters { [JsonProperty("children")] IEnumerable Children { get; set; } + + /// + /// The ID of the existing block that the new block should be appended after. + /// + [JsonProperty("after")] + public string After { get; set; } } } From 0029cf791ffeb90a44757bec610fe3b5019baac3 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 17 Sep 2023 04:15:58 +0530 Subject: [PATCH 15/89] Add support for filter_properties in Database query api query params --- .../Api/Databases/DatabasesClient.cs | 15 +++++++++++++-- .../RequestParams/DatabasesQueryParameters.cs | 4 +++- .../IDatabaseQueryQueryParameters.cs | 11 +++++++++++ Src/Notion.Client/RestClient/IRestClient.cs | 2 +- Src/Notion.Client/RestClient/RestClient.cs | 6 +++--- Src/Notion.Client/http/QueryHelpers.cs | 2 +- 6 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 Src/Notion.Client/Api/Databases/RequestParams/IDatabaseQueryQueryParameters.cs diff --git a/Src/Notion.Client/Api/Databases/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/DatabasesClient.cs index 4412b8bb..ca6a1bef 100644 --- a/Src/Notion.Client/Api/Databases/DatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/DatabasesClient.cs @@ -1,4 +1,6 @@ -using System.Threading; +using System.Collections.Generic; +using System.Linq; +using System.Threading; using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; @@ -23,8 +25,17 @@ public async Task> QueryAsync( DatabasesQueryParameters databasesQueryParameters, CancellationToken cancellationToken = default) { var body = (IDatabaseQueryBodyParameters)databasesQueryParameters; + var queryParameters = (IDatabaseQueryQueryParameters)databasesQueryParameters; - return await _client.PostAsync>(DatabasesApiUrls.Query(databaseId), body, cancellationToken: cancellationToken); + var queryParams = queryParameters.FilterProperties? + .Select(x => new KeyValuePair("filter_properties", x)); + + return await _client.PostAsync>( + DatabasesApiUrls.Query(databaseId), + body, + queryParams, + cancellationToken: cancellationToken + ); } public async Task CreateAsync(DatabasesCreateParameters databasesCreateParameters, CancellationToken cancellationToken = default) diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesQueryParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesQueryParameters.cs index 51bd8a06..2c2bb030 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesQueryParameters.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesQueryParameters.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class DatabasesQueryParameters : IDatabaseQueryBodyParameters + public class DatabasesQueryParameters : IDatabaseQueryBodyParameters, IDatabaseQueryQueryParameters { public Filter Filter { get; set; } @@ -11,5 +11,7 @@ public class DatabasesQueryParameters : IDatabaseQueryBodyParameters public string StartCursor { get; set; } public int? PageSize { get; set; } + + public List FilterProperties { get; set; } } } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/IDatabaseQueryQueryParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/IDatabaseQueryQueryParameters.cs new file mode 100644 index 00000000..f8ba1f41 --- /dev/null +++ b/Src/Notion.Client/Api/Databases/RequestParams/IDatabaseQueryQueryParameters.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IDatabaseQueryQueryParameters + { + [JsonProperty("filter_properties")] + List FilterProperties { get; set; } + } +} diff --git a/Src/Notion.Client/RestClient/IRestClient.cs b/Src/Notion.Client/RestClient/IRestClient.cs index 7abb8553..b8ffe5b3 100644 --- a/Src/Notion.Client/RestClient/IRestClient.cs +++ b/Src/Notion.Client/RestClient/IRestClient.cs @@ -17,7 +17,7 @@ Task GetAsync( Task PostAsync( string uri, object body, - IDictionary queryParams = null, + IEnumerable> queryParams = null, IDictionary headers = null, JsonSerializerSettings serializerSettings = null, CancellationToken cancellationToken = default); diff --git a/Src/Notion.Client/RestClient/RestClient.cs b/Src/Notion.Client/RestClient/RestClient.cs index 307fcd7a..e64f187d 100644 --- a/Src/Notion.Client/RestClient/RestClient.cs +++ b/Src/Notion.Client/RestClient/RestClient.cs @@ -45,7 +45,7 @@ public async Task GetAsync( public async Task PostAsync( string uri, object body, - IDictionary queryParams = null, + IEnumerable> queryParams = null, IDictionary headers = null, JsonSerializerSettings serializerSettings = null, CancellationToken cancellationToken = default) @@ -125,7 +125,7 @@ private static async Task BuildException(HttpResponseMessage response private async Task SendAsync( string requestUri, HttpMethod httpMethod, - IDictionary queryParams = null, + IEnumerable> queryParams = null, IDictionary headers = null, Action attachContent = null, CancellationToken cancellationToken = default) @@ -176,7 +176,7 @@ private void EnsureHttpClient() _httpClient.BaseAddress = new Uri(_options.BaseUrl); } - private static string AddQueryString(string uri, IDictionary queryParams) + private static string AddQueryString(string uri, IEnumerable> queryParams) { return queryParams == null ? uri : QueryHelpers.AddQueryString(uri, queryParams); } diff --git a/Src/Notion.Client/http/QueryHelpers.cs b/Src/Notion.Client/http/QueryHelpers.cs index 530536f3..60de4e7b 100644 --- a/Src/Notion.Client/http/QueryHelpers.cs +++ b/Src/Notion.Client/http/QueryHelpers.cs @@ -45,7 +45,7 @@ public static string AddQueryString(string uri, IDictionary quer return AddQueryString(uri, (IEnumerable>)queryParams); } - private static string AddQueryString( + public static string AddQueryString( string uri, IEnumerable> queryParams) { From 0882a76051b8382af007f4967f20d969f1309ad0 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 17 Sep 2023 04:40:33 +0530 Subject: [PATCH 16/89] NotionApiRateLimitException to expose Retry-After value --- Src/Notion.Client/NotionApiException.cs | 17 ++++++++++++++++- Src/Notion.Client/RestClient/RestClient.cs | 11 +++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Src/Notion.Client/NotionApiException.cs b/Src/Notion.Client/NotionApiException.cs index d11fea6f..3e5d2b5b 100644 --- a/Src/Notion.Client/NotionApiException.cs +++ b/Src/Notion.Client/NotionApiException.cs @@ -5,7 +5,7 @@ namespace Notion.Client { [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public sealed class NotionApiException : Exception + public class NotionApiException : Exception { public NotionApiException(HttpStatusCode statusCode, NotionAPIErrorCode? notionAPIErrorCode, string message) : this(statusCode, notionAPIErrorCode, message, null) @@ -29,4 +29,19 @@ private NotionApiException( public HttpStatusCode StatusCode { get; } } + + public sealed class NotionApiRateLimitException : NotionApiException + { + public TimeSpan? RetryAfter { get; } + + public NotionApiRateLimitException( + HttpStatusCode statusCode, + NotionAPIErrorCode? notionAPIErrorCode, + string message, + TimeSpan? retryAfter) + : base(statusCode, notionAPIErrorCode, message) + { + RetryAfter = retryAfter; + } + } } diff --git a/Src/Notion.Client/RestClient/RestClient.cs b/Src/Notion.Client/RestClient/RestClient.cs index 307fcd7a..a16e314e 100644 --- a/Src/Notion.Client/RestClient/RestClient.cs +++ b/Src/Notion.Client/RestClient/RestClient.cs @@ -112,6 +112,17 @@ private static async Task BuildException(HttpResponseMessage response try { errorResponse = JsonConvert.DeserializeObject(errorBody); + + if (errorResponse.ErrorCode == NotionAPIErrorCode.RateLimited) + { + var retryAfter = response.Headers.RetryAfter.Delta; + return new NotionApiRateLimitException( + response.StatusCode, + errorResponse.ErrorCode, + errorResponse.Message, + retryAfter + ); + } } catch (Exception ex) { From 5188eb4683532e07ca570bbb9bccfa2a2b2e07a9 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 17 Sep 2023 04:54:54 +0530 Subject: [PATCH 17/89] Resolve Code Factor warning --- Src/Notion.Client/NotionApiException.cs | 20 +++++------------ .../NotionApiRateLimitException.cs | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 Src/Notion.Client/NotionApiRateLimitException.cs diff --git a/Src/Notion.Client/NotionApiException.cs b/Src/Notion.Client/NotionApiException.cs index 3e5d2b5b..cf62f1b6 100644 --- a/Src/Notion.Client/NotionApiException.cs +++ b/Src/Notion.Client/NotionApiException.cs @@ -21,6 +21,11 @@ private NotionApiException( NotionAPIErrorCode = notionAPIErrorCode; StatusCode = statusCode; + InitializeData(); + } + + private void InitializeData() + { Data.Add("StatusCode", StatusCode); Data.Add("NotionApiErrorCode", NotionAPIErrorCode); } @@ -29,19 +34,4 @@ private NotionApiException( public HttpStatusCode StatusCode { get; } } - - public sealed class NotionApiRateLimitException : NotionApiException - { - public TimeSpan? RetryAfter { get; } - - public NotionApiRateLimitException( - HttpStatusCode statusCode, - NotionAPIErrorCode? notionAPIErrorCode, - string message, - TimeSpan? retryAfter) - : base(statusCode, notionAPIErrorCode, message) - { - RetryAfter = retryAfter; - } - } } diff --git a/Src/Notion.Client/NotionApiRateLimitException.cs b/Src/Notion.Client/NotionApiRateLimitException.cs new file mode 100644 index 00000000..c10cce2d --- /dev/null +++ b/Src/Notion.Client/NotionApiRateLimitException.cs @@ -0,0 +1,22 @@ +using System; +using System.Net; + +namespace Notion.Client +{ + public sealed class NotionApiRateLimitException : NotionApiException + { + public TimeSpan? RetryAfter { get; } + + public NotionApiRateLimitException( + HttpStatusCode statusCode, + NotionAPIErrorCode? notionAPIErrorCode, + string message, + TimeSpan? retryAfter) + : base(statusCode, notionAPIErrorCode, message) + { + RetryAfter = retryAfter; + + Data.Add("RetryAfter", retryAfter); + } + } +} From 9c433dafa1b50ab23b77bb41c3b53e63f2412754 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 17 Sep 2023 05:12:51 +0530 Subject: [PATCH 18/89] Change VersionPrefix 4.2.0-preview --- Src/Notion.Client/Notion.Client.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Notion.Client/Notion.Client.csproj b/Src/Notion.Client/Notion.Client.csproj index 4a614c64..c7e96e08 100644 --- a/Src/Notion.Client/Notion.Client.csproj +++ b/Src/Notion.Client/Notion.Client.csproj @@ -1,7 +1,7 @@  - 4.1.0-preview + 4.2.0-preview netstandard2.0 9.0 From 95d0b6895d0382574196c0c4c6d066d3830a20bf Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Fri, 13 Oct 2023 00:17:46 +0530 Subject: [PATCH 19/89] Integrate release drafter (#389) * Add release drafter workflow * Add release drafter configuration --- .github/release-drafter.yml | 16 +++++++++++ .github/workflows/release-drafter.yml | 41 +++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 .github/release-drafter.yml create mode 100644 .github/workflows/release-drafter.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 00000000..f42ffd37 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,16 @@ +categories: + - title: '🚀 Features' + labels: + - 'feature' + - 'enhancement' + - title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bugfix' + - 'bug' + - title: '🧰 Maintenance' + label: 'chore' +template: | + ## Changes + + $CHANGES \ No newline at end of file diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 00000000..4eed5a56 --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,41 @@ +name: Release Drafter + +on: + push: + # branches to consider in the event; optional, defaults to all + branches: + - main + # pull_request event is required only for autolabeler + pull_request: + # Only following types are handled by the action, but one can default to all as well + types: [opened, reopened, synchronize] + # pull_request_target event is required for autolabeler to support PRs from forks + pull_request_target: + types: [opened, reopened, synchronize] + +permissions: + contents: read + +jobs: + update_release_draft: + permissions: + # write permission is required to create a github release + contents: write + # write permission is required for autolabeler + # otherwise, read permission is required at least + pull-requests: write + runs-on: ubuntu-latest + steps: + # (Optional) GitHub Enterprise requires GHE_HOST variable set + #- name: Set GHE_HOST + # run: | + # echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV + + # Drafts your next Release notes as Pull Requests are merged into "master" + - uses: release-drafter/release-drafter@v5.21.1 + # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml + # with: + # config-name: my-config.yml + # disable-autolabeler: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 5ec0c9586f084e4aa3d145059f07310c96dd7a90 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:54:51 +0530 Subject: [PATCH 20/89] Add interface for Wiki database --- Src/Notion.Client/Models/Database/Database.cs | 2 +- Src/Notion.Client/Models/Database/IWikiDatabase.cs | 13 +++++++++++++ Src/Notion.Client/Models/Page/Page.cs | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 Src/Notion.Client/Models/Database/IWikiDatabase.cs diff --git a/Src/Notion.Client/Models/Database/Database.cs b/Src/Notion.Client/Models/Database/Database.cs index f83d3316..c5a46ed6 100644 --- a/Src/Notion.Client/Models/Database/Database.cs +++ b/Src/Notion.Client/Models/Database/Database.cs @@ -4,7 +4,7 @@ namespace Notion.Client { - public class Database : IObject, IObjectModificationData + public class Database : IObject, IObjectModificationData, IWikiDatabase { [JsonProperty("title")] public List Title { get; set; } diff --git a/Src/Notion.Client/Models/Database/IWikiDatabase.cs b/Src/Notion.Client/Models/Database/IWikiDatabase.cs new file mode 100644 index 00000000..ac7a798b --- /dev/null +++ b/Src/Notion.Client/Models/Database/IWikiDatabase.cs @@ -0,0 +1,13 @@ +using JsonSubTypes; +using Newtonsoft.Json; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "object")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(Page), ObjectType.Page)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(Database), ObjectType.Database)] + public interface IWikiDatabase : IObject + { + + } +} diff --git a/Src/Notion.Client/Models/Page/Page.cs b/Src/Notion.Client/Models/Page/Page.cs index cd81c411..c6bcfae1 100644 --- a/Src/Notion.Client/Models/Page/Page.cs +++ b/Src/Notion.Client/Models/Page/Page.cs @@ -4,7 +4,7 @@ namespace Notion.Client { - public class Page : IObject, IObjectModificationData + public class Page : IObject, IObjectModificationData, IWikiDatabase { /// /// The parent of this page. Can be a database, page, or workspace. From 28132edb7827cccd936b61911b0a51b38136dff7 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:57:30 +0530 Subject: [PATCH 21/89] Update Query database endpoint to return both Page and Database --- .../Api/Databases/DatabasesClient.cs | 24 ++-------------- .../Api/Databases/IDatabasesClient.cs | 2 +- .../Api/Databases/Query/DatabasesClient.cs | 28 +++++++++++++++++++ .../Request}/DatabasesQueryParameters.cs | 0 .../Request}/IDatabaseQueryBodyParameters.cs | 0 .../Request}/IDatabaseQueryQueryParameters.cs | 0 .../Query/Response/DatabaseQueryResponse.cs | 7 +++++ Test/Notion.UnitTests/DatabasesClientTests.cs | 6 ++-- 8 files changed, 42 insertions(+), 25 deletions(-) create mode 100644 Src/Notion.Client/Api/Databases/Query/DatabasesClient.cs rename Src/Notion.Client/Api/Databases/{RequestParams => Query/Request}/DatabasesQueryParameters.cs (100%) rename Src/Notion.Client/Api/Databases/{RequestParams => Query/Request}/IDatabaseQueryBodyParameters.cs (100%) rename Src/Notion.Client/Api/Databases/{RequestParams => Query/Request}/IDatabaseQueryQueryParameters.cs (100%) create mode 100644 Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs diff --git a/Src/Notion.Client/Api/Databases/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/DatabasesClient.cs index ca6a1bef..673ee122 100644 --- a/Src/Notion.Client/Api/Databases/DatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/DatabasesClient.cs @@ -1,12 +1,10 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; namespace Notion.Client { - public class DatabasesClient : IDatabasesClient + public sealed partial class DatabasesClient : IDatabasesClient { private readonly IRestClient _client; @@ -20,24 +18,6 @@ public async Task RetrieveAsync(string databaseId, CancellationToken c return await _client.GetAsync(DatabasesApiUrls.Retrieve(databaseId), cancellationToken: cancellationToken); } - public async Task> QueryAsync( - string databaseId, - DatabasesQueryParameters databasesQueryParameters, CancellationToken cancellationToken = default) - { - var body = (IDatabaseQueryBodyParameters)databasesQueryParameters; - var queryParameters = (IDatabaseQueryQueryParameters)databasesQueryParameters; - - var queryParams = queryParameters.FilterProperties? - .Select(x => new KeyValuePair("filter_properties", x)); - - return await _client.PostAsync>( - DatabasesApiUrls.Query(databaseId), - body, - queryParams, - cancellationToken: cancellationToken - ); - } - public async Task CreateAsync(DatabasesCreateParameters databasesCreateParameters, CancellationToken cancellationToken = default) { var body = (IDatabasesCreateBodyParameters)databasesCreateParameters; diff --git a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs index c7e1c21a..98df1273 100644 --- a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs @@ -24,7 +24,7 @@ public interface IDatabasesClient /// /// /// - Task> QueryAsync(string databaseId, DatabasesQueryParameters databasesQueryParameters, CancellationToken cancellationToken = default); + Task QueryAsync(string databaseId, DatabasesQueryParameters databasesQueryParameters, CancellationToken cancellationToken = default); /// /// Creates a database as a subpage in the specified parent page, with the specified properties schema. diff --git a/Src/Notion.Client/Api/Databases/Query/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/Query/DatabasesClient.cs new file mode 100644 index 00000000..2d0c62be --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Query/DatabasesClient.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class DatabasesClient + { + public async Task QueryAsync( + string databaseId, + DatabasesQueryParameters databasesQueryParameters, CancellationToken cancellationToken = default) + { + var body = (IDatabaseQueryBodyParameters)databasesQueryParameters; + var queryParameters = (IDatabaseQueryQueryParameters)databasesQueryParameters; + + var queryParams = queryParameters.FilterProperties? + .Select(x => new KeyValuePair("filter_properties", x)); + + return await _client.PostAsync( + ApiEndpoints.DatabasesApiUrls.Query(databaseId), + body, + queryParams, + cancellationToken: cancellationToken + ); + } + } +} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesQueryParameters.cs b/Src/Notion.Client/Api/Databases/Query/Request/DatabasesQueryParameters.cs similarity index 100% rename from Src/Notion.Client/Api/Databases/RequestParams/DatabasesQueryParameters.cs rename to Src/Notion.Client/Api/Databases/Query/Request/DatabasesQueryParameters.cs diff --git a/Src/Notion.Client/Api/Databases/RequestParams/IDatabaseQueryBodyParameters.cs b/Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryBodyParameters.cs similarity index 100% rename from Src/Notion.Client/Api/Databases/RequestParams/IDatabaseQueryBodyParameters.cs rename to Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryBodyParameters.cs diff --git a/Src/Notion.Client/Api/Databases/RequestParams/IDatabaseQueryQueryParameters.cs b/Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryQueryParameters.cs similarity index 100% rename from Src/Notion.Client/Api/Databases/RequestParams/IDatabaseQueryQueryParameters.cs rename to Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryQueryParameters.cs diff --git a/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs b/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs new file mode 100644 index 00000000..73968c38 --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs @@ -0,0 +1,7 @@ +namespace Notion.Client +{ + // ReSharper disable once ClassNeverInstantiated.Global + public class DatabaseQueryResponse : PaginatedList + { + } +} diff --git a/Test/Notion.UnitTests/DatabasesClientTests.cs b/Test/Notion.UnitTests/DatabasesClientTests.cs index fc06ebc7..3bd047a7 100644 --- a/Test/Notion.UnitTests/DatabasesClientTests.cs +++ b/Test/Notion.UnitTests/DatabasesClientTests.cs @@ -64,8 +64,9 @@ public async Task QueryAsync() pagesPaginatedList.Results.Should().ContainSingle(); - foreach (var page in pagesPaginatedList.Results) + foreach (var iWikiDatabase in pagesPaginatedList.Results) { + var page = (Page)iWikiDatabase; page.Parent.Should().BeAssignableTo(); page.Object.Should().Be(ObjectType.Page); } @@ -476,8 +477,9 @@ var jsonData pagesPaginatedList.Results.Should().ContainSingle(); - foreach (var page in pagesPaginatedList.Results) + foreach (var iWikiDatabase in pagesPaginatedList.Results) { + var page = (Page)iWikiDatabase; page.Parent.Should().BeAssignableTo(); page.Object.Should().Be(ObjectType.Page); From 770c4e59ccba465f8f9ed1e129323ab6f9aeca77 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:57:52 +0530 Subject: [PATCH 22/89] Add integration test for Query database api --- .../DatabasesClientTests.cs | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Test/Notion.IntegrationTests/DatabasesClientTests.cs diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs new file mode 100644 index 00000000..069f5be8 --- /dev/null +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Notion.Client; +using Xunit; + +namespace Notion.IntegrationTests; + +public class DatabasesClientTests : IntegrationTestBase, IDisposable +{ + private readonly Page _page; + + public DatabasesClientTests() + { + _page = Client.Pages.CreateAsync( + PagesCreateParametersBuilder.Create( + new ParentPageInput { PageId = ParentPageId } + ).Build() + ).Result; + } + + public void Dispose() + { + Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }).Wait(); + } + + [Fact] + public async Task QueryDatabase() + { + // Arrange + var createdDatabase = await CreateDatabaseWithAPageAsync(); + + + // Act + var response = await Client.Databases.QueryAsync(createdDatabase.Id, new DatabasesQueryParameters()); + + // Assert + Assert.NotNull(response.Results); + Assert.Single(response.Results); + var page = response.Results.Cast().First(); + var title = page.Properties["Name"] as TitlePropertyValue; + Assert.Equal("Test Title", (title!.Title.Cast().First()).Text.Content); + } + + private async Task CreateDatabaseWithAPageAsync() + { + var createDbRequest = new DatabasesCreateParameters + { + Title = new List + { + new RichTextTextInput + { + Text = new Text + { + Content = "Test List", + Link = null + } + } + }, + Properties = new Dictionary + { + { "Name", new TitlePropertySchema { Title = new Dictionary() } }, + }, + Parent = new ParentPageInput { PageId = _page.Id } + }; + + var createdDatabase = await Client.Databases.CreateAsync(createDbRequest); + + var pagesCreateParameters = PagesCreateParametersBuilder + .Create(new DatabaseParentInput { DatabaseId = createdDatabase.Id }) + .AddProperty("Name", + new TitlePropertyValue + { + Title = new List + { + new RichTextText { Text = new Text { Content = "Test Title" } } + } + }) + .Build(); + + await Client.Pages.CreateAsync(pagesCreateParameters); + + return createdDatabase; + } +} From 8236df37f5bfd444f4efc27d0755a8e438efd5b0 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Fri, 13 Oct 2023 15:02:19 +0530 Subject: [PATCH 23/89] Resolve code factor violations --- Src/Notion.Client/Models/Database/IWikiDatabase.cs | 1 - Test/Notion.IntegrationTests/DatabasesClientTests.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/Src/Notion.Client/Models/Database/IWikiDatabase.cs b/Src/Notion.Client/Models/Database/IWikiDatabase.cs index ac7a798b..59969175 100644 --- a/Src/Notion.Client/Models/Database/IWikiDatabase.cs +++ b/Src/Notion.Client/Models/Database/IWikiDatabase.cs @@ -8,6 +8,5 @@ namespace Notion.Client [JsonSubtypes.KnownSubTypeAttribute(typeof(Database), ObjectType.Database)] public interface IWikiDatabase : IObject { - } } diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs index 069f5be8..e2255339 100644 --- a/Test/Notion.IntegrationTests/DatabasesClientTests.cs +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -31,7 +31,6 @@ public async Task QueryDatabase() // Arrange var createdDatabase = await CreateDatabaseWithAPageAsync(); - // Act var response = await Client.Databases.QueryAsync(createdDatabase.Id, new DatabasesQueryParameters()); From c932a4264b89c0e402f0a1755d93069eab07fafb Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Fri, 13 Oct 2023 16:14:41 +0530 Subject: [PATCH 24/89] Add support for create token endpoint --- Src/Notion.Client/Api/ApiEndpoints.cs | 5 +++ .../Authentication/AuthenticationClient.cs | 12 +++++++ .../CreateToken/AuthenticationClient.cs | 21 +++++++++++ .../CreateToken/Request/CreateTokenRequest.cs | 13 +++++++ .../CreateToken/Request/ExternalAccount.cs | 22 ++++++++++++ .../Request/ICreateTokenBodyParameters.cs | 35 +++++++++++++++++++ .../Response/CreateTokenResponse.cs | 31 ++++++++++++++++ .../Authentication/IAuthenticationClient.cs | 22 ++++++++++++ Src/Notion.Client/NotionClient.cs | 8 ++++- Src/Notion.Client/NotionClientFactory.cs | 5 +-- 10 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 Src/Notion.Client/Api/Authentication/AuthenticationClient.cs create mode 100644 Src/Notion.Client/Api/Authentication/CreateToken/AuthenticationClient.cs create mode 100644 Src/Notion.Client/Api/Authentication/CreateToken/Request/CreateTokenRequest.cs create mode 100644 Src/Notion.Client/Api/Authentication/CreateToken/Request/ExternalAccount.cs create mode 100644 Src/Notion.Client/Api/Authentication/CreateToken/Request/ICreateTokenBodyParameters.cs create mode 100644 Src/Notion.Client/Api/Authentication/CreateToken/Response/CreateTokenResponse.cs create mode 100644 Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs diff --git a/Src/Notion.Client/Api/ApiEndpoints.cs b/Src/Notion.Client/Api/ApiEndpoints.cs index a6434683..4ed80bb1 100644 --- a/Src/Notion.Client/Api/ApiEndpoints.cs +++ b/Src/Notion.Client/Api/ApiEndpoints.cs @@ -131,5 +131,10 @@ public static string Create() return "/v1/comments"; } } + + public static class AuthenticationUrls + { + public static string CreateToken() => "/v1/oauth/token"; + } } } diff --git a/Src/Notion.Client/Api/Authentication/AuthenticationClient.cs b/Src/Notion.Client/Api/Authentication/AuthenticationClient.cs new file mode 100644 index 00000000..ab141200 --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/AuthenticationClient.cs @@ -0,0 +1,12 @@ +namespace Notion.Client +{ + public sealed partial class AuthenticationClient : IAuthenticationClient + { + private readonly IRestClient _client; + + public AuthenticationClient(IRestClient restClient) + { + _client = restClient; + } + } +} diff --git a/Src/Notion.Client/Api/Authentication/CreateToken/AuthenticationClient.cs b/Src/Notion.Client/Api/Authentication/CreateToken/AuthenticationClient.cs new file mode 100644 index 00000000..23632632 --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/CreateToken/AuthenticationClient.cs @@ -0,0 +1,21 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class AuthenticationClient + { + public async Task CreateTokenAsync( + CreateTokenRequest createTokenRequest, + CancellationToken cancellationToken = default) + { + var body = (ICreateTokenBodyParameters)createTokenRequest; + + return await _client.PostAsync( + ApiEndpoints.AuthenticationUrls.CreateToken(), + body, + cancellationToken: cancellationToken + ); + } + } +} diff --git a/Src/Notion.Client/Api/Authentication/CreateToken/Request/CreateTokenRequest.cs b/Src/Notion.Client/Api/Authentication/CreateToken/Request/CreateTokenRequest.cs new file mode 100644 index 00000000..3fe8ffde --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/CreateToken/Request/CreateTokenRequest.cs @@ -0,0 +1,13 @@ +namespace Notion.Client +{ + public class CreateTokenRequest : ICreateTokenBodyParameters + { + public string GrantType => "authorization_code"; + + public string Code { get; set; } + + public string RedirectUri { get; set; } + + public ExternalAccount ExternalAccount { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Authentication/CreateToken/Request/ExternalAccount.cs b/Src/Notion.Client/Api/Authentication/CreateToken/Request/ExternalAccount.cs new file mode 100644 index 00000000..432d709f --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/CreateToken/Request/ExternalAccount.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + /// + /// External account info + /// + public class ExternalAccount + { + /// + /// External account key + /// + [JsonProperty("key")] + public string Key { get; set; } + + /// + /// External account name + /// + [JsonProperty("name")] + public string Name { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Authentication/CreateToken/Request/ICreateTokenBodyParameters.cs b/Src/Notion.Client/Api/Authentication/CreateToken/Request/ICreateTokenBodyParameters.cs new file mode 100644 index 00000000..e896e71a --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/CreateToken/Request/ICreateTokenBodyParameters.cs @@ -0,0 +1,35 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface ICreateTokenBodyParameters + { + /// + /// A constant string: "authorization_code". + /// + [JsonProperty("grant_type")] + string GrantType { get; } + + /// + /// A unique random code that Notion generates to authenticate with your service, + /// generated when a user initiates the OAuth flow. + /// + [JsonProperty("code")] + string Code { get; set; } + + /// + /// The "redirect_uri" that was provided in the OAuth Domain & URI section + /// of the integration's Authorization settings. Do not include this field if a + /// "redirect_uri" query param was not included in the Authorization URL + /// provided to users. In most cases, this field is required. + /// + [JsonProperty("redirect_uri")] + string RedirectUri { get; set; } + + /// + /// External account details + /// + [JsonProperty("external_account")] + ExternalAccount ExternalAccount { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Authentication/CreateToken/Response/CreateTokenResponse.cs b/Src/Notion.Client/Api/Authentication/CreateToken/Response/CreateTokenResponse.cs new file mode 100644 index 00000000..fbbe7a7a --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/CreateToken/Response/CreateTokenResponse.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CreateTokenResponse + { + [JsonProperty("access_token")] + public string AccessToken { get; set; } + + [JsonProperty("token_type")] + public string TokenType { get; set; } = "bearer"; + + [JsonProperty("bot_id")] + public string BotId { get; set; } + + [JsonProperty("duplicated_template_id")] + public string DuplicatedTemplateId { get; set; } + + [JsonProperty("owner")] + public IBotOwner Owner { get; set; } + + [JsonProperty("workspace_icon")] + public string WorkspaceIcon { get; set; } + + [JsonProperty("workspace_id")] + public string WorkspaceId { get; set; } + + [JsonProperty("workspace_name")] + public string WorkspaceName { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs b/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs new file mode 100644 index 00000000..0b4ebeb8 --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs @@ -0,0 +1,22 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + /// + /// Authentication client + /// + public interface IAuthenticationClient + { + /// + /// Creates an access token that a third-party service can use to authenticate with Notion. + /// + /// + /// + /// + Task CreateTokenAsync( + CreateTokenRequest createTokenRequest, + CancellationToken cancellationToken = default + ); + } +} diff --git a/Src/Notion.Client/NotionClient.cs b/Src/Notion.Client/NotionClient.cs index ca0c1334..2fc6f479 100644 --- a/Src/Notion.Client/NotionClient.cs +++ b/Src/Notion.Client/NotionClient.cs @@ -5,6 +5,8 @@ namespace Notion.Client [SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] public interface INotionClient { + IAuthenticationClient AuthenticationClient { get; } + IUsersClient Users { get; } IDatabasesClient Databases { get; } @@ -29,7 +31,8 @@ public NotionClient( IPagesClient pages, ISearchClient search, ICommentsClient comments, - IBlocksClient blocks) + IBlocksClient blocks, + IAuthenticationClient authenticationClient) { RestClient = restClient; Users = users; @@ -38,8 +41,11 @@ public NotionClient( Search = search; Comments = comments; Blocks = blocks; + AuthenticationClient = authenticationClient; } + public IAuthenticationClient AuthenticationClient { get; } + public IUsersClient Users { get; } public IDatabasesClient Databases { get; } diff --git a/Src/Notion.Client/NotionClientFactory.cs b/Src/Notion.Client/NotionClientFactory.cs index e82ba2de..e66f0781 100644 --- a/Src/Notion.Client/NotionClientFactory.cs +++ b/Src/Notion.Client/NotionClientFactory.cs @@ -12,8 +12,9 @@ public static NotionClient Create(ClientOptions options) , new DatabasesClient(restClient) , new PagesClient(restClient) , new SearchClient(restClient) - , blocks: new BlocksClient(restClient) - , comments: new CommentsClient(restClient) + , new CommentsClient(restClient) + , new BlocksClient(restClient) + , new AuthenticationClient(restClient) ); } } From 68ddcd1b22e6296825e52fbcb602319ae65b98c6 Mon Sep 17 00:00:00 2001 From: Kashif Soofi Date: Fri, 13 Oct 2023 12:30:37 +0100 Subject: [PATCH 25/89] #390: Add missing property in paginated response --- Src/Notion.Client/Models/PaginatedList.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Src/Notion.Client/Models/PaginatedList.cs b/Src/Notion.Client/Models/PaginatedList.cs index e126125a..d0b1107f 100644 --- a/Src/Notion.Client/Models/PaginatedList.cs +++ b/Src/Notion.Client/Models/PaginatedList.cs @@ -25,5 +25,8 @@ public class PaginatedList [JsonProperty("next_cursor")] public string NextCursor { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } } } From 9ada4418e846c53c0978ef585687fa26a5abf9e7 Mon Sep 17 00:00:00 2001 From: Kashif Soofi Date: Fri, 13 Oct 2023 20:20:08 +0100 Subject: [PATCH 26/89] #390: Remove Type from RetrieveCommentsResponse --- Src/Notion.Client/Api/Comments/Retrieve/Response/Comments.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Src/Notion.Client/Api/Comments/Retrieve/Response/Comments.cs b/Src/Notion.Client/Api/Comments/Retrieve/Response/Comments.cs index c89182a5..8b3b43b3 100644 --- a/Src/Notion.Client/Api/Comments/Retrieve/Response/Comments.cs +++ b/Src/Notion.Client/Api/Comments/Retrieve/Response/Comments.cs @@ -5,9 +5,6 @@ namespace Notion.Client { public class RetrieveCommentsResponse : PaginatedList { - [JsonProperty("type")] - public string Type { get; set; } - [JsonProperty("comment")] public Dictionary Comment { get; set; } } From e66a83fa422a4298344788bba9b805ccc276aa93 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 14 Oct 2023 23:03:37 +0530 Subject: [PATCH 27/89] Add block property in paginated block children response --- Src/Notion.Client/Api/Blocks/BlocksClient.cs | 24 +------------ Src/Notion.Client/Api/Blocks/IBlocksClient.cs | 19 +++++++--- .../BlocksRetrieveChildrenParameters.cs | 9 ----- .../IBlocksRetrieveChildrenQueryParameters.cs | 6 ---- .../Blocks/RetrieveChildren/BlocksClient.cs | 36 +++++++++++++++++++ .../Request/BlockRetrieveChildrenRequest.cs | 13 +++++++ .../IBlockRetrieveChildrenPathParameters.cs | 7 ++++ .../IBlockRetrieveChildrenQueryParameters.cs | 6 ++++ .../Response/RetrieveChildrenResponse.cs | 11 ++++++ .../IBlocksClientTests.cs | 14 ++++++-- Test/Notion.UnitTests/BlocksClientTests.cs | 5 ++- 11 files changed, 104 insertions(+), 46 deletions(-) delete mode 100644 Src/Notion.Client/Api/Blocks/RequestParams/BlocksRetrieveChildrenParameters.cs delete mode 100644 Src/Notion.Client/Api/Blocks/RequestParams/IBlocksRetrieveChildrenQueryParameters.cs create mode 100644 Src/Notion.Client/Api/Blocks/RetrieveChildren/BlocksClient.cs create mode 100644 Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/BlockRetrieveChildrenRequest.cs create mode 100644 Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/IBlockRetrieveChildrenPathParameters.cs create mode 100644 Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/IBlockRetrieveChildrenQueryParameters.cs create mode 100644 Src/Notion.Client/Api/Blocks/RetrieveChildren/Response/RetrieveChildrenResponse.cs diff --git a/Src/Notion.Client/Api/Blocks/BlocksClient.cs b/Src/Notion.Client/Api/Blocks/BlocksClient.cs index 068ce969..2c82457f 100644 --- a/Src/Notion.Client/Api/Blocks/BlocksClient.cs +++ b/Src/Notion.Client/Api/Blocks/BlocksClient.cs @@ -6,7 +6,7 @@ namespace Notion.Client { - public class BlocksClient : IBlocksClient + public sealed partial class BlocksClient : IBlocksClient { private readonly IRestClient _client; @@ -15,28 +15,6 @@ public BlocksClient(IRestClient client) _client = client; } - public async Task> RetrieveChildrenAsync( - string blockId, - BlocksRetrieveChildrenParameters parameters = null, CancellationToken cancellationToken = default) - { - if (string.IsNullOrWhiteSpace(blockId)) - { - throw new ArgumentNullException(nameof(blockId)); - } - - var url = BlocksApiUrls.RetrieveChildren(blockId); - - var queryParameters = (IBlocksRetrieveChildrenQueryParameters)parameters; - - var queryParams = new Dictionary - { - { "start_cursor", queryParameters?.StartCursor }, - { "page_size", queryParameters?.PageSize?.ToString() } - }; - - return await _client.GetAsync>(url, queryParams, cancellationToken: cancellationToken); - } - public async Task> AppendChildrenAsync( string blockId, BlocksAppendChildrenParameters parameters = null, CancellationToken cancellationToken = default) diff --git a/Src/Notion.Client/Api/Blocks/IBlocksClient.cs b/Src/Notion.Client/Api/Blocks/IBlocksClient.cs index 252a218d..59dac072 100644 --- a/Src/Notion.Client/Api/Blocks/IBlocksClient.cs +++ b/Src/Notion.Client/Api/Blocks/IBlocksClient.cs @@ -18,11 +18,22 @@ public interface IBlocksClient /// /// /// Block - Task UpdateAsync(string blockId, IUpdateBlock updateBlock, CancellationToken cancellationToken = default); + Task UpdateAsync(string blockId, IUpdateBlock updateBlock, + CancellationToken cancellationToken = default); - Task> RetrieveChildrenAsync( - string blockId, - BlocksRetrieveChildrenParameters parameters = null, CancellationToken cancellationToken = default); + /// + /// Returns a paginated array of child block objects contained in the block using the ID specified. + ///
+ /// In order to receive a complete representation of a block, you may need to recursively retrieve the + /// block children of child blocks. + ///
+ /// + /// + /// + Task RetrieveChildrenAsync( + BlockRetrieveChildrenRequest request, + CancellationToken cancellationToken = default + ); /// /// Creates and appends new children blocks to the parent block_id specified. diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksRetrieveChildrenParameters.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksRetrieveChildrenParameters.cs deleted file mode 100644 index 30f9c17d..00000000 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksRetrieveChildrenParameters.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Notion.Client -{ - public class BlocksRetrieveChildrenParameters : IBlocksRetrieveChildrenQueryParameters - { - public string StartCursor { get; set; } - - public int? PageSize { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksRetrieveChildrenQueryParameters.cs b/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksRetrieveChildrenQueryParameters.cs deleted file mode 100644 index 5c85e06a..00000000 --- a/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksRetrieveChildrenQueryParameters.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Notion.Client -{ - public interface IBlocksRetrieveChildrenQueryParameters : IPaginationParameters - { - } -} diff --git a/Src/Notion.Client/Api/Blocks/RetrieveChildren/BlocksClient.cs b/Src/Notion.Client/Api/Blocks/RetrieveChildren/BlocksClient.cs new file mode 100644 index 00000000..c91f5c6d --- /dev/null +++ b/Src/Notion.Client/Api/Blocks/RetrieveChildren/BlocksClient.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class BlocksClient + { + public async Task RetrieveChildrenAsync( + BlockRetrieveChildrenRequest request, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(request.BlockId)) + { + throw new ArgumentNullException(nameof(request.BlockId)); + } + + var url = ApiEndpoints.BlocksApiUrls.RetrieveChildren(request.BlockId); + + var queryParameters = (IBlockRetrieveChildrenQueryParameters)request; + + var queryParams = new Dictionary + { + { "start_cursor", queryParameters?.StartCursor }, + { "page_size", queryParameters?.PageSize?.ToString() } + }; + + return await _client.GetAsync( + url, + queryParams, + cancellationToken: cancellationToken + ); + } + } +} diff --git a/Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/BlockRetrieveChildrenRequest.cs b/Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/BlockRetrieveChildrenRequest.cs new file mode 100644 index 00000000..c0e87f3e --- /dev/null +++ b/Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/BlockRetrieveChildrenRequest.cs @@ -0,0 +1,13 @@ +namespace Notion.Client +{ + public class BlockRetrieveChildrenRequest : + IBlockRetrieveChildrenQueryParameters, + IBlockRetrieveChildrenPathParameters + { + public string StartCursor { get; set; } + + public int? PageSize { get; set; } + + public string BlockId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/IBlockRetrieveChildrenPathParameters.cs b/Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/IBlockRetrieveChildrenPathParameters.cs new file mode 100644 index 00000000..c23c2e90 --- /dev/null +++ b/Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/IBlockRetrieveChildrenPathParameters.cs @@ -0,0 +1,7 @@ +namespace Notion.Client +{ + public interface IBlockRetrieveChildrenPathParameters + { + public string BlockId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/IBlockRetrieveChildrenQueryParameters.cs b/Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/IBlockRetrieveChildrenQueryParameters.cs new file mode 100644 index 00000000..68c7de32 --- /dev/null +++ b/Src/Notion.Client/Api/Blocks/RetrieveChildren/Request/IBlockRetrieveChildrenQueryParameters.cs @@ -0,0 +1,6 @@ +namespace Notion.Client +{ + public interface IBlockRetrieveChildrenQueryParameters : IPaginationParameters + { + } +} diff --git a/Src/Notion.Client/Api/Blocks/RetrieveChildren/Response/RetrieveChildrenResponse.cs b/Src/Notion.Client/Api/Blocks/RetrieveChildren/Response/RetrieveChildrenResponse.cs new file mode 100644 index 00000000..0b34619f --- /dev/null +++ b/Src/Notion.Client/Api/Blocks/RetrieveChildren/Response/RetrieveChildrenResponse.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class RetrieveChildrenResponse : PaginatedList + { + [JsonProperty("block")] + public Dictionary Block { get; set; } + } +} diff --git a/Test/Notion.IntegrationTests/IBlocksClientTests.cs b/Test/Notion.IntegrationTests/IBlocksClientTests.cs index 3f616cfa..9435060c 100644 --- a/Test/Notion.IntegrationTests/IBlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/IBlocksClientTests.cs @@ -68,7 +68,10 @@ public async Task UpdateBlockAsync_UpdatesGivenBlock() var blockId = blocks.Results.First().Id; await Client.Blocks.UpdateAsync(blockId, new BreadcrumbUpdateBlock()); - blocks = await Client.Blocks.RetrieveChildrenAsync(page.Id); + blocks = await Client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest + { + BlockId = page.Id + }); blocks.Results.Should().HaveCount(1); // cleanup @@ -121,7 +124,10 @@ public async Task UpdateAsync_UpdatesGivenBlock( var blockId = blocks.Results.First().Id; await Client.Blocks.UpdateAsync(blockId, updateBlock); - blocks = await Client.Blocks.RetrieveChildrenAsync(page.Id); + blocks = await Client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest + { + BlockId = page.Id + }); blocks.Results.Should().HaveCount(1); var updatedBlock = blocks.Results.First(); @@ -443,7 +449,9 @@ private static IEnumerable BlockData() var tableBlock = block.Should().NotBeNull().And.BeOfType().Subject; tableBlock.HasChildren.Should().BeTrue(); - var children = client.Blocks.RetrieveChildrenAsync(tableBlock.Id).GetAwaiter().GetResult(); + var children = client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest{ + BlockId = tableBlock.Id + }).GetAwaiter().GetResult(); children.Results.Should().ContainSingle() .Subject.Should().BeOfType() diff --git a/Test/Notion.UnitTests/BlocksClientTests.cs b/Test/Notion.UnitTests/BlocksClientTests.cs index 0d6b2c01..a1432050 100644 --- a/Test/Notion.UnitTests/BlocksClientTests.cs +++ b/Test/Notion.UnitTests/BlocksClientTests.cs @@ -34,7 +34,10 @@ public async Task RetrieveBlockChildren() ); // Act - var childrenResult = await _client.RetrieveChildrenAsync(blockId, new BlocksRetrieveChildrenParameters()); + var childrenResult = await _client.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest + { + BlockId = blockId + }); // Assert var children = childrenResult.Results; From 0d3f322fcf802f7b21ebc53e207693db1ac1288a Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 14 Oct 2023 23:37:33 +0530 Subject: [PATCH 28/89] Add block property in Append children api response --- .../Api/Blocks/AppendChildren/BlocksClient.cs | 25 ++++++++++++++++ .../Request/BlockAppendChildrenRequest.cs} | 4 ++- .../IBlockAppendChildrenBodyParameters.cs} | 2 +- .../IBlockAppendChildrenPathParameters.cs | 7 +++++ .../Response/AppendChildrenResponse.cs | 11 +++++++ Src/Notion.Client/Api/Blocks/BlocksClient.cs | 16 ---------- Src/Notion.Client/Api/Blocks/IBlocksClient.cs | 11 +++---- .../IBlocksClientTests.cs | 29 ++++++++++--------- Test/Notion.UnitTests/BlocksClientTests.cs | 5 ++-- 9 files changed, 72 insertions(+), 38 deletions(-) create mode 100644 Src/Notion.Client/Api/Blocks/AppendChildren/BlocksClient.cs rename Src/Notion.Client/Api/Blocks/{RequestParams/BlocksAppendChildrenParameters.cs => AppendChildren/Request/BlockAppendChildrenRequest.cs} (52%) rename Src/Notion.Client/Api/Blocks/{RequestParams/IBlocksAppendChildrenBodyParameters.cs => AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs} (88%) create mode 100644 Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenPathParameters.cs create mode 100644 Src/Notion.Client/Api/Blocks/AppendChildren/Response/AppendChildrenResponse.cs diff --git a/Src/Notion.Client/Api/Blocks/AppendChildren/BlocksClient.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/BlocksClient.cs new file mode 100644 index 00000000..66d9e1ea --- /dev/null +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/BlocksClient.cs @@ -0,0 +1,25 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class BlocksClient + { + public async Task AppendChildrenAsync( + BlockAppendChildrenRequest request, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(request.BlockId)) + { + throw new ArgumentNullException(nameof(request.BlockId)); + } + + var url = ApiEndpoints.BlocksApiUrls.AppendChildren(request.BlockId); + + var body = (IBlockAppendChildrenBodyParameters)request; + + return await _client.PatchAsync(url, body, cancellationToken: cancellationToken); + } + } +} diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksAppendChildrenParameters.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/BlockAppendChildrenRequest.cs similarity index 52% rename from Src/Notion.Client/Api/Blocks/RequestParams/BlocksAppendChildrenParameters.cs rename to Src/Notion.Client/Api/Blocks/AppendChildren/Request/BlockAppendChildrenRequest.cs index 0d5574dd..580d164a 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksAppendChildrenParameters.cs +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/BlockAppendChildrenRequest.cs @@ -2,10 +2,12 @@ namespace Notion.Client { - public class BlocksAppendChildrenParameters : IBlocksAppendChildrenBodyParameters + public class BlockAppendChildrenRequest : IBlockAppendChildrenBodyParameters, IBlockAppendChildrenPathParameters { public IEnumerable Children { get; set; } public string After { get; set; } + + public string BlockId { get; set; } } } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksAppendChildrenBodyParameters.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs similarity index 88% rename from Src/Notion.Client/Api/Blocks/RequestParams/IBlocksAppendChildrenBodyParameters.cs rename to Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs index ef1321aa..3d8650aa 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksAppendChildrenBodyParameters.cs +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs @@ -4,7 +4,7 @@ namespace Notion.Client { // TODO: need an input version of Block - public interface IBlocksAppendChildrenBodyParameters + public interface IBlockAppendChildrenBodyParameters { [JsonProperty("children")] IEnumerable Children { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenPathParameters.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenPathParameters.cs new file mode 100644 index 00000000..350382f6 --- /dev/null +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenPathParameters.cs @@ -0,0 +1,7 @@ +namespace Notion.Client +{ + public interface IBlockAppendChildrenPathParameters + { + public string BlockId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Blocks/AppendChildren/Response/AppendChildrenResponse.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/Response/AppendChildrenResponse.cs new file mode 100644 index 00000000..88e04ad5 --- /dev/null +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/Response/AppendChildrenResponse.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class AppendChildrenResponse : PaginatedList + { + [JsonProperty("block")] + public Dictionary Block { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Blocks/BlocksClient.cs b/Src/Notion.Client/Api/Blocks/BlocksClient.cs index 2c82457f..92713a78 100644 --- a/Src/Notion.Client/Api/Blocks/BlocksClient.cs +++ b/Src/Notion.Client/Api/Blocks/BlocksClient.cs @@ -15,22 +15,6 @@ public BlocksClient(IRestClient client) _client = client; } - public async Task> AppendChildrenAsync( - string blockId, - BlocksAppendChildrenParameters parameters = null, CancellationToken cancellationToken = default) - { - if (string.IsNullOrWhiteSpace(blockId)) - { - throw new ArgumentNullException(nameof(blockId)); - } - - var url = BlocksApiUrls.AppendChildren(blockId); - - var body = (IBlocksAppendChildrenBodyParameters)parameters; - - return await _client.PatchAsync>(url, body, cancellationToken: cancellationToken); - } - public async Task RetrieveAsync(string blockId, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(blockId)) diff --git a/Src/Notion.Client/Api/Blocks/IBlocksClient.cs b/Src/Notion.Client/Api/Blocks/IBlocksClient.cs index 59dac072..fec1b9f5 100644 --- a/Src/Notion.Client/Api/Blocks/IBlocksClient.cs +++ b/Src/Notion.Client/Api/Blocks/IBlocksClient.cs @@ -38,12 +38,13 @@ Task RetrieveChildrenAsync( /// /// Creates and appends new children blocks to the parent block_id specified. /// - /// Identifier for a block - /// + /// + /// /// A paginated list of newly created first level children block objects. - Task> AppendChildrenAsync( - string blockId, - BlocksAppendChildrenParameters parameters = null, CancellationToken cancellationToken = default); + Task AppendChildrenAsync( + BlockAppendChildrenRequest request, + CancellationToken cancellationToken = default + ); /// /// Sets a Block object, including page blocks, to archived: true using the ID specified. diff --git a/Test/Notion.IntegrationTests/IBlocksClientTests.cs b/Test/Notion.IntegrationTests/IBlocksClientTests.cs index 9435060c..24e28da7 100644 --- a/Test/Notion.IntegrationTests/IBlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/IBlocksClientTests.cs @@ -20,9 +20,9 @@ public async Task AppendChildrenAsync_AppendsBlocksGivenBlocks() ); var blocks = await Client.Blocks.AppendChildrenAsync( - page.Id, - new BlocksAppendChildrenParameters + new BlockAppendChildrenRequest { + BlockId = page.Id, Children = new List { new BreadcrumbBlock { Breadcrumb = new BreadcrumbBlock.Data() }, @@ -58,9 +58,9 @@ public async Task UpdateBlockAsync_UpdatesGivenBlock() ); var blocks = await Client.Blocks.AppendChildrenAsync( - page.Id, - new BlocksAppendChildrenParameters + new BlockAppendChildrenRequest { + BlockId = page.Id, Children = new List { new BreadcrumbBlock { Breadcrumb = new BreadcrumbBlock.Data() } } } ); @@ -68,11 +68,11 @@ public async Task UpdateBlockAsync_UpdatesGivenBlock() var blockId = blocks.Results.First().Id; await Client.Blocks.UpdateAsync(blockId, new BreadcrumbUpdateBlock()); - blocks = await Client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest + var updatedBlocks = await Client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest { BlockId = page.Id }); - blocks.Results.Should().HaveCount(1); + updatedBlocks.Results.Should().HaveCount(1); // cleanup await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); @@ -88,9 +88,9 @@ public async Task DeleteAsync_DeleteBlockWithGivenId() ); var blocks = await Client.Blocks.AppendChildrenAsync( - page.Id, - new BlocksAppendChildrenParameters + new BlockAppendChildrenRequest { + BlockId = page.Id, Children = new List { new DividerBlock { Divider = new DividerBlock.Data() }, @@ -117,20 +117,23 @@ public async Task UpdateAsync_UpdatesGivenBlock( ); var blocks = await Client.Blocks.AppendChildrenAsync( - page.Id, - new BlocksAppendChildrenParameters { Children = new List { block } } + new BlockAppendChildrenRequest + { + BlockId = page.Id, + Children = new List { block } + } ); var blockId = blocks.Results.First().Id; await Client.Blocks.UpdateAsync(blockId, updateBlock); - blocks = await Client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest + var updatedBlocks = await Client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest { BlockId = page.Id }); - blocks.Results.Should().HaveCount(1); + updatedBlocks.Results.Should().HaveCount(1); - var updatedBlock = blocks.Results.First(); + var updatedBlock = updatedBlocks.Results.First(); assert.Invoke(updatedBlock, Client); diff --git a/Test/Notion.UnitTests/BlocksClientTests.cs b/Test/Notion.UnitTests/BlocksClientTests.cs index a1432050..600e0bf4 100644 --- a/Test/Notion.UnitTests/BlocksClientTests.cs +++ b/Test/Notion.UnitTests/BlocksClientTests.cs @@ -60,8 +60,9 @@ public async Task AppendBlockChildren() .WithBody(jsonData) ); - var parameters = new BlocksAppendChildrenParameters + var request = new BlockAppendChildrenRequest { + BlockId = blockId, Children = new List { new HeadingTwoBlock @@ -100,7 +101,7 @@ public async Task AppendBlockChildren() }; // Act - var blocksResult = await _client.AppendChildrenAsync(blockId, parameters); + var blocksResult = await _client.AppendChildrenAsync(request); // Assert var blocks = blocksResult.Results; From 37a7125afac4c5b16a64d8126a3980b2e142e4fe Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 14 Oct 2023 23:40:07 +0530 Subject: [PATCH 29/89] Add database property in DatabaseQuery response --- .../Api/Databases/Query/Response/DatabaseQueryResponse.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs b/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs index 73968c38..5b7c9ec6 100644 --- a/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs +++ b/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs @@ -1,7 +1,12 @@ -namespace Notion.Client +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client { // ReSharper disable once ClassNeverInstantiated.Global public class DatabaseQueryResponse : PaginatedList { + [JsonProperty("database")] + public Dictionary Database { get; set; } } } From 063723dd96d5120ec7b53a5a99644407494b35a9 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 14 Oct 2023 23:51:17 +0530 Subject: [PATCH 30/89] Add PageOrDatabase property in search response --- Src/Notion.Client/Api/Search/ISearchClient.cs | 8 ++++++-- .../{Parameters => Request}/ISearchBodyParameters.cs | 0 .../Search/{Parameters => Request}/SearchDirection.cs | 0 .../Search/{Parameters => Request}/SearchFilter.cs | 0 .../{Parameters => Request}/SearchObjectType.cs | 0 .../SearchParameters.cs => Request/SearchRequest.cs} | 2 +- .../Api/Search/{Parameters => Request}/SearchSort.cs | 0 .../Api/Search/Response/SearchResponse.cs | 11 +++++++++++ Src/Notion.Client/Api/Search/SearchClient.cs | 10 ++++++---- Test/Notion.UnitTests/SearchClientTest.cs | 2 +- 10 files changed, 25 insertions(+), 8 deletions(-) rename Src/Notion.Client/Api/Search/{Parameters => Request}/ISearchBodyParameters.cs (100%) rename Src/Notion.Client/Api/Search/{Parameters => Request}/SearchDirection.cs (100%) rename Src/Notion.Client/Api/Search/{Parameters => Request}/SearchFilter.cs (100%) rename Src/Notion.Client/Api/Search/{Parameters => Request}/SearchObjectType.cs (100%) rename Src/Notion.Client/Api/Search/{Parameters/SearchParameters.cs => Request/SearchRequest.cs} (82%) rename Src/Notion.Client/Api/Search/{Parameters => Request}/SearchSort.cs (100%) create mode 100644 Src/Notion.Client/Api/Search/Response/SearchResponse.cs diff --git a/Src/Notion.Client/Api/Search/ISearchClient.cs b/Src/Notion.Client/Api/Search/ISearchClient.cs index a1e05990..accee1e1 100644 --- a/Src/Notion.Client/Api/Search/ISearchClient.cs +++ b/Src/Notion.Client/Api/Search/ISearchClient.cs @@ -11,10 +11,14 @@ public interface ISearchClient /// Searches all original pages, databases, and child pages/databases that are shared with the integration. /// It will not return linked databases, since these duplicate their source databases. /// - /// Search filters and body parameters + /// Search filters and body parameters + /// /// /// /// - Task> SearchAsync(SearchParameters parameters, CancellationToken cancellationToken = default); + Task SearchAsync( + SearchRequest request, + CancellationToken cancellationToken = default + ); } } diff --git a/Src/Notion.Client/Api/Search/Parameters/ISearchBodyParameters.cs b/Src/Notion.Client/Api/Search/Request/ISearchBodyParameters.cs similarity index 100% rename from Src/Notion.Client/Api/Search/Parameters/ISearchBodyParameters.cs rename to Src/Notion.Client/Api/Search/Request/ISearchBodyParameters.cs diff --git a/Src/Notion.Client/Api/Search/Parameters/SearchDirection.cs b/Src/Notion.Client/Api/Search/Request/SearchDirection.cs similarity index 100% rename from Src/Notion.Client/Api/Search/Parameters/SearchDirection.cs rename to Src/Notion.Client/Api/Search/Request/SearchDirection.cs diff --git a/Src/Notion.Client/Api/Search/Parameters/SearchFilter.cs b/Src/Notion.Client/Api/Search/Request/SearchFilter.cs similarity index 100% rename from Src/Notion.Client/Api/Search/Parameters/SearchFilter.cs rename to Src/Notion.Client/Api/Search/Request/SearchFilter.cs diff --git a/Src/Notion.Client/Api/Search/Parameters/SearchObjectType.cs b/Src/Notion.Client/Api/Search/Request/SearchObjectType.cs similarity index 100% rename from Src/Notion.Client/Api/Search/Parameters/SearchObjectType.cs rename to Src/Notion.Client/Api/Search/Request/SearchObjectType.cs diff --git a/Src/Notion.Client/Api/Search/Parameters/SearchParameters.cs b/Src/Notion.Client/Api/Search/Request/SearchRequest.cs similarity index 82% rename from Src/Notion.Client/Api/Search/Parameters/SearchParameters.cs rename to Src/Notion.Client/Api/Search/Request/SearchRequest.cs index e1c8ced8..a9ac887f 100644 --- a/Src/Notion.Client/Api/Search/Parameters/SearchParameters.cs +++ b/Src/Notion.Client/Api/Search/Request/SearchRequest.cs @@ -1,6 +1,6 @@ namespace Notion.Client { - public class SearchParameters : ISearchBodyParameters + public class SearchRequest : ISearchBodyParameters { public string Query { get; set; } diff --git a/Src/Notion.Client/Api/Search/Parameters/SearchSort.cs b/Src/Notion.Client/Api/Search/Request/SearchSort.cs similarity index 100% rename from Src/Notion.Client/Api/Search/Parameters/SearchSort.cs rename to Src/Notion.Client/Api/Search/Request/SearchSort.cs diff --git a/Src/Notion.Client/Api/Search/Response/SearchResponse.cs b/Src/Notion.Client/Api/Search/Response/SearchResponse.cs new file mode 100644 index 00000000..2be0e2f1 --- /dev/null +++ b/Src/Notion.Client/Api/Search/Response/SearchResponse.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class SearchResponse : PaginatedList + { + [JsonProperty("page_or_database")] + public Dictionary PageOrDatabase { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Search/SearchClient.cs b/Src/Notion.Client/Api/Search/SearchClient.cs index cebe6aa3..492e0940 100644 --- a/Src/Notion.Client/Api/Search/SearchClient.cs +++ b/Src/Notion.Client/Api/Search/SearchClient.cs @@ -4,7 +4,7 @@ namespace Notion.Client { - public class SearchClient : ISearchClient + public sealed class SearchClient : ISearchClient { private readonly IRestClient _client; @@ -13,13 +13,15 @@ public SearchClient(IRestClient client) _client = client; } - public async Task> SearchAsync(SearchParameters parameters, CancellationToken cancellationToken = default) + public async Task SearchAsync( + SearchRequest request, + CancellationToken cancellationToken = default) { var url = SearchApiUrls.Search(); - var body = (ISearchBodyParameters)parameters; + var body = (ISearchBodyParameters)request; - return await _client.PostAsync>(url, body, cancellationToken: cancellationToken); + return await _client.PostAsync(url, body, cancellationToken: cancellationToken); } } } diff --git a/Test/Notion.UnitTests/SearchClientTest.cs b/Test/Notion.UnitTests/SearchClientTest.cs index 63fb4a94..35765cef 100644 --- a/Test/Notion.UnitTests/SearchClientTest.cs +++ b/Test/Notion.UnitTests/SearchClientTest.cs @@ -30,7 +30,7 @@ public async Task Search() .WithBody(jsonData) ); - var searchParameters = new SearchParameters + var searchParameters = new SearchRequest { Query = "External tasks", Sort = new SearchSort From 535b161fc2d39cae5758a9de0955aa0532722565 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 00:03:34 +0530 Subject: [PATCH 31/89] Add User property to ListUsers response --- Src/Notion.Client/Api/Users/IUsersClient.cs | 18 ++++++++++++++---- ...tUsersParameters.cs => ListUsersRequest.cs} | 2 +- .../Users/List/Response/ListUsersResponse.cs | 11 +++++++++++ .../Api/Users/List/UsersClient.cs | 16 ++++++++++++---- Src/Notion.Client/Api/Users/UsersClient.cs | 5 ----- 5 files changed, 38 insertions(+), 14 deletions(-) rename Src/Notion.Client/Api/Users/List/Request/{ListUsersParameters.cs => ListUsersRequest.cs} (78%) create mode 100644 Src/Notion.Client/Api/Users/List/Response/ListUsersResponse.cs diff --git a/Src/Notion.Client/Api/Users/IUsersClient.cs b/Src/Notion.Client/Api/Users/IUsersClient.cs index 0f9f18ac..bc0c3d8a 100644 --- a/Src/Notion.Client/Api/Users/IUsersClient.cs +++ b/Src/Notion.Client/Api/Users/IUsersClient.cs @@ -19,13 +19,23 @@ public interface IUsersClient /// Returns a paginated list of Users for the workspace. /// The response may contain fewer than page_size of results. /// + /// /// - /// + /// /// - Task> ListAsync(CancellationToken cancellationToken = default); + Task ListAsync(CancellationToken cancellationToken = default); - Task> ListAsync( - ListUsersParameters listUsersParameters, + /// + /// Returns a paginated list of Users for the workspace. + /// The response may contain fewer than page_size of results. + /// + /// + /// + /// + /// + /// + Task ListAsync( + ListUsersRequest listUsersRequest, CancellationToken cancellationToken = default ); diff --git a/Src/Notion.Client/Api/Users/List/Request/ListUsersParameters.cs b/Src/Notion.Client/Api/Users/List/Request/ListUsersRequest.cs similarity index 78% rename from Src/Notion.Client/Api/Users/List/Request/ListUsersParameters.cs rename to Src/Notion.Client/Api/Users/List/Request/ListUsersRequest.cs index 046a0c5b..f3684d09 100644 --- a/Src/Notion.Client/Api/Users/List/Request/ListUsersParameters.cs +++ b/Src/Notion.Client/Api/Users/List/Request/ListUsersRequest.cs @@ -4,7 +4,7 @@ public interface IListUsersQueryParameters : IPaginationParameters { } - public class ListUsersParameters : IListUsersQueryParameters + public class ListUsersRequest : IListUsersQueryParameters { public string StartCursor { get; set; } diff --git a/Src/Notion.Client/Api/Users/List/Response/ListUsersResponse.cs b/Src/Notion.Client/Api/Users/List/Response/ListUsersResponse.cs new file mode 100644 index 00000000..2d30237f --- /dev/null +++ b/Src/Notion.Client/Api/Users/List/Response/ListUsersResponse.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ListUsersResponse : PaginatedList + { + [JsonProperty("user")] + public Dictionary User { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Users/List/UsersClient.cs b/Src/Notion.Client/Api/Users/List/UsersClient.cs index 57c40ea3..ce13633a 100644 --- a/Src/Notion.Client/Api/Users/List/UsersClient.cs +++ b/Src/Notion.Client/Api/Users/List/UsersClient.cs @@ -7,12 +7,20 @@ namespace Notion.Client { public partial class UsersClient { - public async Task> ListAsync( - ListUsersParameters listUsersParameters, + public async Task ListAsync(CancellationToken cancellationToken = default) + { + return await _client.GetAsync( + ApiEndpoints.UsersApiUrls.List(), + cancellationToken: cancellationToken + ); + } + + public async Task ListAsync( + ListUsersRequest listUsersRequest, CancellationToken cancellationToken = default ) { - var queryParameters = (IListUsersQueryParameters)listUsersParameters; + var queryParameters = (IListUsersQueryParameters)listUsersRequest; var queryParams = new Dictionary { @@ -20,7 +28,7 @@ public async Task> ListAsync( { "page_size", queryParameters?.PageSize?.ToString() } }; - return await _client.GetAsync>( + return await _client.GetAsync( ApiEndpoints.UsersApiUrls.List(), queryParams, cancellationToken: cancellationToken diff --git a/Src/Notion.Client/Api/Users/UsersClient.cs b/Src/Notion.Client/Api/Users/UsersClient.cs index f40299ee..24681b53 100644 --- a/Src/Notion.Client/Api/Users/UsersClient.cs +++ b/Src/Notion.Client/Api/Users/UsersClient.cs @@ -18,11 +18,6 @@ public async Task RetrieveAsync(string userId, CancellationToken cancellat return await _client.GetAsync(UsersApiUrls.Retrieve(userId), cancellationToken: cancellationToken); } - public async Task> ListAsync(CancellationToken cancellationToken = default) - { - return await _client.GetAsync>(UsersApiUrls.List(), cancellationToken: cancellationToken); - } - /// /// Retrieves the bot User associated with the API token provided in the authorization header. /// From bb2f97e679379f2e6c3d588b3e4441e82e391b40 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 04:12:06 +0530 Subject: [PATCH 32/89] Add wrapper class to avoid sending block id as part of request body --- .../Api/Blocks/AppendChildren/BlocksClient.cs | 2 +- .../Request/IBlockAppendChildrenBodyParameters.cs | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Src/Notion.Client/Api/Blocks/AppendChildren/BlocksClient.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/BlocksClient.cs index 66d9e1ea..50ce3c61 100644 --- a/Src/Notion.Client/Api/Blocks/AppendChildren/BlocksClient.cs +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/BlocksClient.cs @@ -17,7 +17,7 @@ public async Task AppendChildrenAsync( var url = ApiEndpoints.BlocksApiUrls.AppendChildren(request.BlockId); - var body = (IBlockAppendChildrenBodyParameters)request; + var body = new BlockAppendChildrenBodyParameters(request); return await _client.PatchAsync(url, body, cancellationToken: cancellationToken); } diff --git a/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs index 3d8650aa..b476c089 100644 --- a/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs @@ -15,4 +15,17 @@ public interface IBlockAppendChildrenBodyParameters [JsonProperty("after")] public string After { get; set; } } + + internal class BlockAppendChildrenBodyParameters : IBlockAppendChildrenBodyParameters + { + public IEnumerable Children { get; set; } + + public string After { get; set; } + + public BlockAppendChildrenBodyParameters(BlockAppendChildrenRequest request) + { + Children = request.Children; + After = request.After; + } + } } From 2c94a50422f77d949567b6ca41bca0dcff1eb06c Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 02:44:05 +0530 Subject: [PATCH 33/89] Adjust CommentsClient Tests --- Test/Notion.IntegrationTests/CommentsClientTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/Notion.IntegrationTests/CommentsClientTests.cs b/Test/Notion.IntegrationTests/CommentsClientTests.cs index f2a84d21..0eb56bea 100644 --- a/Test/Notion.IntegrationTests/CommentsClientTests.cs +++ b/Test/Notion.IntegrationTests/CommentsClientTests.cs @@ -78,7 +78,7 @@ public async Task ShouldCreateADiscussionComment() ); // Arrange - Assert.Null(response.Parent); + Assert.NotNull(response.Parent); Assert.NotNull(response.Id); Assert.Equal(comment.DiscussionId, response.DiscussionId); From 8a0d469febfec2b521808ee4b9171b150ef775ed Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 02:44:34 +0530 Subject: [PATCH 34/89] Adjust PageClient tests --- ...IPageClientTests.cs => PageClientTests.cs} | 157 +++++++++++------- 1 file changed, 100 insertions(+), 57 deletions(-) rename Test/Notion.IntegrationTests/{IPageClientTests.cs => PageClientTests.cs} (71%) diff --git a/Test/Notion.IntegrationTests/IPageClientTests.cs b/Test/Notion.IntegrationTests/PageClientTests.cs similarity index 71% rename from Test/Notion.IntegrationTests/IPageClientTests.cs rename to Test/Notion.IntegrationTests/PageClientTests.cs index 84ac493e..1e697c59 100644 --- a/Test/Notion.IntegrationTests/IPageClientTests.cs +++ b/Test/Notion.IntegrationTests/PageClientTests.cs @@ -8,13 +8,69 @@ namespace Notion.IntegrationTests; -public class IPageClientTests : IntegrationTestBase +public class PageClientTests : IntegrationTestBase, IDisposable { + private readonly Page _page; + private readonly Database _database; + + public PageClientTests() + { + // Create a page + _page = Client.Pages.CreateAsync( + PagesCreateParametersBuilder.Create( + new ParentPageInput { PageId = ParentPageId } + ).Build() + ).Result; + + // Create a database + var createDbRequest = new DatabasesCreateParameters + { + Title = new List + { + new RichTextTextInput + { + Text = new Text + { + Content = "Test List", + Link = null + } + } + }, + Properties = new Dictionary + { + { "Name", new TitlePropertySchema { Title = new Dictionary() } }, + { + "TestSelect", + new SelectPropertySchema + { + Select = new OptionWrapper + { + Options = new List + { + new() { Name = "Red" }, + new() { Name = "Blue" } + } + } + } + }, + { "Number", new NumberPropertySchema { Number = new Number { Format = "number" } } } + }, + Parent = new ParentPageInput { PageId = _page.Id } + }; + + _database = Client.Databases.CreateAsync(createDbRequest).GetAwaiter().GetResult(); + } + + public void Dispose() + { + Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }).GetAwaiter().GetResult(); + } + [Fact] public async Task CreateAsync_CreatesANewPage() { var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = ParentDatabaseId }) + .Create(new DatabaseParentInput { DatabaseId = _database.Id }) .AddProperty("Name", new TitlePropertyValue { @@ -30,10 +86,10 @@ public async Task CreateAsync_CreatesANewPage() page.Should().NotBeNull(); page.Parent.Should().BeOfType().Which - .DatabaseId.Should().Be(ParentDatabaseId); + .DatabaseId.Should().Be(_database.Id); page.Properties.Should().ContainKey("Name"); - var pageProperty = page.Properties["Name"].Should().BeOfType().Subject; + var pageProperty = page.Properties["Name"].Should().BeOfType().Subject; var titleProperty = (ListPropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( @@ -44,15 +100,14 @@ var titleProperty }); titleProperty.Results.First().As().Title.PlainText.Should().Be("Test Page Title"); - - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); } [Fact] public async Task Bug_unable_to_create_page_with_select_property() { + // Arrange var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = ParentDatabaseId }) + .Create(new DatabaseParentInput { DatabaseId = _database.Id }) .AddProperty("Name", new TitlePropertyValue { @@ -62,37 +117,33 @@ public async Task Bug_unable_to_create_page_with_select_property() } }) .AddProperty("TestSelect", - new SelectPropertyValue { Select = new SelectOption { Id = "dfbfbe65-6f67-4876-9f75-699124334d06" } }) + new SelectPropertyValue { Select = new SelectOption { Name = "Blue" } }) .Build(); + // Act var page = await Client.Pages.CreateAsync(pagesCreateParameters); + // Asserts page.Should().NotBeNull(); page.Parent.Should().BeOfType().Which - .DatabaseId.Should().Be(ParentDatabaseId); + .DatabaseId.Should().Be(_database.Id); page.Properties.Should().ContainKey("Name"); - var pageProperty = page.Properties["Name"].Should().BeOfType().Subject; - - var titleProperty - = (ListPropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( - new RetrievePropertyItemParameters - { - PageId = page.Id, - PropertyId = pageProperty.Id - }); - - titleProperty.Results.First().As().Title.PlainText.Should().Be("Test Page Title"); + var titlePropertyValue = page.Properties["Name"].Should().BeOfType().Subject; + titlePropertyValue.Title.First().PlainText.Should().Be("Test Page Title"); - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); + page.Properties.Should().ContainKey("TestSelect"); + var selectPropertyValue = page.Properties["TestSelect"].Should().BeOfType().Subject; + selectPropertyValue.Select.Name.Should().Be("Blue"); } [Fact] public async Task Test_RetrievePagePropertyItemAsync() { + // Arrange var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = ParentDatabaseId }) + .Create(new DatabaseParentInput { DatabaseId = _database.Id }) .AddProperty("Name", new TitlePropertyValue { @@ -105,12 +156,14 @@ public async Task Test_RetrievePagePropertyItemAsync() var page = await Client.Pages.CreateAsync(pagesCreateParameters); + // Act var property = await Client.Pages.RetrievePagePropertyItemAsync(new RetrievePropertyItemParameters { PageId = page.Id, PropertyId = "title" }); + // Assert property.Should().NotBeNull(); property.Should().BeOfType(); @@ -125,16 +178,14 @@ public async Task Test_RetrievePagePropertyItemAsync() titleProperty.Title.PlainText.Should().Be("Test Page Title"); }); - - // cleanup - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); } [Fact] public async Task Test_UpdatePageProperty_with_date_as_null() { - // setup - add property to db and create a page with the property having a date + // Arrange + // Add property Date property to database const string DatePropertyName = "Test Date Property"; var updateDatabaseParameters = new DatabasesUpdateParameters @@ -149,8 +200,9 @@ public async Task Test_UpdatePageProperty_with_date_as_null() } }; + // Create a page with the property having a date var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = ParentDatabaseId }) + .Create(new DatabaseParentInput { DatabaseId = _database.Id }) .AddProperty("Name", new TitlePropertyValue { @@ -170,10 +222,11 @@ public async Task Test_UpdatePageProperty_with_date_as_null() }) .Build(); - await Client.Databases.UpdateAsync(ParentDatabaseId, updateDatabaseParameters); + await Client.Databases.UpdateAsync(_database.Id, updateDatabaseParameters); var page = await Client.Pages.CreateAsync(pagesCreateParameters); + // Act var setDate = (DatePropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( new RetrievePropertyItemParameters { @@ -182,27 +235,28 @@ public async Task Test_UpdatePageProperty_with_date_as_null() } ); + // Assert setDate?.Date?.Start.Should().Be(Convert.ToDateTime("2020-12-08T12:00:00Z")); - // verify - IDictionary testProps = new Dictionary(); - - testProps.Add(DatePropertyName, new DatePropertyValue { Date = null }); + var pageUpdateParameters = new PagesUpdateParameters + { + Properties = new Dictionary + { + { DatePropertyName, new DatePropertyValue { Date = null } } + } + }; - var updatedPage = - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Properties = testProps }); + var updatedPage = await Client.Pages.UpdateAsync(page.Id, pageUpdateParameters); var verifyDate = (DatePropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( new RetrievePropertyItemParameters { PageId = page.Id, PropertyId = updatedPage.Properties[DatePropertyName].Id - }); + } + ); verifyDate?.Date.Should().BeNull(); - - //cleanup - await Client.Blocks.DeleteAsync(page.Id); } [Fact] @@ -210,14 +264,16 @@ public async Task Bug_Unable_To_Parse_NumberPropertyItem() { // Arrange var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = ParentDatabaseId }).AddProperty("Name", + .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .AddProperty("Name", new TitlePropertyValue { Title = new List { new RichTextText { Text = new Text { Content = "Test Page Title" } } } - }).AddProperty("Number", new NumberPropertyValue { Number = 200.00 }).Build(); + }) + .AddProperty("Number", new NumberPropertyValue { Number = 200.00 }).Build(); // Act var page = await Client.Pages.CreateAsync(pagesCreateParameters); @@ -225,7 +281,7 @@ public async Task Bug_Unable_To_Parse_NumberPropertyItem() // Assert Assert.NotNull(page); var pageParent = Assert.IsType(page.Parent); - Assert.Equal(ParentDatabaseId, pageParent.DatabaseId); + Assert.Equal(_database.Id, pageParent.DatabaseId); var titleProperty = (ListPropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( new RetrievePropertyItemParameters @@ -244,8 +300,6 @@ public async Task Bug_Unable_To_Parse_NumberPropertyItem() }); Assert.Equal(200.00, numberProperty.Number); - - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); } [Fact] @@ -255,19 +309,11 @@ public async Task Bug_exception_when_attempting_to_set_select_property_to_nothin var databaseCreateRequest = new DatabasesCreateParameters { Title = - new List - { - new RichTextTextInput() { Text = new Text { Content = "Test Database" } } - }, - Parent = new ParentPageInput() { PageId = ParentPageId }, + new List { new RichTextTextInput { Text = new Text { Content = "Test Database" } } }, + Parent = new ParentPageInput() { PageId = _page.Id }, Properties = new Dictionary { - { - "title", new TitlePropertySchema - { - Title = new Dictionary() - } - }, + { "title", new TitlePropertySchema { Title = new Dictionary() } }, { "Colors1", new SelectPropertySchema @@ -337,8 +383,5 @@ public async Task Bug_exception_when_attempting_to_set_select_property_to_nothin updatedPage.Properties["Colors1"].As().Select.Name.Should().Be("Blue"); updatedPage.Properties["Colors2"].As().Select.Should().BeNull(); - - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); - await Client.Databases.UpdateAsync(database.Id, new DatabasesUpdateParameters { Archived = true }); } } From 0813c026ae7b126ee24632e34e5a789efefa090b Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 02:52:58 +0530 Subject: [PATCH 35/89] Make use of IAsyncDisposable in PageWithPageParent test --- .../PageWithPageParentTests.cs | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Test/Notion.IntegrationTests/PageWithPageParentTests.cs b/Test/Notion.IntegrationTests/PageWithPageParentTests.cs index cca3356b..3d31e94d 100644 --- a/Test/Notion.IntegrationTests/PageWithPageParentTests.cs +++ b/Test/Notion.IntegrationTests/PageWithPageParentTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using FluentAssertions; @@ -7,12 +8,12 @@ namespace Notion.IntegrationTests; -public class PageWithPageParentTests : IntegrationTestBase +public class PageWithPageParentTests : IntegrationTestBase, IAsyncDisposable { - [Fact] - public async Task Update_Title_Of_Page() + private readonly Page _page; + + public PageWithPageParentTests() { - // Arrange var pagesCreateParameters = PagesCreateParametersBuilder .Create(new ParentPageInput() { PageId = ParentPageId }) .AddProperty("title", @@ -24,8 +25,13 @@ public async Task Update_Title_Of_Page() } }).Build(); - var page = await Client.Pages.CreateAsync(pagesCreateParameters); + _page = Client.Pages.CreateAsync(pagesCreateParameters).GetAwaiter().GetResult(); + } + [Fact] + public async Task Update_Title_Of_Page() + { + // Arrange var updatePage = new PagesUpdateParameters() { Properties = new Dictionary @@ -44,7 +50,7 @@ public async Task Update_Title_Of_Page() }; // Act - var updatedPage = await Client.Pages.UpdateAsync(page.Id, updatePage); + var updatedPage = await Client.Pages.UpdateAsync(_page.Id, updatePage); // Assert var titleProperty = (ListPropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( @@ -55,9 +61,11 @@ public async Task Update_Title_Of_Page() } ); - Assert.Equal("Page Title Updated", titleProperty.Results.First().As().Title.PlainText); + titleProperty.Results.First().As().Title.PlainText.Should().Be("Page Title Updated"); + } - // Clean Up - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); + public async ValueTask DisposeAsync() + { + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); } } From 66d75a4fa8bff78b5e4b67a4e4a6a699ef18c7ae Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 03:01:19 +0530 Subject: [PATCH 36/89] User IAsyncDisposable in PageClient tests --- Test/Notion.IntegrationTests/PageClientTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Test/Notion.IntegrationTests/PageClientTests.cs b/Test/Notion.IntegrationTests/PageClientTests.cs index 1e697c59..d2843dc4 100644 --- a/Test/Notion.IntegrationTests/PageClientTests.cs +++ b/Test/Notion.IntegrationTests/PageClientTests.cs @@ -8,7 +8,7 @@ namespace Notion.IntegrationTests; -public class PageClientTests : IntegrationTestBase, IDisposable +public class PageClientTests : IntegrationTestBase, IAsyncDisposable { private readonly Page _page; private readonly Database _database; @@ -20,7 +20,7 @@ public PageClientTests() PagesCreateParametersBuilder.Create( new ParentPageInput { PageId = ParentPageId } ).Build() - ).Result; + ).GetAwaiter().GetResult(); // Create a database var createDbRequest = new DatabasesCreateParameters @@ -61,9 +61,9 @@ public PageClientTests() _database = Client.Databases.CreateAsync(createDbRequest).GetAwaiter().GetResult(); } - public void Dispose() + public async ValueTask DisposeAsync() { - Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }).GetAwaiter().GetResult(); + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); } [Fact] From 5231ed1c40c21f43aa89ce0b43b7262e3d7d9c0f Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 03:03:07 +0530 Subject: [PATCH 37/89] Use IAsyncDisposable in Comments client tests --- Test/Notion.IntegrationTests/CommentsClientTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Test/Notion.IntegrationTests/CommentsClientTests.cs b/Test/Notion.IntegrationTests/CommentsClientTests.cs index 0eb56bea..5a6de044 100644 --- a/Test/Notion.IntegrationTests/CommentsClientTests.cs +++ b/Test/Notion.IntegrationTests/CommentsClientTests.cs @@ -7,7 +7,7 @@ namespace Notion.IntegrationTests; -public class CommentsClientTests : IntegrationTestBase, IDisposable +public class CommentsClientTests : IntegrationTestBase, IAsyncDisposable { private readonly Page _page; @@ -17,12 +17,12 @@ public CommentsClientTests() PagesCreateParametersBuilder.Create( new ParentPageInput { PageId = ParentPageId } ).Build() - ).Result; + ).GetAwaiter().GetResult(); } - public void Dispose() + public async ValueTask DisposeAsync() { - Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }).Wait(); + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); } [Fact] From f5db1489c22e846d606775270dbcd3ffb7feb8ac Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 03:09:00 +0530 Subject: [PATCH 38/89] Use IAsyncDisposable in Databases Client tests * use fluent assertions --- .../DatabasesClientTests.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs index e2255339..cbdfb652 100644 --- a/Test/Notion.IntegrationTests/DatabasesClientTests.cs +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -2,12 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using FluentAssertions; using Notion.Client; using Xunit; namespace Notion.IntegrationTests; -public class DatabasesClientTests : IntegrationTestBase, IDisposable +public class DatabasesClientTests : IntegrationTestBase, IAsyncDisposable { private readonly Page _page; @@ -17,12 +18,12 @@ public DatabasesClientTests() PagesCreateParametersBuilder.Create( new ParentPageInput { PageId = ParentPageId } ).Build() - ).Result; + ).GetAwaiter().GetResult(); } - public void Dispose() + public async ValueTask DisposeAsync() { - Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }).Wait(); + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); } [Fact] @@ -35,11 +36,12 @@ public async Task QueryDatabase() var response = await Client.Databases.QueryAsync(createdDatabase.Id, new DatabasesQueryParameters()); // Assert - Assert.NotNull(response.Results); - Assert.Single(response.Results); - var page = response.Results.Cast().First(); - var title = page.Properties["Name"] as TitlePropertyValue; - Assert.Equal("Test Title", (title!.Title.Cast().First()).Text.Content); + response.Results.Should().NotBeNull(); + var page = response.Results.Should().ContainSingle().Subject.As(); + + page.Properties["Name"].As() + .Title.Cast().First() + .Text.Content.Should().Be("Test Title"); } private async Task CreateDatabaseWithAPageAsync() From 50a7b66a51edf6aefd48d47fdb4a844974c1116c Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 04:21:19 +0530 Subject: [PATCH 39/89] Adjust Breaking BlocksClients tests --- ...cksClientTests.cs => BlocksClientTests.cs} | 58 +++---------------- 1 file changed, 7 insertions(+), 51 deletions(-) rename Test/Notion.IntegrationTests/{IBlocksClientTests.cs => BlocksClientTests.cs} (89%) diff --git a/Test/Notion.IntegrationTests/IBlocksClientTests.cs b/Test/Notion.IntegrationTests/BlocksClientTests.cs similarity index 89% rename from Test/Notion.IntegrationTests/IBlocksClientTests.cs rename to Test/Notion.IntegrationTests/BlocksClientTests.cs index 24e28da7..9b09ec3f 100644 --- a/Test/Notion.IntegrationTests/IBlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/BlocksClientTests.cs @@ -188,12 +188,13 @@ private static IEnumerable BlockData() }, new object[] { - new DividerBlock { Divider = new DividerBlock.Data() }, new DividerUpdateBlock(), new Action( - block => - { - Assert.NotNull(block); - _ = Assert.IsType(block); - }) + new DividerBlock { Divider = new DividerBlock.Data() }, + new DividerUpdateBlock(), + new Action((block, client) => + { + Assert.NotNull(block); + _ = Assert.IsType(block); + }) }, new object[] { @@ -354,51 +355,6 @@ private static IEnumerable BlockData() }) }, new object[] - { - new TemplateBlock - { - Template = new TemplateBlock.Data - { - RichText = new List - { - new RichTextText { Text = new Text { Content = "Test Template" } } - }, - Children = new List - { - new EmbedBlock - { - Embed = new EmbedBlock.Info - { - Url - = "https://zephoria.com/wp-content/uploads/2014/08/online-community.jpg" - } - } - } - } - }, - new TemplateUpdateBlock - { - Template = new TemplateUpdateBlock.Info - { - RichText = new List - { - new RichTextTextInput { Text = new Text { Content = "Test Template 2" } } - } - } - }, - new Action((block, client) => - { - Assert.NotNull(block); - var templateBlock = Assert.IsType(block); - - Assert.Single(templateBlock.Template.RichText); - Assert.Null(templateBlock.Template.Children); - - Assert.Equal("Test Template 2", - templateBlock.Template.RichText.OfType().First().Text.Content); - }) - }, - new object[] { new LinkToPageBlock { From 3b4324befb554d858383e102fde4b4e0f0f905d7 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 04:28:20 +0530 Subject: [PATCH 40/89] Use IAsyncLifetime to initialize and cleanup common resources --- .../BlocksClientTests.cs | 81 +++++++------------ 1 file changed, 29 insertions(+), 52 deletions(-) diff --git a/Test/Notion.IntegrationTests/BlocksClientTests.cs b/Test/Notion.IntegrationTests/BlocksClientTests.cs index 9b09ec3f..71d853b6 100644 --- a/Test/Notion.IntegrationTests/BlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/BlocksClientTests.cs @@ -8,21 +8,31 @@ namespace Notion.IntegrationTests; -public class IBlocksClientTests : IntegrationTestBase +public class IBlocksClientTests : IntegrationTestBase, IAsyncLifetime { - [Fact] - public async Task AppendChildrenAsync_AppendsBlocksGivenBlocks() + private Page _page = null!; + + public async Task InitializeAsync() { - var page = await Client.Pages.CreateAsync( + _page = await Client.Pages.CreateAsync( PagesCreateParametersBuilder.Create( new ParentPageInput { PageId = ParentPageId } ).Build() ); + } + public async Task DisposeAsync() + { + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); + } + + [Fact] + public async Task AppendChildrenAsync_AppendsBlocksGivenBlocks() + { var blocks = await Client.Blocks.AppendChildrenAsync( new BlockAppendChildrenRequest { - BlockId = page.Id, + BlockId = _page.Id, Children = new List { new BreadcrumbBlock { Breadcrumb = new BreadcrumbBlock.Data() }, @@ -43,24 +53,15 @@ public async Task AppendChildrenAsync_AppendsBlocksGivenBlocks() ); blocks.Results.Should().HaveCount(4); - - // cleanup - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); } [Fact] public async Task UpdateBlockAsync_UpdatesGivenBlock() { - var page = await Client.Pages.CreateAsync( - PagesCreateParametersBuilder.Create( - new ParentPageInput { PageId = ParentPageId } - ).Build() - ); - var blocks = await Client.Blocks.AppendChildrenAsync( new BlockAppendChildrenRequest { - BlockId = page.Id, + BlockId = _page.Id, Children = new List { new BreadcrumbBlock { Breadcrumb = new BreadcrumbBlock.Data() } } } ); @@ -68,29 +69,19 @@ public async Task UpdateBlockAsync_UpdatesGivenBlock() var blockId = blocks.Results.First().Id; await Client.Blocks.UpdateAsync(blockId, new BreadcrumbUpdateBlock()); - var updatedBlocks = await Client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest - { - BlockId = page.Id - }); - updatedBlocks.Results.Should().HaveCount(1); + var updatedBlocks = + await Client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest { BlockId = _page.Id }); - // cleanup - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); + updatedBlocks.Results.Should().HaveCount(1); } [Fact] public async Task DeleteAsync_DeleteBlockWithGivenId() { - var page = await Client.Pages.CreateAsync( - PagesCreateParametersBuilder.Create( - new ParentPageInput { PageId = ParentPageId } - ).Build() - ); - var blocks = await Client.Blocks.AppendChildrenAsync( new BlockAppendChildrenRequest { - BlockId = page.Id, + BlockId = _page.Id, Children = new List { new DividerBlock { Divider = new DividerBlock.Data() }, @@ -100,9 +91,6 @@ public async Task DeleteAsync_DeleteBlockWithGivenId() ); blocks.Results.Should().HaveCount(2); - - // cleanup - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); } [Theory] @@ -110,16 +98,10 @@ public async Task DeleteAsync_DeleteBlockWithGivenId() public async Task UpdateAsync_UpdatesGivenBlock( IBlock block, IUpdateBlock updateBlock, Action assert) { - var page = await Client.Pages.CreateAsync( - PagesCreateParametersBuilder.Create( - new ParentPageInput { PageId = ParentPageId } - ).Build() - ); - var blocks = await Client.Blocks.AppendChildrenAsync( new BlockAppendChildrenRequest { - BlockId = page.Id, + BlockId = _page.Id, Children = new List { block } } ); @@ -127,18 +109,14 @@ public async Task UpdateAsync_UpdatesGivenBlock( var blockId = blocks.Results.First().Id; await Client.Blocks.UpdateAsync(blockId, updateBlock); - var updatedBlocks = await Client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest - { - BlockId = page.Id - }); + var updatedBlocks = + await Client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest { BlockId = _page.Id }); + updatedBlocks.Results.Should().HaveCount(1); var updatedBlock = updatedBlocks.Results.First(); assert.Invoke(updatedBlock, Client); - - // cleanup - await Client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters { Archived = true }); } private static IEnumerable BlockData() @@ -188,8 +166,7 @@ private static IEnumerable BlockData() }, new object[] { - new DividerBlock { Divider = new DividerBlock.Data() }, - new DividerUpdateBlock(), + new DividerBlock { Divider = new DividerBlock.Data() }, new DividerUpdateBlock(), new Action((block, client) => { Assert.NotNull(block); @@ -374,7 +351,7 @@ private static IEnumerable BlockData() var linkToPageBlock = Assert.IsType(block); var pageParent = Assert.IsType(linkToPageBlock.LinkToPage); - + // TODO: Currently the api doesn't allow to update the link_to_page block type // This will change to updated ID once api start to support Assert.Equal(Guid.Parse("533578e3edf14c0a91a9da6b09bac3ee"), Guid.Parse(pageParent.PageId)); @@ -408,9 +385,9 @@ private static IEnumerable BlockData() var tableBlock = block.Should().NotBeNull().And.BeOfType().Subject; tableBlock.HasChildren.Should().BeTrue(); - var children = client.Blocks.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest{ - BlockId = tableBlock.Id - }).GetAwaiter().GetResult(); + var children = client.Blocks + .RetrieveChildrenAsync(new BlockRetrieveChildrenRequest { BlockId = tableBlock.Id }) + .GetAwaiter().GetResult(); children.Results.Should().ContainSingle() .Subject.Should().BeOfType() From c79531a165be24a7400c2ca74ec28506f6361a79 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 04:30:48 +0530 Subject: [PATCH 41/89] Discard unused lambda args --- .../Notion.IntegrationTests/BlocksClientTests.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Test/Notion.IntegrationTests/BlocksClientTests.cs b/Test/Notion.IntegrationTests/BlocksClientTests.cs index 71d853b6..4db78d85 100644 --- a/Test/Notion.IntegrationTests/BlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/BlocksClientTests.cs @@ -147,7 +147,7 @@ private static IEnumerable BlockData() } } }, - new Action((block, client) => + new Action((block, _) => { var updatedBlock = (BookmarkBlock)block; Assert.Equal("https://github.com/notion-dotnet/notion-sdk-net", updatedBlock.Bookmark.Url); @@ -158,7 +158,7 @@ private static IEnumerable BlockData() { new EquationBlock { Equation = new EquationBlock.Info { Expression = "e=mc^3" } }, new EquationUpdateBlock { Equation = new EquationUpdateBlock.Info { Expression = "e=mc^2" } }, - new Action((block, client) => + new Action((block, _) => { var updatedBlock = (EquationBlock)block; Assert.Equal("e=mc^2", updatedBlock.Equation.Expression); @@ -195,7 +195,7 @@ private static IEnumerable BlockData() } } }, - new Action((block, client) => + new Action((block, _) => { block.Should().NotBeNull(); @@ -235,7 +235,7 @@ private static IEnumerable BlockData() } } }, - new Action((block, client) => + new Action((block, _) => { Assert.NotNull(block); var calloutBlock = Assert.IsType(block); @@ -265,7 +265,7 @@ private static IEnumerable BlockData() } } }, - new Action((block, client) => + new Action((block, _) => { Assert.NotNull(block); var quoteBlock = Assert.IsType(block); @@ -296,7 +296,7 @@ private static IEnumerable BlockData() } } }, - new Action((block, client) => + new Action((block, _) => { Assert.NotNull(block); var imageBlock = Assert.IsType(block); @@ -322,7 +322,7 @@ private static IEnumerable BlockData() Url = "https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg" } }, - new Action((block, client) => + new Action((block, _) => { Assert.NotNull(block); var embedBlock = Assert.IsType(block); @@ -345,7 +345,7 @@ private static IEnumerable BlockData() { LinkToPage = new ParentPageInput { PageId = "3c357473a28149a488c010d2b245a589" } }, - new Action((block, client) => + new Action((block, _) => { Assert.NotNull(block); var linkToPageBlock = Assert.IsType(block); From 88135e48942a9c7b0fabbc1366666785933acaaa Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 04:33:02 +0530 Subject: [PATCH 42/89] Use IAsyncLifetime in CommentsClient Tests --- .../CommentsClientTests.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Test/Notion.IntegrationTests/CommentsClientTests.cs b/Test/Notion.IntegrationTests/CommentsClientTests.cs index 5a6de044..1655fc71 100644 --- a/Test/Notion.IntegrationTests/CommentsClientTests.cs +++ b/Test/Notion.IntegrationTests/CommentsClientTests.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Notion.Client; @@ -7,20 +6,20 @@ namespace Notion.IntegrationTests; -public class CommentsClientTests : IntegrationTestBase, IAsyncDisposable +public class CommentsClientTests : IntegrationTestBase, IAsyncLifetime { - private readonly Page _page; + private Page _page = null!; - public CommentsClientTests() + public async Task InitializeAsync() { - _page = Client.Pages.CreateAsync( + _page = await Client.Pages.CreateAsync( PagesCreateParametersBuilder.Create( new ParentPageInput { PageId = ParentPageId } ).Build() - ).GetAwaiter().GetResult(); + ); } - public async ValueTask DisposeAsync() + public async Task DisposeAsync() { await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); } From f6e8feb4c0e8c17ff134ecdf23d61dc0ff86abe7 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 04:34:38 +0530 Subject: [PATCH 43/89] User IAsyncLifeTIme in DatabasesClient tests --- .../DatabasesClientTests.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs index cbdfb652..c5c7082b 100644 --- a/Test/Notion.IntegrationTests/DatabasesClientTests.cs +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using FluentAssertions; @@ -8,20 +7,20 @@ namespace Notion.IntegrationTests; -public class DatabasesClientTests : IntegrationTestBase, IAsyncDisposable +public class DatabasesClientTests : IntegrationTestBase, IAsyncLifetime { - private readonly Page _page; + private Page _page = null!; - public DatabasesClientTests() + public async Task InitializeAsync() { - _page = Client.Pages.CreateAsync( + _page = await Client.Pages.CreateAsync( PagesCreateParametersBuilder.Create( new ParentPageInput { PageId = ParentPageId } ).Build() - ).GetAwaiter().GetResult(); + ); } - public async ValueTask DisposeAsync() + public async Task DisposeAsync() { await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); } From 889fa12412b52f158f342af7ef7499603753b42a Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 04:36:41 +0530 Subject: [PATCH 44/89] Use IAsyncLifetime in PageClient tests --- Test/Notion.IntegrationTests/PageClientTests.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Test/Notion.IntegrationTests/PageClientTests.cs b/Test/Notion.IntegrationTests/PageClientTests.cs index d2843dc4..2e4153eb 100644 --- a/Test/Notion.IntegrationTests/PageClientTests.cs +++ b/Test/Notion.IntegrationTests/PageClientTests.cs @@ -8,19 +8,19 @@ namespace Notion.IntegrationTests; -public class PageClientTests : IntegrationTestBase, IAsyncDisposable +public class PageClientTests : IntegrationTestBase, IAsyncLifetime { - private readonly Page _page; - private readonly Database _database; + private Page _page = null!; + private Database _database = null!; - public PageClientTests() + public async Task InitializeAsync() { // Create a page - _page = Client.Pages.CreateAsync( + _page = await Client.Pages.CreateAsync( PagesCreateParametersBuilder.Create( new ParentPageInput { PageId = ParentPageId } ).Build() - ).GetAwaiter().GetResult(); + ); // Create a database var createDbRequest = new DatabasesCreateParameters @@ -58,10 +58,10 @@ public PageClientTests() Parent = new ParentPageInput { PageId = _page.Id } }; - _database = Client.Databases.CreateAsync(createDbRequest).GetAwaiter().GetResult(); + _database = await Client.Databases.CreateAsync(createDbRequest); } - public async ValueTask DisposeAsync() + public async Task DisposeAsync() { await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); } From f1c0a228313131b4e963d18d8d6722248996bf77 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 04:38:26 +0530 Subject: [PATCH 45/89] User IAsyncLifetime in PageWithPageParent tests --- .../PageWithPageParentTests.cs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Test/Notion.IntegrationTests/PageWithPageParentTests.cs b/Test/Notion.IntegrationTests/PageWithPageParentTests.cs index 3d31e94d..5f398dc7 100644 --- a/Test/Notion.IntegrationTests/PageWithPageParentTests.cs +++ b/Test/Notion.IntegrationTests/PageWithPageParentTests.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using FluentAssertions; @@ -8,11 +7,11 @@ namespace Notion.IntegrationTests; -public class PageWithPageParentTests : IntegrationTestBase, IAsyncDisposable +public class PageWithPageParentTests : IntegrationTestBase, IAsyncLifetime { - private readonly Page _page; + private Page _page = null!; - public PageWithPageParentTests() + public async Task InitializeAsync() { var pagesCreateParameters = PagesCreateParametersBuilder .Create(new ParentPageInput() { PageId = ParentPageId }) @@ -25,7 +24,12 @@ public PageWithPageParentTests() } }).Build(); - _page = Client.Pages.CreateAsync(pagesCreateParameters).GetAwaiter().GetResult(); + _page = await Client.Pages.CreateAsync(pagesCreateParameters); + } + + public async Task DisposeAsync() + { + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); } [Fact] @@ -63,9 +67,4 @@ public async Task Update_Title_Of_Page() titleProperty.Results.First().As().Title.PlainText.Should().Be("Page Title Updated"); } - - public async ValueTask DisposeAsync() - { - await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); - } } From 8d574d66407f301c0f0c6dce72a5ca04c52969ff Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 01:43:23 +0530 Subject: [PATCH 46/89] Add Block object request models --- .../Blocks/Request/AudioBlockRequest.cs | 12 +++++++ .../Blocks/Request/BlockObjectRequest.cs | 28 +++++++++++++++++ .../Blocks/Request/BookmarkBlockRequest.cs | 22 +++++++++++++ .../Blocks/Request/BreadcrumbBlockRequest.cs | 16 ++++++++++ .../Request/BulletedListItemBlockRequest.cs | 27 ++++++++++++++++ .../Blocks/Request/CalloutBlockRequest.cs | 30 ++++++++++++++++++ .../Request/ChildDatabaseBlockRequest.cs | 18 +++++++++++ .../Blocks/Request/ChildPageBlockRequest.cs | 18 +++++++++++ .../Models/Blocks/Request/CodeBlockRequest.cs | 25 +++++++++++++++ .../Blocks/Request/ColumnBlockRequest.cs | 19 ++++++++++++ .../Blocks/Request/ColumnListBlockRequest.cs | 19 ++++++++++++ .../Blocks/Request/DividerBlockRequest.cs | 16 ++++++++++ .../Blocks/Request/EmbedBlockRequest.cs | 22 +++++++++++++ .../Blocks/Request/EquationBlockRequest.cs | 18 +++++++++++ .../Models/Blocks/Request/FileBlockRequest.cs | 12 +++++++ .../Blocks/Request/HeadingOneBlockRequest.cs | 29 +++++++++++++++++ .../Request/HeadingThreeBlockRequest.cs | 29 +++++++++++++++++ .../Blocks/Request/HeadingTwoBlockRequest.cs | 29 +++++++++++++++++ .../Blocks/Request/IBlockObjectRequest.cs | 19 ++++++++++++ .../Request/IColumnChildrenBlockRequest.cs | 18 +++++++++++ .../Blocks/Request/ImageBlockRequest.cs | 12 +++++++ .../Blocks/Request/LinkPreviewBlockRequest.cs | 18 +++++++++++ .../Blocks/Request/LinkToPageBlockRequest.cs | 12 +++++++ .../Request/NumberedListItemBlockRequest.cs | 27 ++++++++++++++++ .../Models/Blocks/Request/PDFBlockRequest.cs | 14 +++++++++ .../Blocks/Request/ParagraphBlockRequest.cs | 27 ++++++++++++++++ .../Blocks/Request/QuoteBlockRequest.cs | 27 ++++++++++++++++ .../Blocks/Request/SyncedBlockBlockRequest.cs | 31 +++++++++++++++++++ .../Blocks/Request/TableBlockRequest.cs | 28 +++++++++++++++++ .../Request/TableOfContentsBlockRequest.cs | 20 ++++++++++++ .../Blocks/Request/TableRowBlockRequest.cs | 19 ++++++++++++ .../Blocks/Request/TemplateBlockRequest.cs | 22 +++++++++++++ .../Models/Blocks/Request/ToDoBlockRequest.cs | 30 ++++++++++++++++++ .../Blocks/Request/ToggleBlockRequest.cs | 27 ++++++++++++++++ .../Blocks/Request/VideoBlockRequest.cs | 12 +++++++ 35 files changed, 752 insertions(+) create mode 100644 Src/Notion.Client/Models/Blocks/Request/AudioBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/BlockObjectRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/BookmarkBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/BreadcrumbBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/BulletedListItemBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/CalloutBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/ChildDatabaseBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/ChildPageBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/CodeBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/ColumnBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/ColumnListBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/DividerBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/EmbedBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/EquationBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/FileBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/HeadingOneBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/HeadingThreeBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/HeadingTwoBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/IBlockObjectRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/IColumnChildrenBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/ImageBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/LinkPreviewBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/LinkToPageBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/NumberedListItemBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/PDFBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/ParagraphBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/QuoteBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/SyncedBlockBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/TableBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/TableOfContentsBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/TableRowBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/TemplateBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/ToDoBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/ToggleBlockRequest.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/VideoBlockRequest.cs diff --git a/Src/Notion.Client/Models/Blocks/Request/AudioBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/AudioBlockRequest.cs new file mode 100644 index 00000000..8378574e --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/AudioBlockRequest.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class AudioBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("audio")] + public FileObject Audio { get; set; } + + public override BlockType Type => BlockType.Audio; + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/BlockObjectRequest.cs b/Src/Notion.Client/Models/Blocks/Request/BlockObjectRequest.cs new file mode 100644 index 00000000..a3eb3182 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/BlockObjectRequest.cs @@ -0,0 +1,28 @@ +using System; + +namespace Notion.Client +{ + public abstract class BlockObjectRequest : IBlockObjectRequest + { + public ObjectType Object => ObjectType.Block; + + public string Id { get; set; } + + public virtual BlockType Type { get; set; } + + public DateTime CreatedTime { get; set; } + + public DateTime LastEditedTime { get; set; } + + public virtual bool HasChildren { get; set; } + + public PartialUser CreatedBy { get; set; } + + public PartialUser LastEditedBy { get; set; } + + /// + /// Information about the block's parent. + /// + public IBlockParent Parent { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/BookmarkBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/BookmarkBlockRequest.cs new file mode 100644 index 00000000..0c7c0be2 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/BookmarkBlockRequest.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class BookmarkBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("bookmark")] + public Info Bookmark { get; set; } + + public override BlockType Type => BlockType.Bookmark; + + public class Info + { + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("caption")] + public IEnumerable Caption { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/BreadcrumbBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/BreadcrumbBlockRequest.cs new file mode 100644 index 00000000..f6039456 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/BreadcrumbBlockRequest.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class BreadcrumbBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("breadcrumb")] + public Data Breadcrumb { get; set; } + + public override BlockType Type => BlockType.Breadcrumb; + + public class Data + { + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/BulletedListItemBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/BulletedListItemBlockRequest.cs new file mode 100644 index 00000000..0aa8a183 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/BulletedListItemBlockRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class BulletedListItemBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("bulleted_list_item")] + public Info BulletedListItem { get; set; } + + public override BlockType Type => BlockType.BulletedListItem; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/CalloutBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/CalloutBlockRequest.cs new file mode 100644 index 00000000..b8a56823 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/CalloutBlockRequest.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class CalloutBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("callout")] + public Info Callout { get; set; } + + public override BlockType Type => BlockType.Callout; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("icon")] + public IPageIcon Icon { get; set; } + + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/ChildDatabaseBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/ChildDatabaseBlockRequest.cs new file mode 100644 index 00000000..34ff9387 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/ChildDatabaseBlockRequest.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ChildDatabaseBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("child_database")] + public Info ChildDatabase { get; set; } + + public override BlockType Type => BlockType.ChildDatabase; + + public class Info + { + [JsonProperty("title")] + public string Title { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/ChildPageBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/ChildPageBlockRequest.cs new file mode 100644 index 00000000..43213b77 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/ChildPageBlockRequest.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ChildPageBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("child_page")] + public Info ChildPage { get; set; } + + public override BlockType Type => BlockType.ChildPage; + + public class Info + { + [JsonProperty("title")] + public string Title { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/CodeBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/CodeBlockRequest.cs new file mode 100644 index 00000000..732e3208 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/CodeBlockRequest.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CodeBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("code")] + public Info Code { get; set; } + + public override BlockType Type => BlockType.Code; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("language")] + public string Language { get; set; } + + [JsonProperty("caption")] + public IEnumerable Caption { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/ColumnBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/ColumnBlockRequest.cs new file mode 100644 index 00000000..c4136294 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/ColumnBlockRequest.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ColumnBlockRequest : BlockObjectRequest + { + public override BlockType Type => BlockType.Column; + + [JsonProperty("column")] + public Info Column { get; set; } + + public class Info + { + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/ColumnListBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/ColumnListBlockRequest.cs new file mode 100644 index 00000000..431acf8e --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/ColumnListBlockRequest.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ColumnListBlockRequest : BlockObjectRequest, INonColumnBlockRequest + { + [JsonProperty("column_list")] + public Info ColumnList { get; set; } + + public override BlockType Type => BlockType.ColumnList; + + public class Info + { + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/DividerBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/DividerBlockRequest.cs new file mode 100644 index 00000000..49c81059 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/DividerBlockRequest.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DividerBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("divider")] + public Data Divider { get; set; } + + public override BlockType Type => BlockType.Divider; + + public class Data + { + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/EmbedBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/EmbedBlockRequest.cs new file mode 100644 index 00000000..81cb2339 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/EmbedBlockRequest.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class EmbedBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("embed")] + public Info Embed { get; set; } + + public override BlockType Type => BlockType.Embed; + + public class Info + { + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("caption")] + public IEnumerable Caption { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/EquationBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/EquationBlockRequest.cs new file mode 100644 index 00000000..5c2ddb8a --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/EquationBlockRequest.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class EquationBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("equation")] + public Info Equation { get; set; } + + public override BlockType Type => BlockType.Equation; + + public class Info + { + [JsonProperty("expression")] + public string Expression { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/FileBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/FileBlockRequest.cs new file mode 100644 index 00000000..0539c41c --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/FileBlockRequest.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class FileBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("file")] + public FileObject File { get; set; } + + public override BlockType Type => BlockType.File; + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/HeadingOneBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/HeadingOneBlockRequest.cs new file mode 100644 index 00000000..dd91451a --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/HeadingOneBlockRequest.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class HeadingOneBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("heading_1")] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public Info Heading_1 { get; set; } + + public override BlockType Type => BlockType.Heading_1; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonProperty("is_toggleable")] + public bool IsToggleable { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/HeadingThreeBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/HeadingThreeBlockRequest.cs new file mode 100644 index 00000000..9b78c80e --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/HeadingThreeBlockRequest.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class HeadingThreeBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("heading_3")] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public Info Heading_3 { get; set; } + + public override BlockType Type => BlockType.Heading_3; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonProperty("is_toggleable")] + public bool IsToggleable { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/HeadingTwoBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/HeadingTwoBlockRequest.cs new file mode 100644 index 00000000..dfdeb9dd --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/HeadingTwoBlockRequest.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class HeadingTwoBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("heading_2")] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public Info Heading_2 { get; set; } + + public override BlockType Type => BlockType.Heading_2; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonProperty("is_toggleable")] + public bool IsToggleable { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/IBlockObjectRequest.cs b/Src/Notion.Client/Models/Blocks/Request/IBlockObjectRequest.cs new file mode 100644 index 00000000..b3fbaf55 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/IBlockObjectRequest.cs @@ -0,0 +1,19 @@ +using JsonSubTypes; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public interface IBlockObjectRequest : IObject, IObjectModificationData + { + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + BlockType Type { get; } + + [JsonProperty("has_children")] + bool HasChildren { get; set; } + + [JsonProperty("parent")] + IBlockParent Parent { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/IColumnChildrenBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/IColumnChildrenBlockRequest.cs new file mode 100644 index 00000000..54e08fab --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/IColumnChildrenBlockRequest.cs @@ -0,0 +1,18 @@ +namespace Notion.Client +{ + public interface ITemplateChildrenBlockRequest : IBlockObjectRequest + { + } + + public interface ISyncedBlockChildrenRequest : IBlockObjectRequest + { + } + + public interface IColumnChildrenBlockRequest : ITemplateChildrenBlockRequest, ISyncedBlockChildrenRequest + { + } + + public interface INonColumnBlockRequest : IBlockObjectRequest + { + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/ImageBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/ImageBlockRequest.cs new file mode 100644 index 00000000..d3ec252b --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/ImageBlockRequest.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ImageBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("image")] + public FileObject Image { get; set; } + + public override BlockType Type => BlockType.Image; + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/LinkPreviewBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/LinkPreviewBlockRequest.cs new file mode 100644 index 00000000..11a47592 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/LinkPreviewBlockRequest.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LinkPreviewBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("link_preview")] + public Data LinkPreview { get; set; } + + public override BlockType Type => BlockType.LinkPreview; + + public class Data + { + [JsonProperty("url")] + public string Url { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlockRequest.cs new file mode 100644 index 00000000..ec182df5 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlockRequest.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LinkToPageBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("link_to_page")] + public IPageParent LinkToPage { get; set; } + + public override BlockType Type => BlockType.LinkToPage; + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/NumberedListItemBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/NumberedListItemBlockRequest.cs new file mode 100644 index 00000000..87342c1d --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/NumberedListItemBlockRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class NumberedListItemBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("numbered_list_item")] + public Info NumberedListItem { get; set; } + + public override BlockType Type => BlockType.NumberedListItem; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/PDFBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/PDFBlockRequest.cs new file mode 100644 index 00000000..5590000d --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/PDFBlockRequest.cs @@ -0,0 +1,14 @@ +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; + +namespace Notion.Client +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public class PDFBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("pdf")] + public FileObject PDF { get; set; } + + public override BlockType Type => BlockType.PDF; + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/ParagraphBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/ParagraphBlockRequest.cs new file mode 100644 index 00000000..8e8dfa51 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/ParagraphBlockRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class ParagraphBlockRequest : Block, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("paragraph")] + public Info Paragraph { get; set; } + + public override BlockType Type => BlockType.Paragraph; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/QuoteBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/QuoteBlockRequest.cs new file mode 100644 index 00000000..3acd3130 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/QuoteBlockRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class QuoteBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("quote")] + public Info Quote { get; set; } + + public override BlockType Type => BlockType.Quote; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/SyncedBlockBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/SyncedBlockBlockRequest.cs new file mode 100644 index 00000000..5338e5bb --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/SyncedBlockBlockRequest.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class SyncedBlockBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("synced_block")] + public Data SyncedBlock { get; set; } + + public override BlockType Type => BlockType.SyncedBlock; + + public class Data + { + [JsonProperty("synced_from")] + public SyncedFromBlockId SyncedFrom { get; set; } + + [JsonProperty("children")] + public IEnumerable Children { get; set; } + + public class SyncedFromBlockId + { + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("block_id")] + public string BlockId { get; set; } + } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/TableBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/TableBlockRequest.cs new file mode 100644 index 00000000..1e966182 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/TableBlockRequest.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class TableBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("table")] + public Info Table { get; set; } + + public override BlockType Type => BlockType.Table; + + public class Info + { + [JsonProperty("table_width")] + public int TableWidth { get; set; } + + [JsonProperty("has_column_header")] + public bool HasColumnHeader { get; set; } + + [JsonProperty("has_row_header")] + public bool HasRowHeader { get; set; } + + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/TableOfContentsBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/TableOfContentsBlockRequest.cs new file mode 100644 index 00000000..2aef499d --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/TableOfContentsBlockRequest.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class TableOfContentsBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("table_of_contents")] + public Data TableOfContents { get; set; } + + public override BlockType Type => BlockType.TableOfContents; + + public class Data + { + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/TableRowBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/TableRowBlockRequest.cs new file mode 100644 index 00000000..ead85b33 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/TableRowBlockRequest.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class TableRowBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("table_row")] + public Info TableRow { get; set; } + + public override BlockType Type => BlockType.TableRow; + + public class Info + { + [JsonProperty("cells")] + public IEnumerable> Cells { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/TemplateBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/TemplateBlockRequest.cs new file mode 100644 index 00000000..04c161d2 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/TemplateBlockRequest.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class TemplateBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("template")] + public Data Template { get; set; } + + public override BlockType Type => BlockType.Template; + + public class Data + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/ToDoBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/ToDoBlockRequest.cs new file mode 100644 index 00000000..ed7b09c3 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/ToDoBlockRequest.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class ToDoBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("to_do")] + public Info ToDo { get; set; } + + public override BlockType Type => BlockType.ToDo; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("checked")] + public bool IsChecked { get; set; } + + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/ToggleBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/ToggleBlockRequest.cs new file mode 100644 index 00000000..fbbbcd37 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/ToggleBlockRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class ToggleBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("toggle")] + public Info Toggle { get; set; } + + public override BlockType Type => BlockType.Toggle; + + public class Info + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonProperty("children")] + public IEnumerable Children { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/VideoBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/VideoBlockRequest.cs new file mode 100644 index 00000000..238b2d26 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/VideoBlockRequest.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class VideoBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest + { + [JsonProperty("video")] + public FileObject Video { get; set; } + + public override BlockType Type => BlockType.Video; + } +} From f5f69be7cf24497ce59f8a166cb47d5a1543790f Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 15 Oct 2023 01:53:05 +0530 Subject: [PATCH 47/89] Use IBlockObjectRequest in Block Append Children api --- .../Request/BlockAppendChildrenRequest.cs | 2 +- .../IBlockAppendChildrenBodyParameters.cs | 5 +- .../BlocksClientTests.cs | 63 ++++++++++--------- Test/Notion.UnitTests/BlocksClientTests.cs | 10 +-- 4 files changed, 41 insertions(+), 39 deletions(-) diff --git a/Src/Notion.Client/Api/Blocks/AppendChildren/Request/BlockAppendChildrenRequest.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/BlockAppendChildrenRequest.cs index 580d164a..8a5a9cde 100644 --- a/Src/Notion.Client/Api/Blocks/AppendChildren/Request/BlockAppendChildrenRequest.cs +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/BlockAppendChildrenRequest.cs @@ -4,7 +4,7 @@ namespace Notion.Client { public class BlockAppendChildrenRequest : IBlockAppendChildrenBodyParameters, IBlockAppendChildrenPathParameters { - public IEnumerable Children { get; set; } + public IEnumerable Children { get; set; } public string After { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs index b476c089..ea6cef37 100644 --- a/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs @@ -3,11 +3,10 @@ namespace Notion.Client { - // TODO: need an input version of Block public interface IBlockAppendChildrenBodyParameters { [JsonProperty("children")] - IEnumerable Children { get; set; } + IEnumerable Children { get; set; } /// /// The ID of the existing block that the new block should be appended after. @@ -18,7 +17,7 @@ public interface IBlockAppendChildrenBodyParameters internal class BlockAppendChildrenBodyParameters : IBlockAppendChildrenBodyParameters { - public IEnumerable Children { get; set; } + public IEnumerable Children { get; set; } public string After { get; set; } diff --git a/Test/Notion.IntegrationTests/BlocksClientTests.cs b/Test/Notion.IntegrationTests/BlocksClientTests.cs index 4db78d85..284ac009 100644 --- a/Test/Notion.IntegrationTests/BlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/BlocksClientTests.cs @@ -33,14 +33,14 @@ public async Task AppendChildrenAsync_AppendsBlocksGivenBlocks() new BlockAppendChildrenRequest { BlockId = _page.Id, - Children = new List + Children = new List { - new BreadcrumbBlock { Breadcrumb = new BreadcrumbBlock.Data() }, - new DividerBlock { Divider = new DividerBlock.Data() }, - new TableOfContentsBlock { TableOfContents = new TableOfContentsBlock.Data() }, - new CalloutBlock + new BreadcrumbBlockRequest { Breadcrumb = new BreadcrumbBlockRequest.Data() }, + new DividerBlockRequest { Divider = new DividerBlockRequest.Data() }, + new TableOfContentsBlockRequest { TableOfContents = new TableOfContentsBlockRequest.Data() }, + new CalloutBlockRequest { - Callout = new CalloutBlock.Info + Callout = new CalloutBlockRequest.Info { RichText = new List { @@ -62,7 +62,10 @@ public async Task UpdateBlockAsync_UpdatesGivenBlock() new BlockAppendChildrenRequest { BlockId = _page.Id, - Children = new List { new BreadcrumbBlock { Breadcrumb = new BreadcrumbBlock.Data() } } + Children = new List + { + new BreadcrumbBlockRequest { Breadcrumb = new BreadcrumbBlockRequest.Data() } + } } ); @@ -82,10 +85,10 @@ public async Task DeleteAsync_DeleteBlockWithGivenId() new BlockAppendChildrenRequest { BlockId = _page.Id, - Children = new List + Children = new List { - new DividerBlock { Divider = new DividerBlock.Data() }, - new TableOfContentsBlock { TableOfContents = new TableOfContentsBlock.Data() } + new DividerBlockRequest { Divider = new DividerBlockRequest.Data() }, + new TableOfContentsBlockRequest { TableOfContents = new TableOfContentsBlockRequest.Data() } } } ); @@ -96,13 +99,13 @@ public async Task DeleteAsync_DeleteBlockWithGivenId() [Theory] [MemberData(nameof(BlockData))] public async Task UpdateAsync_UpdatesGivenBlock( - IBlock block, IUpdateBlock updateBlock, Action assert) + IBlockObjectRequest block, IUpdateBlock updateBlock, Action assert) { var blocks = await Client.Blocks.AppendChildrenAsync( new BlockAppendChildrenRequest { BlockId = _page.Id, - Children = new List { block } + Children = new List { block } } ); @@ -125,9 +128,9 @@ private static IEnumerable BlockData() { new object[] { - new BookmarkBlock + new BookmarkBlockRequest { - Bookmark = new BookmarkBlock.Info + Bookmark = new BookmarkBlockRequest.Info { Url = "https://developers.notion.com/reference/rich-text", Caption = new List @@ -156,7 +159,7 @@ private static IEnumerable BlockData() }, new object[] { - new EquationBlock { Equation = new EquationBlock.Info { Expression = "e=mc^3" } }, + new EquationBlockRequest { Equation = new EquationBlockRequest.Info { Expression = "e=mc^3" } }, new EquationUpdateBlock { Equation = new EquationUpdateBlock.Info { Expression = "e=mc^2" } }, new Action((block, _) => { @@ -166,7 +169,7 @@ private static IEnumerable BlockData() }, new object[] { - new DividerBlock { Divider = new DividerBlock.Data() }, new DividerUpdateBlock(), + new DividerBlockRequest { Divider = new DividerBlockRequest.Data() }, new DividerUpdateBlock(), new Action((block, client) => { Assert.NotNull(block); @@ -175,7 +178,7 @@ private static IEnumerable BlockData() }, new object[] { - new AudioBlock + new AudioBlockRequest { Audio = new ExternalFile { @@ -206,7 +209,7 @@ private static IEnumerable BlockData() }, new object[] { - new TableOfContentsBlock { TableOfContents = new TableOfContentsBlock.Data() }, + new TableOfContentsBlockRequest { TableOfContents = new TableOfContentsBlockRequest.Data() }, new TableOfContentsUpdateBlock(), new Action((block, client) => { Assert.NotNull(block); @@ -215,9 +218,9 @@ private static IEnumerable BlockData() }, new object[] { - new CalloutBlock + new CalloutBlockRequest { - Callout = new CalloutBlock.Info + Callout = new CalloutBlockRequest.Info { RichText = new List { @@ -245,9 +248,9 @@ private static IEnumerable BlockData() }, new object[] { - new QuoteBlock + new QuoteBlockRequest { - Quote = new QuoteBlock.Info + Quote = new QuoteBlockRequest.Info { RichText = new List { @@ -275,7 +278,7 @@ private static IEnumerable BlockData() }, new object[] { - new ImageBlock + new ImageBlockRequest { Image = new ExternalFile { @@ -308,9 +311,9 @@ private static IEnumerable BlockData() }, new object[] { - new EmbedBlock + new EmbedBlockRequest { - Embed = new EmbedBlock.Info + Embed = new EmbedBlockRequest.Info { Url = "https://zephoria.com/wp-content/uploads/2014/08/online-community.jpg" } @@ -333,7 +336,7 @@ private static IEnumerable BlockData() }, new object[] { - new LinkToPageBlock + new LinkToPageBlockRequest { LinkToPage = new PageParent { @@ -359,16 +362,16 @@ private static IEnumerable BlockData() }, new object[] { - new TableBlock + new TableBlockRequest { - Table = new TableBlock.Info + Table = new TableBlockRequest.Info { TableWidth = 1, Children = new[] { - new TableRowBlock + new TableRowBlockRequest { - TableRow = new TableRowBlock.Info + TableRow = new TableRowBlockRequest.Info { Cells = new[] { diff --git a/Test/Notion.UnitTests/BlocksClientTests.cs b/Test/Notion.UnitTests/BlocksClientTests.cs index 600e0bf4..6dd1656b 100644 --- a/Test/Notion.UnitTests/BlocksClientTests.cs +++ b/Test/Notion.UnitTests/BlocksClientTests.cs @@ -63,11 +63,11 @@ public async Task AppendBlockChildren() var request = new BlockAppendChildrenRequest { BlockId = blockId, - Children = new List + Children = new List { - new HeadingTwoBlock + new HeadingTwoBlockRequest { - Heading_2 = new HeadingTwoBlock.Info + Heading_2 = new HeadingTwoBlockRequest.Info { RichText = new List { @@ -75,9 +75,9 @@ public async Task AppendBlockChildren() } } }, - new ParagraphBlock + new ParagraphBlockRequest { - Paragraph = new ParagraphBlock.Info + Paragraph = new ParagraphBlockRequest.Info { RichText = new List { From 09ff9194a934ed2b24ffed7cbaac130cad9fae5d Mon Sep 17 00:00:00 2001 From: Gehongyan Date: Wed, 8 Nov 2023 18:00:03 +0800 Subject: [PATCH 48/89] Fix broken database relation request parameters. --- .../PropertySchema/RelationPropertySchema.cs | 17 ++--------------- .../RelationUpdatePropertySchema.cs | 17 ++--------------- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RelationPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RelationPropertySchema.cs index fa6a3249..4c278ac2 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RelationPropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RelationPropertySchema.cs @@ -1,23 +1,10 @@ -using System; -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Notion.Client { public class RelationPropertySchema : IPropertySchema { [JsonProperty("relation")] - public RelationInfo Relation { get; set; } - - public class RelationInfo - { - [JsonProperty("database_id")] - public Guid DatabaseId { get; set; } - - [JsonProperty("synced_property_id")] - public string SyncedPropertyId { get; set; } - - [JsonProperty("synced_property_name")] - public string SyncedPropertyName { get; set; } - } + public RelationData Relation { get; set; } } } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RelationUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RelationUpdatePropertySchema.cs index 4f6a74a3..25f65cd4 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RelationUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RelationUpdatePropertySchema.cs @@ -1,23 +1,10 @@ -using System; -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Notion.Client { public class RelationUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("relation")] - public RelationInfo Relation { get; set; } - - public class RelationInfo - { - [JsonProperty("database_id")] - public Guid DatabaseId { get; set; } - - [JsonProperty("synced_property_id")] - public string SyncedPropertyId { get; set; } - - [JsonProperty("synced_property_name")] - public string SyncedPropertyName { get; set; } - } + public RelationData Relation { get; set; } } } From 59fd00540c0e0c1cdb619e6704bf04dbd86c4cd7 Mon Sep 17 00:00:00 2001 From: "boris.kuzmanov" Date: Sat, 27 Apr 2024 14:47:47 +0200 Subject: [PATCH 49/89] Change GetewayTimeout to GatewayTimeout (typo fix) --- Src/Notion.Client/NotionAPIErrorCode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Notion.Client/NotionAPIErrorCode.cs b/Src/Notion.Client/NotionAPIErrorCode.cs index e0264ae7..97984f98 100644 --- a/Src/Notion.Client/NotionAPIErrorCode.cs +++ b/Src/Notion.Client/NotionAPIErrorCode.cs @@ -49,6 +49,6 @@ public enum NotionAPIErrorCode DatabaseConnectionUnavailable, [EnumMember(Value = "gateway_timeout")] - GetewayTimeout + GatewayTimeout } } From b85a175fad43b4c65d1baa35d4af4030b0a5b4f6 Mon Sep 17 00:00:00 2001 From: "boris.kuzmanov" Date: Sun, 28 Apr 2024 13:37:54 +0200 Subject: [PATCH 50/89] Add name property to FileObject --- Src/Notion.Client/Models/File/FileObject.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Src/Notion.Client/Models/File/FileObject.cs b/Src/Notion.Client/Models/File/FileObject.cs index 9ed206de..2c219a1b 100644 --- a/Src/Notion.Client/Models/File/FileObject.cs +++ b/Src/Notion.Client/Models/File/FileObject.cs @@ -11,6 +11,9 @@ public abstract class FileObject : IPageIcon { [JsonProperty("caption")] public IEnumerable Caption { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } [JsonProperty("type")] public virtual string Type { get; set; } From 09937b69db43e1b8e8abe2bd2023972297261fa8 Mon Sep 17 00:00:00 2001 From: "boris.kuzmanov" Date: Sun, 28 Apr 2024 14:24:30 +0200 Subject: [PATCH 51/89] Run lint --- Src/Notion.Client/Models/File/FileObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Notion.Client/Models/File/FileObject.cs b/Src/Notion.Client/Models/File/FileObject.cs index 2c219a1b..aa7aed1b 100644 --- a/Src/Notion.Client/Models/File/FileObject.cs +++ b/Src/Notion.Client/Models/File/FileObject.cs @@ -11,7 +11,7 @@ public abstract class FileObject : IPageIcon { [JsonProperty("caption")] public IEnumerable Caption { get; set; } - + [JsonProperty("name")] public string Name { get; set; } From 08ed291c0d27ca02ce02f8a7d5b9d2c31032dad7 Mon Sep 17 00:00:00 2001 From: kosaku-hayashi Date: Sun, 14 Jul 2024 14:57:47 +0900 Subject: [PATCH 52/89] Removed 'archived' property and added 'in_trash' property. --- Src/Notion.Client/Api/Blocks/IBlocksClient.cs | 2 +- .../UpdateBlocks/BookmarkUpdateBlock.cs | 2 +- .../UpdateBlocks/BreadcrumbUpdateBlock.cs | 2 +- .../UpdateBlocks/DividerUpdateBlock.cs | 2 +- .../UpdateBlocks/IUpdateBlock.cs | 4 ++-- .../UpdateBlocks/TableOfContentsUpdateBlock.cs | 2 +- .../UpdateBlocks/UpdateBlock.cs | 2 +- .../DatabasesUpdateParameters.cs | 2 +- .../IDatabasesUpdateBodyParameters.cs | 4 ++-- .../IPagesUpdateBodyParameters.cs | 4 ++-- .../RequestParams/PagesUpdateParameters.cs | 4 ++-- Src/Notion.Client/Models/Blocks/Block.cs | 2 ++ Src/Notion.Client/Models/Blocks/IBlock.cs | 3 +++ Src/Notion.Client/Models/Database/Database.cs | 7 ++----- Src/Notion.Client/Models/Page/Page.cs | 6 +++--- .../BlocksClientTests.cs | 2 +- .../CommentsClientTests.cs | 2 +- .../DatabasesClientTests.cs | 2 +- .../Notion.IntegrationTests/PageClientTests.cs | 2 +- .../PageWithPageParentTests.cs | 2 +- Test/Notion.UnitTests/BlocksClientTests.cs | 1 + Test/Notion.UnitTests/Notion.UnitTests.csproj | 2 +- Test/Notion.UnitTests/PagesClientTests.cs | 14 +++++++------- Test/Notion.UnitTests/SearchClientTest.cs | 2 +- .../blocks/AppendBlockChildrenResponse.json | 1 + .../blocks/RetrieveBlockChildrenResponse.json | 18 +++++++++--------- .../data/blocks/RetrieveBlockResponse.json | 1 + .../data/blocks/UpdateBlockResponse.json | 1 + .../databases/DatabaseRetrieveResponse.json | 1 + .../data/databases/DatabasesQueryResponse.json | 2 +- ...yncDateFormulaValueReturnsNullResponse.json | 2 +- .../data/pages/CreatePageResponse.json | 2 +- ...ageObjectShouldHaveUrlPropertyResponse.json | 2 +- ...ageResponse.json => TrashPageResponse.json} | 2 +- .../pages/UpdatePagePropertiesResponse.json | 2 +- .../data/search/SearchResponse.json | 3 ++- 36 files changed, 61 insertions(+), 53 deletions(-) rename Test/Notion.UnitTests/data/pages/{ArchivePageResponse.json => TrashPageResponse.json} (97%) diff --git a/Src/Notion.Client/Api/Blocks/IBlocksClient.cs b/Src/Notion.Client/Api/Blocks/IBlocksClient.cs index fec1b9f5..c5a64e59 100644 --- a/Src/Notion.Client/Api/Blocks/IBlocksClient.cs +++ b/Src/Notion.Client/Api/Blocks/IBlocksClient.cs @@ -47,7 +47,7 @@ Task AppendChildrenAsync( ); /// - /// Sets a Block object, including page blocks, to archived: true using the ID specified. + /// Moves a Block object, including page blocks, to the trash: true using the ID specified. /// /// Identifier for a Notion block Task DeleteAsync(string blockId, CancellationToken cancellationToken = default); diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BookmarkUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BookmarkUpdateBlock.cs index 612b6dda..b147c587 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BookmarkUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BookmarkUpdateBlock.cs @@ -8,7 +8,7 @@ public class BookmarkUpdateBlock : IUpdateBlock [JsonProperty("bookmark")] public Info Bookmark { get; set; } - public bool Archived { get; set; } + public bool InTrash { get; set; } public class Info { diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BreadcrumbUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BreadcrumbUpdateBlock.cs index a90f6966..260eca82 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BreadcrumbUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BreadcrumbUpdateBlock.cs @@ -12,7 +12,7 @@ public BreadcrumbUpdateBlock() [JsonProperty("breadcrumb")] public Info Breadcrumb { get; set; } - public bool Archived { get; set; } + public bool InTrash { get; set; } public class Info { diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/DividerUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/DividerUpdateBlock.cs index 79f332f0..62b83451 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/DividerUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/DividerUpdateBlock.cs @@ -12,7 +12,7 @@ public DividerUpdateBlock() [JsonProperty("divider")] public Info Divider { get; set; } - public bool Archived { get; set; } + public bool InTrash { get; set; } public class Info { diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/IUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/IUpdateBlock.cs index ba93fe29..5b1de4be 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/IUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/IUpdateBlock.cs @@ -4,7 +4,7 @@ namespace Notion.Client { public interface IUpdateBlock { - [JsonProperty("archived")] - bool Archived { get; set; } + [JsonProperty("in_trash")] + bool InTrash { get; set; } } } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableOfContentsUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableOfContentsUpdateBlock.cs index bef1f278..2e4adff9 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableOfContentsUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableOfContentsUpdateBlock.cs @@ -12,7 +12,7 @@ public TableOfContentsUpdateBlock() [JsonProperty("table_of_contents")] public Info TableOfContents { get; set; } - public bool Archived { get; set; } + public bool InTrash { get; set; } public class Info { diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/UpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/UpdateBlock.cs index d0321e52..14704cb2 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/UpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/UpdateBlock.cs @@ -2,6 +2,6 @@ { public abstract class UpdateBlock : IUpdateBlock { - public bool Archived { get; set; } + public bool InTrash { get; set; } } } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateParameters.cs index 41da2d17..5147a6b0 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateParameters.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateParameters.cs @@ -12,7 +12,7 @@ public class DatabasesUpdateParameters : IDatabasesUpdateBodyParameters public FileObject Cover { get; set; } - public bool Archived { get; set; } + public bool InTrash { get; set; } public bool? IsInline { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/IDatabasesUpdateBodyParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/IDatabasesUpdateBodyParameters.cs index b1dc419a..f37df431 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/IDatabasesUpdateBodyParameters.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/IDatabasesUpdateBodyParameters.cs @@ -17,8 +17,8 @@ public interface IDatabasesUpdateBodyParameters [JsonProperty("cover")] FileObject Cover { get; set; } - [JsonProperty("archived")] - bool Archived { get; set; } + [JsonProperty("in_trash")] + bool InTrash { get; set; } [JsonProperty("is_inline")] bool? IsInline { get; set; } diff --git a/Src/Notion.Client/Api/Pages/RequestParams/IPagesUpdateBodyParameters.cs b/Src/Notion.Client/Api/Pages/RequestParams/IPagesUpdateBodyParameters.cs index b37dd1fd..b7ea1ea6 100644 --- a/Src/Notion.Client/Api/Pages/RequestParams/IPagesUpdateBodyParameters.cs +++ b/Src/Notion.Client/Api/Pages/RequestParams/IPagesUpdateBodyParameters.cs @@ -5,8 +5,8 @@ namespace Notion.Client { public interface IPagesUpdateBodyParameters { - [JsonProperty("archived")] - bool Archived { get; set; } + [JsonProperty("in_trash")] + bool InTrash { get; set; } [JsonProperty("properties")] IDictionary Properties { get; set; } diff --git a/Src/Notion.Client/Api/Pages/RequestParams/PagesUpdateParameters.cs b/Src/Notion.Client/Api/Pages/RequestParams/PagesUpdateParameters.cs index 742ef8dd..6845f27b 100644 --- a/Src/Notion.Client/Api/Pages/RequestParams/PagesUpdateParameters.cs +++ b/Src/Notion.Client/Api/Pages/RequestParams/PagesUpdateParameters.cs @@ -11,8 +11,8 @@ public class PagesUpdateParameters : IPagesUpdateBodyParameters [JsonProperty("cover")] public FileObject Cover { get; set; } - [JsonProperty("archived")] - public bool Archived { get; set; } + [JsonProperty("in_trash")] + public bool InTrash { get; set; } [JsonProperty("properties")] public IDictionary Properties { get; set; } diff --git a/Src/Notion.Client/Models/Blocks/Block.cs b/Src/Notion.Client/Models/Blocks/Block.cs index 883399df..fa1ef612 100644 --- a/Src/Notion.Client/Models/Blocks/Block.cs +++ b/Src/Notion.Client/Models/Blocks/Block.cs @@ -16,6 +16,8 @@ public abstract class Block : IBlock public virtual bool HasChildren { get; set; } + public bool InTrash { get; set; } + public PartialUser CreatedBy { get; set; } public PartialUser LastEditedBy { get; set; } diff --git a/Src/Notion.Client/Models/Blocks/IBlock.cs b/Src/Notion.Client/Models/Blocks/IBlock.cs index 24d6a12a..b06a3646 100644 --- a/Src/Notion.Client/Models/Blocks/IBlock.cs +++ b/Src/Notion.Client/Models/Blocks/IBlock.cs @@ -47,6 +47,9 @@ public interface IBlock : IObject, IObjectModificationData [JsonProperty("has_children")] bool HasChildren { get; set; } + [JsonProperty("in_trash")] + bool InTrash { get; set; } + [JsonProperty("parent")] IBlockParent Parent { get; set; } } diff --git a/Src/Notion.Client/Models/Database/Database.cs b/Src/Notion.Client/Models/Database/Database.cs index c5a46ed6..be288ea0 100644 --- a/Src/Notion.Client/Models/Database/Database.cs +++ b/Src/Notion.Client/Models/Database/Database.cs @@ -27,11 +27,8 @@ public class Database : IObject, IObjectModificationData, IWikiDatabase [JsonProperty("url")] public string Url { get; set; } - /// - /// The archived status of the database. - /// - [JsonProperty("archived")] - public bool Archived { get; set; } + [JsonProperty("in_trash")] + public bool InTrash { get; set; } [JsonProperty("is_inline")] public bool IsInline { get; set; } diff --git a/Src/Notion.Client/Models/Page/Page.cs b/Src/Notion.Client/Models/Page/Page.cs index c6bcfae1..fe4eb0de 100644 --- a/Src/Notion.Client/Models/Page/Page.cs +++ b/Src/Notion.Client/Models/Page/Page.cs @@ -13,10 +13,10 @@ public class Page : IObject, IObjectModificationData, IWikiDatabase public IPageParent Parent { get; set; } /// - /// The archived status of the page. + /// Indicates whether the page is currently in the trash. /// - [JsonProperty("archived")] - public bool IsArchived { get; set; } + [JsonProperty("in_trash")] + public bool InTrash { get; set; } /// /// Property values of this page. diff --git a/Test/Notion.IntegrationTests/BlocksClientTests.cs b/Test/Notion.IntegrationTests/BlocksClientTests.cs index 284ac009..5c8e4618 100644 --- a/Test/Notion.IntegrationTests/BlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/BlocksClientTests.cs @@ -23,7 +23,7 @@ public async Task InitializeAsync() public async Task DisposeAsync() { - await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); } [Fact] diff --git a/Test/Notion.IntegrationTests/CommentsClientTests.cs b/Test/Notion.IntegrationTests/CommentsClientTests.cs index 1655fc71..fac1fce1 100644 --- a/Test/Notion.IntegrationTests/CommentsClientTests.cs +++ b/Test/Notion.IntegrationTests/CommentsClientTests.cs @@ -21,7 +21,7 @@ public async Task InitializeAsync() public async Task DisposeAsync() { - await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); } [Fact] diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs index c5c7082b..31b611f1 100644 --- a/Test/Notion.IntegrationTests/DatabasesClientTests.cs +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -22,7 +22,7 @@ public async Task InitializeAsync() public async Task DisposeAsync() { - await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); } [Fact] diff --git a/Test/Notion.IntegrationTests/PageClientTests.cs b/Test/Notion.IntegrationTests/PageClientTests.cs index 2e4153eb..21adbd5b 100644 --- a/Test/Notion.IntegrationTests/PageClientTests.cs +++ b/Test/Notion.IntegrationTests/PageClientTests.cs @@ -63,7 +63,7 @@ public async Task InitializeAsync() public async Task DisposeAsync() { - await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); } [Fact] diff --git a/Test/Notion.IntegrationTests/PageWithPageParentTests.cs b/Test/Notion.IntegrationTests/PageWithPageParentTests.cs index 5f398dc7..3c6d3c6c 100644 --- a/Test/Notion.IntegrationTests/PageWithPageParentTests.cs +++ b/Test/Notion.IntegrationTests/PageWithPageParentTests.cs @@ -29,7 +29,7 @@ public async Task InitializeAsync() public async Task DisposeAsync() { - await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { Archived = true }); + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); } [Fact] diff --git a/Test/Notion.UnitTests/BlocksClientTests.cs b/Test/Notion.UnitTests/BlocksClientTests.cs index 6dd1656b..e2cc8603 100644 --- a/Test/Notion.UnitTests/BlocksClientTests.cs +++ b/Test/Notion.UnitTests/BlocksClientTests.cs @@ -184,6 +184,7 @@ public async Task UpdateAsync() block.Id.Should().Be(blockId); block.HasChildren.Should().BeFalse(); + block.InTrash.Should().BeFalse(); block.Type.Should().Be(BlockType.ToDo); var todoBlock = (ToDoBlock)block; diff --git a/Test/Notion.UnitTests/Notion.UnitTests.csproj b/Test/Notion.UnitTests/Notion.UnitTests.csproj index 30ff0791..588ddc54 100644 --- a/Test/Notion.UnitTests/Notion.UnitTests.csproj +++ b/Test/Notion.UnitTests/Notion.UnitTests.csproj @@ -51,7 +51,7 @@ Always - + Always diff --git a/Test/Notion.UnitTests/PagesClientTests.cs b/Test/Notion.UnitTests/PagesClientTests.cs index adbb9443..9541f62e 100644 --- a/Test/Notion.UnitTests/PagesClientTests.cs +++ b/Test/Notion.UnitTests/PagesClientTests.cs @@ -39,7 +39,7 @@ public async Task RetrieveAsync() page.Id.Should().Be(pageId); page.Parent.Type.Should().Be(ParentType.DatabaseId); ((DatabaseParent)page.Parent).DatabaseId.Should().Be("48f8fee9-cd79-4180-bc2f-ec0398253067"); - page.IsArchived.Should().BeFalse(); + page.InTrash.Should().BeFalse(); } [Fact] @@ -72,7 +72,7 @@ public async Task CreateAsync() page.Url.Should().NotBeNullOrEmpty(); page.Properties.Should().HaveCount(1); page.Properties.First().Key.Should().Be("Name"); - page.IsArchived.Should().BeFalse(); + page.InTrash.Should().BeFalse(); page.Parent.Should().NotBeNull(); ((DatabaseParent)page.Parent).DatabaseId.Should().Be("3c357473-a281-49a4-88c0-10d2b245a589"); } @@ -172,7 +172,7 @@ public async Task UpdatePageAsync() var page = await _client.UpdateAsync(pageId, pagesUpdateParameters); page.Id.Should().Be(pageId); - page.IsArchived.Should().BeFalse(); + page.InTrash.Should().BeFalse(); page.Properties.Should().HaveCount(2); var updatedProperty = page.Properties.First(x => x.Key == "In stock"); @@ -187,14 +187,14 @@ public async Task UpdatePageAsync() } [Fact] - public async Task ArchivePageAsync() + public async Task TrashPageAsync() { var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; var propertyId = "{>U;"; var path = ApiEndpoints.PagesApiUrls.UpdateProperties(pageId); - var jsonData = await File.ReadAllTextAsync("data/pages/ArchivePageResponse.json"); + var jsonData = await File.ReadAllTextAsync("data/pages/TrashPageResponse.json"); Server.Given(CreatePatchRequestBuilder(path)) .RespondWith( @@ -211,7 +211,7 @@ public async Task ArchivePageAsync() var pagesUpdateParameters = new PagesUpdateParameters { - Archived = true, + InTrash = true, Properties = new Dictionary { { "In stock", new CheckboxPropertyValue { Checkbox = true } } @@ -221,7 +221,7 @@ public async Task ArchivePageAsync() var page = await _client.UpdateAsync(pageId, pagesUpdateParameters); page.Id.Should().Be(pageId); - page.IsArchived.Should().BeTrue(); + page.InTrash.Should().BeTrue(); page.Properties.Should().HaveCount(2); var updatedProperty = page.Properties.First(x => x.Key == "In stock"); diff --git a/Test/Notion.UnitTests/SearchClientTest.cs b/Test/Notion.UnitTests/SearchClientTest.cs index 35765cef..a5a477cb 100644 --- a/Test/Notion.UnitTests/SearchClientTest.cs +++ b/Test/Notion.UnitTests/SearchClientTest.cs @@ -59,7 +59,7 @@ public async Task Search() obj.Object.Should().Be(ObjectType.Page); var page = (Page)obj; - page.IsArchived.Should().BeFalse(); + page.InTrash.Should().BeFalse(); page.Properties.Should().HaveCount(1); page.Parent.Should().BeAssignableTo(); ((DatabaseParent)page.Parent).DatabaseId.Should().Be("e6c6f8ff-c70e-4970-91ba-98f03e0d7fc6"); diff --git a/Test/Notion.UnitTests/data/blocks/AppendBlockChildrenResponse.json b/Test/Notion.UnitTests/data/blocks/AppendBlockChildrenResponse.json index 32612405..13966312 100644 --- a/Test/Notion.UnitTests/data/blocks/AppendBlockChildrenResponse.json +++ b/Test/Notion.UnitTests/data/blocks/AppendBlockChildrenResponse.json @@ -7,6 +7,7 @@ "created_time": "2021-03-16T16:31:00.000Z", "last_edited_time": "2021-03-16T16:32:00.000Z", "has_children": false, + "in_trash" : false, "type": "heading_2", "heading_2": { "rich_text": [ diff --git a/Test/Notion.UnitTests/data/blocks/RetrieveBlockChildrenResponse.json b/Test/Notion.UnitTests/data/blocks/RetrieveBlockChildrenResponse.json index 7b0ae104..b16dfc35 100644 --- a/Test/Notion.UnitTests/data/blocks/RetrieveBlockChildrenResponse.json +++ b/Test/Notion.UnitTests/data/blocks/RetrieveBlockChildrenResponse.json @@ -7,7 +7,7 @@ "created_time": "2021-05-29T16:22:00.000Z", "last_edited_time": "2021-05-29T16:22:00.000Z", "has_children": false, - "archived": false, + "in_trash": false, "type": "paragraph", "paragraph": { "rich_text": [] @@ -19,7 +19,7 @@ "created_time": "2021-05-30T09:25:00.000Z", "last_edited_time": "2021-05-30T09:25:00.000Z", "has_children": false, - "archived": false, + "in_trash": false, "type": "heading_2", "heading_2": { "rich_text": [ @@ -49,7 +49,7 @@ "created_time": "2021-05-30T09:36:00.000Z", "last_edited_time": "2021-05-30T09:36:00.000Z", "has_children": false, - "archived": false, + "in_trash": false, "type": "heading_2", "heading_2": { "rich_text": [ @@ -79,7 +79,7 @@ "created_time": "2021-08-18T21:12:00.000Z", "last_edited_time": "2021-08-18T21:12:00.000Z", "has_children": false, - "archived": false, + "in_trash": false, "type": "paragraph", "paragraph": { "rich_text": [] @@ -91,7 +91,7 @@ "created_time": "2021-08-18T23:00:00.000Z", "last_edited_time": "2021-08-18T23:00:00.000Z", "has_children": false, - "archived": false, + "in_trash": false, "type": "child_page", "child_page": { "title": "" @@ -103,7 +103,7 @@ "created_time": "2021-08-18T23:00:00.000Z", "last_edited_time": "2021-08-18T23:00:00.000Z", "has_children": false, - "archived": false, + "in_trash": false, "type": "child_page", "child_page": { "title": "" @@ -115,7 +115,7 @@ "created_time": "2021-09-09T05:22:00.000Z", "last_edited_time": "2021-09-09T05:22:00.000Z", "has_children": false, - "archived": false, + "in_trash": false, "type": "paragraph", "paragraph": { "rich_text": [] @@ -127,7 +127,7 @@ "created_time": "2022-05-03T13:28:00.000Z", "last_edited_time": "2022-05-03T13:29:00.000Z", "has_children": false, - "archived": false, + "in_trash": false, "type": "image", "image": { "caption": [ @@ -174,7 +174,7 @@ "id": "92e803ec-193c-4bcd-b28e-88365858d562" }, "has_children": true, - "archived": false, + "in_trash": false, "type": "synced_block", "synced_block": { "synced_from": { diff --git a/Test/Notion.UnitTests/data/blocks/RetrieveBlockResponse.json b/Test/Notion.UnitTests/data/blocks/RetrieveBlockResponse.json index 9c7deabe..6df6ddb2 100644 --- a/Test/Notion.UnitTests/data/blocks/RetrieveBlockResponse.json +++ b/Test/Notion.UnitTests/data/blocks/RetrieveBlockResponse.json @@ -4,6 +4,7 @@ "created_time": "2021-03-16T16:31:00.000Z", "last_edited_time": "2021-03-16T16:32:00.000Z", "has_children": false, + "in_trash" : false, "type": "to_do", "to_do": { "rich_text": [ diff --git a/Test/Notion.UnitTests/data/blocks/UpdateBlockResponse.json b/Test/Notion.UnitTests/data/blocks/UpdateBlockResponse.json index 497aba34..c2d3a2c4 100644 --- a/Test/Notion.UnitTests/data/blocks/UpdateBlockResponse.json +++ b/Test/Notion.UnitTests/data/blocks/UpdateBlockResponse.json @@ -4,6 +4,7 @@ "created_time": "2021-03-16T16:31:00.000Z", "last_edited_time": "2021-03-16T16:32:00.000Z", "has_children": false, + "in_trash" : false, "type": "to_do", "to_do": { "rich_text": [ diff --git a/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json b/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json index 9b5cf45f..5849bb88 100644 --- a/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json +++ b/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json @@ -33,6 +33,7 @@ } }, "url": "https://www.notion.so/668d797c76fa49349b05ad288df2d136", + "in_trash" : false, "properties": { "Tags": { "id": "YG~h", diff --git a/Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json b/Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json index 27e70234..cf1b1f01 100644 --- a/Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json +++ b/Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json @@ -10,7 +10,7 @@ "type": "database_id", "database_id": "897e5a76-ae52-4b48-9fdf-e71f5945d1af" }, - "archived": false, + "in_trash": false, "url": "https://www.notion.so/2e01e904febd43a0ad028eedb903a82c", "properties": { "Recipes": { diff --git a/Test/Notion.UnitTests/data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json b/Test/Notion.UnitTests/data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json index 8c1b95c0..00159d76 100644 --- a/Test/Notion.UnitTests/data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json +++ b/Test/Notion.UnitTests/data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json @@ -12,7 +12,7 @@ "type": "database_id", "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb" }, - "archived": false, + "in_trash": false, "properties": { "Column": { "id": "B[\\E", diff --git a/Test/Notion.UnitTests/data/pages/CreatePageResponse.json b/Test/Notion.UnitTests/data/pages/CreatePageResponse.json index 89f0e58e..a801949b 100644 --- a/Test/Notion.UnitTests/data/pages/CreatePageResponse.json +++ b/Test/Notion.UnitTests/data/pages/CreatePageResponse.json @@ -3,7 +3,7 @@ "id": "251d2b5f-268c-4de2-afe9-c71ff92ca95c", "created_time": "2020-03-17T19:10:04.968Z", "last_edited_time": "2020-03-17T21:49:37.913Z", - "archived": false, + "in_trash": false, "url": "https://www.notion.so/Test-251d2b5f268c4de2afe9c71ff92ca95c", "properties": { "Name": { diff --git a/Test/Notion.UnitTests/data/pages/PageObjectShouldHaveUrlPropertyResponse.json b/Test/Notion.UnitTests/data/pages/PageObjectShouldHaveUrlPropertyResponse.json index 8f9d45ab..bf5ba373 100644 --- a/Test/Notion.UnitTests/data/pages/PageObjectShouldHaveUrlPropertyResponse.json +++ b/Test/Notion.UnitTests/data/pages/PageObjectShouldHaveUrlPropertyResponse.json @@ -7,7 +7,7 @@ "type": "database_id", "database_id": "48f8fee9-cd79-4180-bc2f-ec0398253067" }, - "archived": false, + "in_trash": false, "url": "https://www.notion.so/Avocado-251d2b5f268c4de2afe9c71ff92ca95c", "properties": { "Name": { diff --git a/Test/Notion.UnitTests/data/pages/ArchivePageResponse.json b/Test/Notion.UnitTests/data/pages/TrashPageResponse.json similarity index 97% rename from Test/Notion.UnitTests/data/pages/ArchivePageResponse.json rename to Test/Notion.UnitTests/data/pages/TrashPageResponse.json index 2f9af7c6..0c61a3c9 100644 --- a/Test/Notion.UnitTests/data/pages/ArchivePageResponse.json +++ b/Test/Notion.UnitTests/data/pages/TrashPageResponse.json @@ -3,7 +3,7 @@ "id": "251d2b5f-268c-4de2-afe9-c71ff92ca95c", "created_time": "2020-03-17T19:10:04.968Z", "last_edited_time": "2020-03-17T21:49:37.913Z", - "archived": true, + "in_trash": true, "url": "https://www.notion.so/Test-251d2b5f268c4de2afe9c71ff92ca95c", "properties": { "In stock": { diff --git a/Test/Notion.UnitTests/data/pages/UpdatePagePropertiesResponse.json b/Test/Notion.UnitTests/data/pages/UpdatePagePropertiesResponse.json index 12076368..70cc2164 100644 --- a/Test/Notion.UnitTests/data/pages/UpdatePagePropertiesResponse.json +++ b/Test/Notion.UnitTests/data/pages/UpdatePagePropertiesResponse.json @@ -3,7 +3,7 @@ "id": "251d2b5f-268c-4de2-afe9-c71ff92ca95c", "created_time": "2020-03-17T19:10:04.968Z", "last_edited_time": "2020-03-17T21:49:37.913Z", - "archived": false, + "in_trash": false, "url": "https://www.notion.so/Test-251d2b5f268c4de2afe9c71ff92ca95c", "properties": { "In stock": { diff --git a/Test/Notion.UnitTests/data/search/SearchResponse.json b/Test/Notion.UnitTests/data/search/SearchResponse.json index 107adcb3..53defa57 100644 --- a/Test/Notion.UnitTests/data/search/SearchResponse.json +++ b/Test/Notion.UnitTests/data/search/SearchResponse.json @@ -4,6 +4,7 @@ "object": "list", "results": [ { + "in_trash": false, "created_time": "2021-04-22T22:23:26.080Z", "id": "e6c6f8ff-c70e-4970-91ba-98f03e0d7fc6", "last_edited_time": "2021-04-23T04:21:00.000Z", @@ -43,7 +44,7 @@ ] }, { - "archived": false, + "in_trash": false, "created_time": "2021-04-23T04:21:00.000Z", "id": "4f555b50-3a9b-49cb-924c-3746f4ca5522", "last_edited_time": "2021-04-23T04:21:00.000Z", From 609e04dc8b9ef3969d3c214af95e5ddaf18e8b13 Mon Sep 17 00:00:00 2001 From: kosaku-hayashi Date: Sun, 14 Jul 2024 17:01:31 +0900 Subject: [PATCH 53/89] Added support for button properties. --- .../Database/Properties/ButtonProperty.cs | 16 ++++++++++++++++ .../Models/Database/Properties/Property.cs | 1 + .../Models/Database/Properties/PropertyType.cs | 3 +++ .../Models/PropertyValue/ButtonPropertyValue.cs | 17 +++++++++++++++++ .../Models/PropertyValue/PropertyValue.cs | 1 + .../Models/PropertyValue/PropertyValueType.cs | 3 +++ Test/Notion.UnitTests/PagesClientTests.cs | 2 +- Test/Notion.UnitTests/PropertyTests.cs | 2 ++ .../databases/DatabaseRetrieveResponse.json | 6 ++++++ .../data/databases/DatabasesListResponse.json | 6 ++++++ .../data/databases/DatabasesQueryResponse.json | 5 +++++ .../data/pages/TrashPageResponse.json | 5 +++++ 12 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 Src/Notion.Client/Models/Database/Properties/ButtonProperty.cs create mode 100644 Src/Notion.Client/Models/PropertyValue/ButtonPropertyValue.cs diff --git a/Src/Notion.Client/Models/Database/Properties/ButtonProperty.cs b/Src/Notion.Client/Models/Database/Properties/ButtonProperty.cs new file mode 100644 index 00000000..983138e2 --- /dev/null +++ b/Src/Notion.Client/Models/Database/Properties/ButtonProperty.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public class ButtonProperty : Property + { + public override PropertyType Type => PropertyType.Button; + + [JsonProperty("button")] + public Dictionary Button { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Database/Properties/Property.cs b/Src/Notion.Client/Models/Database/Properties/Property.cs index fa0dac50..6392bbaf 100644 --- a/Src/Notion.Client/Models/Database/Properties/Property.cs +++ b/Src/Notion.Client/Models/Database/Properties/Property.cs @@ -26,6 +26,7 @@ namespace Notion.Client [JsonSubtypes.KnownSubTypeAttribute(typeof(TitleProperty), PropertyType.Title)] [JsonSubtypes.KnownSubTypeAttribute(typeof(UrlProperty), PropertyType.Url)] [JsonSubtypes.KnownSubTypeAttribute(typeof(UniqueIdProperty), PropertyType.UniqueId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ButtonProperty), PropertyType.Button)] public class Property { [JsonProperty("id")] diff --git a/Src/Notion.Client/Models/Database/Properties/PropertyType.cs b/Src/Notion.Client/Models/Database/Properties/PropertyType.cs index 6391308c..206f9fe2 100644 --- a/Src/Notion.Client/Models/Database/Properties/PropertyType.cs +++ b/Src/Notion.Client/Models/Database/Properties/PropertyType.cs @@ -71,5 +71,8 @@ public enum PropertyType [EnumMember(Value = "unique_id")] UniqueId, + + [EnumMember(Value = "button")] + Button, } } diff --git a/Src/Notion.Client/Models/PropertyValue/ButtonPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/ButtonPropertyValue.cs new file mode 100644 index 00000000..61ae9fc4 --- /dev/null +++ b/Src/Notion.Client/Models/PropertyValue/ButtonPropertyValue.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ButtonPropertyValue : PropertyValue + { + public override PropertyValueType Type => PropertyValueType.Button; + + [JsonProperty("button")] + public ButtonValue Button { get; set; } + + public class ButtonValue { } + } +} diff --git a/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs index a74b11da..e1289046 100644 --- a/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs @@ -30,6 +30,7 @@ namespace Notion.Client [JsonSubtypes.KnownSubTypeAttribute(typeof(TitlePropertyValue), PropertyValueType.Title)] [JsonSubtypes.KnownSubTypeAttribute(typeof(UrlPropertyValue), PropertyValueType.Url)] [JsonSubtypes.KnownSubTypeAttribute(typeof(UniqueIdPropertyValue), PropertyValueType.UniqueId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ButtonPropertyValue), PropertyValueType.Button)] [JsonSubtypes.KnownSubTypeAttribute(typeof(VerificationPropertyValue), PropertyValueType.Verification)] [SuppressMessage("ReSharper", "UnusedMember.Global")] [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] diff --git a/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs b/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs index d77a564c..574138e9 100644 --- a/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs +++ b/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs @@ -77,5 +77,8 @@ public enum PropertyValueType [EnumMember(Value = "verification")] Verification, + + [EnumMember(Value = "button")] + Button, } } diff --git a/Test/Notion.UnitTests/PagesClientTests.cs b/Test/Notion.UnitTests/PagesClientTests.cs index 9541f62e..4dc75380 100644 --- a/Test/Notion.UnitTests/PagesClientTests.cs +++ b/Test/Notion.UnitTests/PagesClientTests.cs @@ -222,7 +222,7 @@ public async Task TrashPageAsync() page.Id.Should().Be(pageId); page.InTrash.Should().BeTrue(); - page.Properties.Should().HaveCount(2); + page.Properties.Should().HaveCount(3); var updatedProperty = page.Properties.First(x => x.Key == "In stock"); var checkboxPropertyValue = (CheckboxPropertyItem)await _client.RetrievePagePropertyItemAsync( diff --git a/Test/Notion.UnitTests/PropertyTests.cs b/Test/Notion.UnitTests/PropertyTests.cs index fc748413..55f6d1c1 100644 --- a/Test/Notion.UnitTests/PropertyTests.cs +++ b/Test/Notion.UnitTests/PropertyTests.cs @@ -27,6 +27,7 @@ public class PropertyTests [InlineData(typeof(TitleProperty), PropertyType.Title)] [InlineData(typeof(UrlProperty), PropertyType.Url)] [InlineData(typeof(UniqueIdProperty), PropertyType.UniqueId)] + [InlineData(typeof(ButtonProperty),PropertyType.Button)] public void TestPropertyType(Type type, PropertyType expectedPropertyType) { var typeInstance = (Property)Activator.CreateInstance(type); @@ -56,6 +57,7 @@ public void TestPropertyType(Type type, PropertyType expectedPropertyType) [InlineData(typeof(TitleProperty), "title")] [InlineData(typeof(UrlProperty), "url")] [InlineData(typeof(UniqueIdProperty), "unique_id")] + [InlineData(typeof(ButtonProperty), "button")] public void TestPropertyTypeText(Type type, string expectedPropertyType) { var typeInstance = (Property)Activator.CreateInstance(type); diff --git a/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json b/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json index 5849bb88..9e1acfb0 100644 --- a/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json +++ b/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json @@ -90,6 +90,12 @@ } } }, + "SimpleButton": { + "id":"_ri%7C", + "name":"SimpleButton", + "type":"button", + "button": {} + }, "Name": { "id": "title", "name": "Name", diff --git a/Test/Notion.UnitTests/data/databases/DatabasesListResponse.json b/Test/Notion.UnitTests/data/databases/DatabasesListResponse.json index 713c0736..ad0e5497 100644 --- a/Test/Notion.UnitTests/data/databases/DatabasesListResponse.json +++ b/Test/Notion.UnitTests/data/databases/DatabasesListResponse.json @@ -81,6 +81,12 @@ } } }, + "SimpleButton": { + "id":"_ri%7C", + "name":"SimpleButton", + "type":"button", + "button": {} + }, "Name": { "id": "title", "name": "Name", diff --git a/Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json b/Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json index cf1b1f01..d291a5b2 100644 --- a/Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json +++ b/Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json @@ -45,6 +45,11 @@ "id": "{>U;", "type": "checkbox", "checkbox": false + }, + "Add Page Button": { + "id":"_ri%7C", + "type":"button", + "button": {} } } } diff --git a/Test/Notion.UnitTests/data/pages/TrashPageResponse.json b/Test/Notion.UnitTests/data/pages/TrashPageResponse.json index 0c61a3c9..add1f546 100644 --- a/Test/Notion.UnitTests/data/pages/TrashPageResponse.json +++ b/Test/Notion.UnitTests/data/pages/TrashPageResponse.json @@ -11,6 +11,11 @@ "type": "checkbox", "checkbox": true }, + "Add Page Button": { + "id":"_ri%7C", + "type":"button", + "button": {} + }, "Name": { "id": "title", "type": "title", From 0459c906c0c4f92fec3da8da930cdc74f9c81f44 Mon Sep 17 00:00:00 2001 From: kosaku-hayashi Date: Tue, 16 Jul 2024 14:28:46 +0900 Subject: [PATCH 54/89] Support "bad_gateway" error code --- Src/Notion.Client/NotionAPIErrorCode.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Src/Notion.Client/NotionAPIErrorCode.cs b/Src/Notion.Client/NotionAPIErrorCode.cs index e0264ae7..260c25b5 100644 --- a/Src/Notion.Client/NotionAPIErrorCode.cs +++ b/Src/Notion.Client/NotionAPIErrorCode.cs @@ -42,6 +42,9 @@ public enum NotionAPIErrorCode [EnumMember(Value = "internal_server_error")] InternalServerError, + [EnumMember(Value = "bad_gateway")] + BadGateway, + [EnumMember(Value = "service_unavailable")] ServiceUnavailable, From 54f5fd32330b903afff7cc65eeecd51832e060e6 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Wed, 30 Oct 2024 12:28:05 +0530 Subject: [PATCH 55/89] Use DateTimeOffset instead of DateTime for DatePropertyValue --- .../Models/PropertyValue/DatePropertyValue.cs | 7 ++- .../PageClientTests.cs | 61 ++++++++++++++++++- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs index 22715b2e..7467936b 100644 --- a/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs @@ -1,5 +1,6 @@ using System; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace Notion.Client { @@ -26,13 +27,15 @@ public class Date /// Start date with optional time. /// [JsonProperty("start")] - public DateTime? Start { get; set; } + [JsonConverter(typeof(IsoDateTimeConverter))] + public DateTimeOffset? Start { get; set; } /// /// End date with optional time. /// [JsonProperty("end")] - public DateTime? End { get; set; } + [JsonConverter(typeof(IsoDateTimeConverter))] + public DateTimeOffset? End { get; set; } /// /// Optional time zone information for start and end. Possible values are extracted from the IANA database and they are diff --git a/Test/Notion.IntegrationTests/PageClientTests.cs b/Test/Notion.IntegrationTests/PageClientTests.cs index 21adbd5b..31678d73 100644 --- a/Test/Notion.IntegrationTests/PageClientTests.cs +++ b/Test/Notion.IntegrationTests/PageClientTests.cs @@ -216,8 +216,8 @@ public async Task Test_UpdatePageProperty_with_date_as_null() { Date = new Date { - Start = Convert.ToDateTime("2020-12-08T12:00:00Z"), - End = Convert.ToDateTime("2025-12-08T12:00:00Z") + Start = DateTimeOffset.Parse("2024-06-26T00:00:00.000+01:00"), + End = DateTimeOffset.Parse("2025-12-08").Date } }) .Build(); @@ -236,7 +236,8 @@ public async Task Test_UpdatePageProperty_with_date_as_null() ); // Assert - setDate?.Date?.Start.Should().Be(Convert.ToDateTime("2020-12-08T12:00:00Z")); + setDate?.Date?.Start.Should().Be(DateTimeOffset.Parse("2024-06-26T00:00:00.000+01:00")); + setDate?.Date?.End.Should().Be(DateTimeOffset.Parse("2025-12-08T00:00:00.000+01:00")); var pageUpdateParameters = new PagesUpdateParameters { @@ -384,4 +385,58 @@ public async Task Bug_exception_when_attempting_to_set_select_property_to_nothin updatedPage.Properties["Colors1"].As().Select.Name.Should().Be("Blue"); updatedPage.Properties["Colors2"].As().Select.Should().BeNull(); } + + [Fact] + public async Task Verify_date_property_is_parsed_correctly_in_mention_object() + { + var pageRequest = PagesCreateParametersBuilder + .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .AddProperty("Name", + new TitlePropertyValue + { + Title = new List + { + new RichTextMention() + { + Mention = new Mention() + { + Page = new ObjectId() + { + Id = _page.Id, + }, + Date = new DatePropertyValue() + { + Date = new Date() + { + Start = DateTime.UtcNow + } + } + } + } + } + }) + .Build(); + + var page = await Client.Pages.CreateAsync(pageRequest); + + page.Should().NotBeNull(); + + page.Parent.Should().BeOfType().Which + .DatabaseId.Should().Be(_database.Id); + + page.Properties.Should().ContainKey("Name"); + var pageProperty = page.Properties["Name"].Should().BeOfType().Subject; + + var titleProperty = (ListPropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( + new RetrievePropertyItemParameters + { + PageId = page.Id, + PropertyId = pageProperty.Id + }); + + titleProperty.Results.First() + .As() + .Title.As() + .Mention.Date.Date.Should().NotBeNull(); + } } From 8fc28489095a964fe306228bd780640b8c973a95 Mon Sep 17 00:00:00 2001 From: Marian Zagoruiko Date: Mon, 13 Jan 2025 12:59:57 +0200 Subject: [PATCH 56/89] fix: allow setting properties to null --- .gitignore | 2 ++ Src/Notion.Client/Models/PropertyValue/EmailPropertyValue.cs | 2 +- Src/Notion.Client/Models/PropertyValue/NumberPropertyValue.cs | 2 +- .../Models/PropertyValue/PhoneNumberPropertyValue.cs | 2 +- Src/Notion.Client/Models/PropertyValue/StatusPropertyValue.cs | 2 +- Src/Notion.Client/Models/PropertyValue/UrlPropertyValue.cs | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index c6d337c2..5072687a 100644 --- a/.gitignore +++ b/.gitignore @@ -354,3 +354,5 @@ MigrationBackup/ # Rider .idea/ + +.DS_Store diff --git a/Src/Notion.Client/Models/PropertyValue/EmailPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/EmailPropertyValue.cs index 5a8e2c7a..a8ac4806 100644 --- a/Src/Notion.Client/Models/PropertyValue/EmailPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/EmailPropertyValue.cs @@ -12,7 +12,7 @@ public class EmailPropertyValue : PropertyValue /// /// Describes an email address. /// - [JsonProperty("email")] + [JsonProperty("email", NullValueHandling = NullValueHandling.Include)] public string Email { get; set; } } } diff --git a/Src/Notion.Client/Models/PropertyValue/NumberPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/NumberPropertyValue.cs index 15f9c768..a709e4f5 100644 --- a/Src/Notion.Client/Models/PropertyValue/NumberPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/NumberPropertyValue.cs @@ -12,7 +12,7 @@ public class NumberPropertyValue : PropertyValue /// /// Value of number /// - [JsonProperty("number")] + [JsonProperty("number", NullValueHandling = NullValueHandling.Include)] public double? Number { get; set; } } } diff --git a/Src/Notion.Client/Models/PropertyValue/PhoneNumberPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/PhoneNumberPropertyValue.cs index 79a24dac..f7c37a19 100644 --- a/Src/Notion.Client/Models/PropertyValue/PhoneNumberPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/PhoneNumberPropertyValue.cs @@ -12,7 +12,7 @@ public class PhoneNumberPropertyValue : PropertyValue /// /// Phone number value /// - [JsonProperty("phone_number")] + [JsonProperty("phone_number", NullValueHandling = NullValueHandling.Include)] public string PhoneNumber { get; set; } } } diff --git a/Src/Notion.Client/Models/PropertyValue/StatusPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/StatusPropertyValue.cs index 29a64ef7..921ff810 100644 --- a/Src/Notion.Client/Models/PropertyValue/StatusPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/StatusPropertyValue.cs @@ -47,7 +47,7 @@ public enum StatusColor public override PropertyValueType Type => PropertyValueType.Status; - [JsonProperty("status")] + [JsonProperty("status", NullValueHandling = NullValueHandling.Include)] public Data Status { get; set; } public class Data diff --git a/Src/Notion.Client/Models/PropertyValue/UrlPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/UrlPropertyValue.cs index 5fc8f8bb..91b5f71c 100644 --- a/Src/Notion.Client/Models/PropertyValue/UrlPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/UrlPropertyValue.cs @@ -12,7 +12,7 @@ public class UrlPropertyValue : PropertyValue /// /// Describes a web address /// - [JsonProperty("url")] + [JsonProperty("url", NullValueHandling = NullValueHandling.Include)] public string Url { get; set; } } } From 34ecf9d7f706a53f453be34ddb9ccfb44b4a3b7f Mon Sep 17 00:00:00 2001 From: Gehongyan Date: Sat, 22 Feb 2025 11:22:16 +0800 Subject: [PATCH 57/89] Add UpdateDatabaseRelationProperties Test --- .../DatabasesClientTests.cs | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs index 31b611f1..d5278519 100644 --- a/Test/Notion.IntegrationTests/DatabasesClientTests.cs +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -29,7 +29,7 @@ public async Task DisposeAsync() public async Task QueryDatabase() { // Arrange - var createdDatabase = await CreateDatabaseWithAPageAsync(); + var createdDatabase = await CreateDatabaseWithAPageAsync("Test List"); // Act var response = await Client.Databases.QueryAsync(createdDatabase.Id, new DatabasesQueryParameters()); @@ -43,7 +43,64 @@ public async Task QueryDatabase() .Text.Content.Should().Be("Test Title"); } - private async Task CreateDatabaseWithAPageAsync() + [Fact] + public async Task UpdateDatabaseRelationProperties() + { + // Arrange + var createdSourceDatabase = await CreateDatabaseWithAPageAsync("Test Relation Source"); + var createdDestinationDatabase = await CreateDatabaseWithAPageAsync("Test Relation Destination"); + + // Act + var response = await Client.Databases.UpdateAsync(createdDestinationDatabase.Id, + new DatabasesUpdateParameters + { + Properties = new Dictionary + { + { + "Single Relation", + new RelationUpdatePropertySchema + { + Relation = new SinglePropertyRelation + { + DatabaseId = createdSourceDatabase.Id, + SingleProperty = new Dictionary() + } + } + }, + { + "Dual Relation", + new RelationUpdatePropertySchema + { + Relation = new DualPropertyRelation + { + DatabaseId = createdSourceDatabase.Id, + DualProperty = new DualPropertyRelation.Data() + } + } + } + } + }); + + // Assert + response.Properties.Should().NotBeNull(); + + response.Properties.Should().ContainKey("Single Relation"); + var singleRelation = response.Properties["Single Relation"].As().Relation; + singleRelation.Should().BeEquivalentTo( + new SinglePropertyRelation + { + DatabaseId = createdSourceDatabase.Id, + SingleProperty = new Dictionary() + }); + + response.Properties.Should().ContainKey("Dual Relation"); + var dualRelation = response.Properties["Dual Relation"].As().Relation; + dualRelation.DatabaseId.Should().Be(createdSourceDatabase.Id); + dualRelation.Type.Should().Be(RelationType.Dual); + dualRelation.Should().BeOfType(); + } + + private async Task CreateDatabaseWithAPageAsync(string databaseName) { var createDbRequest = new DatabasesCreateParameters { @@ -53,7 +110,7 @@ private async Task CreateDatabaseWithAPageAsync() { Text = new Text { - Content = "Test List", + Content = databaseName, Link = null } } From cff7585c8aac2e09aacb66ccbfe306ba5f71bf03 Mon Sep 17 00:00:00 2001 From: Marian Zagoruiko Date: Wed, 15 Jan 2025 13:50:27 +0200 Subject: [PATCH 58/89] feat: include time option for dates --- .../Models/PropertyValue/DatePropertyValue.cs | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs index 7467936b..7d785212 100644 --- a/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs @@ -21,6 +21,7 @@ public class DatePropertyValue : PropertyValue /// /// Date value object. /// + [JsonConverter(typeof(DateCustomConverter))] public class Date { /// @@ -43,5 +44,94 @@ public class Date /// [JsonProperty("time_zone")] public string TimeZone { get; set; } + + /// + /// Whether to include time + /// + public bool IncludeTime { get; set; } = true; + } + + public class DateJsonObject + { + [JsonProperty("start")] + public string Start { get; set; } + + [JsonProperty("end")] + public string End { get; set; } + + [JsonProperty("time_zone")] + public string TimeZone { get; set; } + } + + public class DateCustomConverter : JsonConverter + { + public override Date ReadJson(JsonReader reader, Type objectType, Date existingValue, bool hasExistingValue, + JsonSerializer serializer) + { + var jsonObject = serializer.Deserialize(reader); + + if (jsonObject == null) + { + return null; + } + + var date = new Date + { + Start = ParseDateTime(jsonObject.Start, out bool includeTime), + End = ParseDateTime(jsonObject.End, out _), + TimeZone = jsonObject.TimeZone, + IncludeTime = includeTime, + }; + + return date; + } + + public override void WriteJson(JsonWriter writer, Date value, JsonSerializer serializer) + { + if (value is null) + { + writer.WriteNull(); + + return; + } + + writer.WriteStartObject(); + + if (value.Start.HasValue) + { + string startFormat = value.IncludeTime ? "yyyy-MM-ddTHH:mm:ss" : "yyyy-MM-dd"; + writer.WritePropertyName("start"); + writer.WriteValue(value.Start.Value.ToString(startFormat)); + } + + if (value.End.HasValue) + { + string endFormat = value.IncludeTime ? "yyyy-MM-ddTHH:mm:ss" : "yyyy-MM-dd"; + writer.WritePropertyName("end"); + writer.WriteValue(value.End.Value.ToString(endFormat)); + } + + if (!string.IsNullOrEmpty(value.TimeZone)) + { + writer.WritePropertyName("time_zone"); + writer.WriteValue(value.TimeZone); + } + + writer.WriteEndObject(); + } + + private static DateTime? ParseDateTime(string dateTimeString, out bool includeTime) + { + includeTime = false; + + if (string.IsNullOrEmpty(dateTimeString)) + { + return null; + } + + includeTime = dateTimeString.Contains("T") || dateTimeString.Contains(" "); + + return DateTimeOffset.Parse(dateTimeString).UtcDateTime; + } } } From f41327e34abf0529a18006581580ec7005738f03 Mon Sep 17 00:00:00 2001 From: Marian Zagoruiko Date: Fri, 17 Jan 2025 18:10:12 +0200 Subject: [PATCH 59/89] feat: rollup date parsing --- Src/Notion.Client/Models/PropertyValue/RollupPropertyValue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Notion.Client/Models/PropertyValue/RollupPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/RollupPropertyValue.cs index 2eb104fb..92020c61 100644 --- a/Src/Notion.Client/Models/PropertyValue/RollupPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/RollupPropertyValue.cs @@ -35,7 +35,7 @@ public class RollupValue /// Date rollup property values contain a date property value. /// [JsonProperty("date")] - public DatePropertyValue Date { get; set; } + public Date Date { get; set; } /// /// Array rollup property values contain an array of element objects. From 954c042c057a0c6fc5b3a2debad938fb40424f37 Mon Sep 17 00:00:00 2001 From: Marian Zagoruiko Date: Fri, 28 Mar 2025 10:06:16 +0200 Subject: [PATCH 60/89] fix: custom emoji support --- Src/Notion.Client/Models/CustomEmoji.cs | 16 ++++++++++++++++ Src/Notion.Client/Models/CustomEmojiObject.cs | 13 +++++++++++++ Src/Notion.Client/Models/Page/IPageIcon.cs | 1 + 3 files changed, 30 insertions(+) create mode 100644 Src/Notion.Client/Models/CustomEmoji.cs create mode 100644 Src/Notion.Client/Models/CustomEmojiObject.cs diff --git a/Src/Notion.Client/Models/CustomEmoji.cs b/Src/Notion.Client/Models/CustomEmoji.cs new file mode 100644 index 00000000..0f7a4c48 --- /dev/null +++ b/Src/Notion.Client/Models/CustomEmoji.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CustomEmoji + { + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("url")] + public string Url { get; set; } + } +} diff --git a/Src/Notion.Client/Models/CustomEmojiObject.cs b/Src/Notion.Client/Models/CustomEmojiObject.cs new file mode 100644 index 00000000..1faa4d74 --- /dev/null +++ b/Src/Notion.Client/Models/CustomEmojiObject.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CustomEmojiObject : IPageIcon + { + [JsonProperty("custom_emoji")] + public CustomEmoji CustomEmoji { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Page/IPageIcon.cs b/Src/Notion.Client/Models/Page/IPageIcon.cs index b9ebea56..5d692185 100644 --- a/Src/Notion.Client/Models/Page/IPageIcon.cs +++ b/Src/Notion.Client/Models/Page/IPageIcon.cs @@ -5,6 +5,7 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] [JsonSubtypes.KnownSubTypeAttribute(typeof(EmojiObject), "emoji")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CustomEmojiObject), "custom_emoji")] [JsonSubtypes.KnownSubTypeAttribute(typeof(FileObject), "file")] [JsonSubtypes.KnownSubTypeAttribute(typeof(FileObject), "external")] public interface IPageIcon From 8ee7f0fd923e55406aa88a12bdd94409c8bf2c3e Mon Sep 17 00:00:00 2001 From: Marian Zagoruiko Date: Fri, 28 Mar 2025 10:28:28 +0200 Subject: [PATCH 61/89] fix: linter --- .../PropertyValue/DateCustomConverter.cs | 77 +++++++++++++++++ .../Models/PropertyValue/DateJsonObject.cs | 16 ++++ .../Models/PropertyValue/DatePropertyValue.cs | 84 ------------------- 3 files changed, 93 insertions(+), 84 deletions(-) create mode 100644 Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs create mode 100644 Src/Notion.Client/Models/PropertyValue/DateJsonObject.cs diff --git a/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs new file mode 100644 index 00000000..6823c303 --- /dev/null +++ b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs @@ -0,0 +1,77 @@ +using System; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DateCustomConverter : JsonConverter + { + public override Date ReadJson(JsonReader reader, Type objectType, Date existingValue, bool hasExistingValue, + JsonSerializer serializer) + { + var jsonObject = serializer.Deserialize(reader); + + if (jsonObject == null) + { + return null; + } + + var date = new Date + { + Start = ParseDateTime(jsonObject.Start, out bool includeTime), + End = ParseDateTime(jsonObject.End, out _), + TimeZone = jsonObject.TimeZone, + IncludeTime = includeTime, + }; + + return date; + } + + public override void WriteJson(JsonWriter writer, Date value, JsonSerializer serializer) + { + if (value is null) + { + writer.WriteNull(); + + return; + } + + writer.WriteStartObject(); + + if (value.Start.HasValue) + { + string startFormat = value.IncludeTime ? "yyyy-MM-ddTHH:mm:ss" : "yyyy-MM-dd"; + writer.WritePropertyName("start"); + writer.WriteValue(value.Start.Value.ToString(startFormat)); + } + + if (value.End.HasValue) + { + string endFormat = value.IncludeTime ? "yyyy-MM-ddTHH:mm:ss" : "yyyy-MM-dd"; + writer.WritePropertyName("end"); + writer.WriteValue(value.End.Value.ToString(endFormat)); + } + + if (!string.IsNullOrEmpty(value.TimeZone)) + { + writer.WritePropertyName("time_zone"); + writer.WriteValue(value.TimeZone); + } + + writer.WriteEndObject(); + } + + private static DateTime? ParseDateTime(string dateTimeString, out bool includeTime) + { + includeTime = false; + + if (string.IsNullOrEmpty(dateTimeString)) + { + return null; + } + + includeTime = dateTimeString.Contains("T") || dateTimeString.Contains(" "); + + return DateTimeOffset.Parse(dateTimeString).UtcDateTime; + } + } +} diff --git a/Src/Notion.Client/Models/PropertyValue/DateJsonObject.cs b/Src/Notion.Client/Models/PropertyValue/DateJsonObject.cs new file mode 100644 index 00000000..b33b58c7 --- /dev/null +++ b/Src/Notion.Client/Models/PropertyValue/DateJsonObject.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + internal class DateJsonObject + { + [JsonProperty("start")] + public string Start { get; set; } + + [JsonProperty("end")] + public string End { get; set; } + + [JsonProperty("time_zone")] + public string TimeZone { get; set; } + } +} diff --git a/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs index 7d785212..b79707db 100644 --- a/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs @@ -50,88 +50,4 @@ public class Date /// public bool IncludeTime { get; set; } = true; } - - public class DateJsonObject - { - [JsonProperty("start")] - public string Start { get; set; } - - [JsonProperty("end")] - public string End { get; set; } - - [JsonProperty("time_zone")] - public string TimeZone { get; set; } - } - - public class DateCustomConverter : JsonConverter - { - public override Date ReadJson(JsonReader reader, Type objectType, Date existingValue, bool hasExistingValue, - JsonSerializer serializer) - { - var jsonObject = serializer.Deserialize(reader); - - if (jsonObject == null) - { - return null; - } - - var date = new Date - { - Start = ParseDateTime(jsonObject.Start, out bool includeTime), - End = ParseDateTime(jsonObject.End, out _), - TimeZone = jsonObject.TimeZone, - IncludeTime = includeTime, - }; - - return date; - } - - public override void WriteJson(JsonWriter writer, Date value, JsonSerializer serializer) - { - if (value is null) - { - writer.WriteNull(); - - return; - } - - writer.WriteStartObject(); - - if (value.Start.HasValue) - { - string startFormat = value.IncludeTime ? "yyyy-MM-ddTHH:mm:ss" : "yyyy-MM-dd"; - writer.WritePropertyName("start"); - writer.WriteValue(value.Start.Value.ToString(startFormat)); - } - - if (value.End.HasValue) - { - string endFormat = value.IncludeTime ? "yyyy-MM-ddTHH:mm:ss" : "yyyy-MM-dd"; - writer.WritePropertyName("end"); - writer.WriteValue(value.End.Value.ToString(endFormat)); - } - - if (!string.IsNullOrEmpty(value.TimeZone)) - { - writer.WritePropertyName("time_zone"); - writer.WriteValue(value.TimeZone); - } - - writer.WriteEndObject(); - } - - private static DateTime? ParseDateTime(string dateTimeString, out bool includeTime) - { - includeTime = false; - - if (string.IsNullOrEmpty(dateTimeString)) - { - return null; - } - - includeTime = dateTimeString.Contains("T") || dateTimeString.Contains(" "); - - return DateTimeOffset.Parse(dateTimeString).UtcDateTime; - } - } } From 80d32df3b95035d044d62a73bf23184d1035633c Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 12 Apr 2025 17:14:04 +0530 Subject: [PATCH 62/89] 431: Throw error if database id was not provided --- Src/Notion.Client/Api/Databases/DatabasesClient.cs | 8 +++++++- Test/Notion.UnitTests/DatabasesClientTests.cs | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Src/Notion.Client/Api/Databases/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/DatabasesClient.cs index 673ee122..a3dc9a8c 100644 --- a/Src/Notion.Client/Api/Databases/DatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/DatabasesClient.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; @@ -15,6 +16,11 @@ public DatabasesClient(IRestClient client) public async Task RetrieveAsync(string databaseId, CancellationToken cancellationToken = default) { + if (string.IsNullOrWhiteSpace(databaseId)) + { + throw new ArgumentNullException(nameof(databaseId)); + } + return await _client.GetAsync(DatabasesApiUrls.Retrieve(databaseId), cancellationToken: cancellationToken); } diff --git a/Test/Notion.UnitTests/DatabasesClientTests.cs b/Test/Notion.UnitTests/DatabasesClientTests.cs index 3bd047a7..1edbc2ed 100644 --- a/Test/Notion.UnitTests/DatabasesClientTests.cs +++ b/Test/Notion.UnitTests/DatabasesClientTests.cs @@ -504,4 +504,18 @@ var jsonData formulaPropertyValue.Formula.Date.End.Should().BeNull(); } } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public async Task RetrieveAsync_throws_argument_null_exception_if_database_id_is_null_or_empty(string databaseId) + { + // Arrange && Act + async Task Act() => await _client.RetrieveAsync(databaseId); + + // Assert + var exception = await Assert.ThrowsAsync(Act); + Assert.Equal("databaseId", exception.ParamName); + } } From 4836c4b863b43a767f686add471387b5b9b32c61 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 12 Apr 2025 23:52:00 +0530 Subject: [PATCH 63/89] fix: enhance DateCustomSerializer and add tests * use ISO 8601 date and time format * fix breaking test --- .../PropertyValue/DateCustomConverter.cs | 9 +- Test/Notion.UnitTests/DatabasesClientTests.cs | 2 +- .../DateCustomConverterTests.cs | 219 ++++++++++++++++++ 3 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 Test/Notion.UnitTests/DateCustomConverterTests.cs diff --git a/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs index 6823c303..d4af88f4 100644 --- a/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs +++ b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs @@ -5,6 +5,9 @@ namespace Notion.Client { public class DateCustomConverter : JsonConverter { + private const string DateFormat = "yyyy-MM-dd"; + private const string DateTimeFormat = "yyyy-MM-ddTHH:mm:ssZ"; + public override Date ReadJson(JsonReader reader, Type objectType, Date existingValue, bool hasExistingValue, JsonSerializer serializer) { @@ -39,14 +42,14 @@ public override void WriteJson(JsonWriter writer, Date value, JsonSerializer ser if (value.Start.HasValue) { - string startFormat = value.IncludeTime ? "yyyy-MM-ddTHH:mm:ss" : "yyyy-MM-dd"; + string startFormat = value.IncludeTime ? DateTimeFormat : DateFormat; writer.WritePropertyName("start"); writer.WriteValue(value.Start.Value.ToString(startFormat)); } if (value.End.HasValue) { - string endFormat = value.IncludeTime ? "yyyy-MM-ddTHH:mm:ss" : "yyyy-MM-dd"; + string endFormat = value.IncludeTime ? DateTimeFormat : DateFormat; writer.WritePropertyName("end"); writer.WriteValue(value.End.Value.ToString(endFormat)); } @@ -71,7 +74,7 @@ public override void WriteJson(JsonWriter writer, Date value, JsonSerializer ser includeTime = dateTimeString.Contains("T") || dateTimeString.Contains(" "); - return DateTimeOffset.Parse(dateTimeString).UtcDateTime; + return DateTimeOffset.Parse(dateTimeString, null, System.Globalization.DateTimeStyles.AssumeUniversal).UtcDateTime; } } } diff --git a/Test/Notion.UnitTests/DatabasesClientTests.cs b/Test/Notion.UnitTests/DatabasesClientTests.cs index 1edbc2ed..30deae75 100644 --- a/Test/Notion.UnitTests/DatabasesClientTests.cs +++ b/Test/Notion.UnitTests/DatabasesClientTests.cs @@ -500,7 +500,7 @@ var jsonData }); //var formulaPropertyValue = (FormulaPropertyValue)page.Properties["FormulaProp"]; - formulaPropertyValue.Formula.Date.Start.Should().Be(DateTime.Parse("2021-06-28")); + formulaPropertyValue.Formula.Date.Start.Should().Be(DateTimeOffset.Parse("2021-06-28", null, System.Globalization.DateTimeStyles.AssumeUniversal).UtcDateTime); formulaPropertyValue.Formula.Date.End.Should().BeNull(); } } diff --git a/Test/Notion.UnitTests/DateCustomConverterTests.cs b/Test/Notion.UnitTests/DateCustomConverterTests.cs new file mode 100644 index 00000000..81c33f57 --- /dev/null +++ b/Test/Notion.UnitTests/DateCustomConverterTests.cs @@ -0,0 +1,219 @@ +using System; +using System.IO; +using Newtonsoft.Json; +using Notion.Client; +using Xunit; + +namespace NotionUnitTests.PropertyValue; + +public class DateCustomConverterTests +{ + private readonly DateCustomConverter _converter = new(); + private readonly JsonSerializer _serializer = new(); + + [Fact] + public void Serialize_null_writes_null() + { + // Arrange + Date date = null; + var stringWriter = new StringWriter(); + var jsonWriter = new JsonTextWriter(stringWriter); + + // Act + _converter.WriteJson(jsonWriter, date, _serializer); + jsonWriter.Flush(); + + // Assert + Assert.Equal("null", stringWriter.ToString()); + } + + [Fact] + public void Serialize_start_date_only_produces_correct_json() + { + // Arrange + var date = new Date + { + Start = new DateTimeOffset(2023, 5, 15, 0, 0, 0, TimeSpan.Zero), + IncludeTime = false + }; + + // Act + var json = JsonConvert.SerializeObject(date); + + // Assert + Assert.Contains("\"start\":\"2023-05-15\"", json); + Assert.DoesNotContain("\"end\":", json); + Assert.DoesNotContain("\"time_zone\":", json); + } + + [Fact] + public void Serialize_start_and_end_dates_produces_correct_json() + { + // Arrange + var date = new Date + { + Start = new DateTimeOffset(2023, 5, 15, 0, 0, 0, TimeSpan.Zero), + End = new DateTimeOffset(2023, 5, 20, 0, 0, 0, TimeSpan.Zero), + IncludeTime = false + }; + + // Act + var json = JsonConvert.SerializeObject(date); + + // Assert + Assert.Contains("\"start\":\"2023-05-15\"", json); + Assert.Contains("\"end\":\"2023-05-20\"", json); + Assert.DoesNotContain("\"time_zone\":", json); + } + + [Fact] + public void Serialize_with_time_included_formats_time_correctly() + { + // Arrange + var date = new Date + { + Start = new DateTimeOffset(2023, 5, 15, 14, 30, 45, TimeSpan.Zero), + IncludeTime = true + }; + + // Act + var json = JsonConvert.SerializeObject(date); + + // Assert + Assert.Contains("\"start\":\"2023-05-15T14:30:45Z\"", json); + } + + [Fact] + public void Serialize_with_time_zone_includes_time_zone() + { + // Arrange + var date = new Date + { + Start = new DateTimeOffset(2023, 5, 15, 14, 30, 45, TimeSpan.Zero), + TimeZone = "Europe/London", + IncludeTime = true + }; + + // Act + var json = JsonConvert.SerializeObject(date); + + // Assert + Assert.Contains("\"start\":\"2023-05-15T14:30:45Z\"", json); + Assert.Contains("\"time_zone\":\"Europe/London\"", json); + } + + [Fact] + public void Deserialize_null_returns_null() + { + // Arrange + const string Json = "null"; + + // Act + var result = JsonConvert.DeserializeObject(Json); + + // Assert + Assert.Null(result); + } + + [Fact] + public void Deserialize_start_date_only_returns_correct_date() + { + // Arrange + const string Json = "{\"start\":\"2023-05-15\"}"; + + // Act + var result = JsonConvert.DeserializeObject(Json); + + // Assert + Assert.NotNull(result); + Assert.Equal(new DateTimeOffset(2023, 5, 15, 0, 0, 0, TimeSpan.Zero), result.Start); + Assert.Null(result.End); + Assert.Null(result.TimeZone); + Assert.False(result.IncludeTime); + } + + [Fact] + public void Deserialize_with_time_sets_include_time_flag() + { + // Arrange + const string Json = "{\"start\":\"2023-05-15T14:30:45\"}"; + + // Act + var result = JsonConvert.DeserializeObject(Json); + + // Assert + Assert.NotNull(result); + Assert.Equal(new DateTimeOffset(2023, 5, 15, 14, 30, 45, TimeSpan.Zero), result.Start); + Assert.True(result.IncludeTime); + } + + [Fact] + public void Deserialize_with_start_end_and_time_zone_returns_complete_date() + { + // Arrange + const string Json = "{\"start\":\"2023-05-15T14:30:45\",\"end\":\"2023-05-20T16:45:00\",\"time_zone\":\"America/New_York\"}"; + + // Act + var result = JsonConvert.DeserializeObject(Json); + + // Assert + Assert.NotNull(result); + Assert.Equal(new DateTimeOffset(2023, 5, 15, 14, 30, 45, TimeSpan.Zero), result.Start); + Assert.Equal(new DateTimeOffset(2023, 5, 20, 16, 45, 0, TimeSpan.Zero), result.End); + Assert.Equal("America/New_York", result.TimeZone); + Assert.True(result.IncludeTime); + } + + [Fact] + public void Date_property_value_serialize_deserialize_maintains_data() + { + // Arrange + var datePropertyValue = new DatePropertyValue + { + Date = new Date + { + Start = new DateTimeOffset(2023, 5, 15, 14, 30, 45, TimeSpan.Zero), + End = new DateTimeOffset(2023, 5, 20, 16, 45, 0, TimeSpan.Zero), + TimeZone = "Europe/Berlin", + IncludeTime = true + } + }; + + // Act + var json = JsonConvert.SerializeObject(datePropertyValue); + var result = JsonConvert.DeserializeObject(json); + + // Assert + Assert.NotNull(result); + Assert.Equal(PropertyValueType.Date, result.Type); + Assert.NotNull(result.Date); + Assert.Equal(datePropertyValue.Date.Start, result.Date.Start); + Assert.Equal(datePropertyValue.Date.End, result.Date.End); + Assert.Equal(datePropertyValue.Date.TimeZone, result.Date.TimeZone); + Assert.Equal(datePropertyValue.Date.IncludeTime, result.Date.IncludeTime); + } + + [Fact] + public void Round_trip_preserves_data() + { + // Arrange + var originalDate = new Date + { + Start = new DateTimeOffset(2023, 5, 15, 14, 30, 45, TimeSpan.Zero), + End = new DateTimeOffset(2023, 5, 20, 16, 45, 0, TimeSpan.Zero), + TimeZone = "Europe/Berlin", + IncludeTime = true + }; + + // Act + var json = JsonConvert.SerializeObject(originalDate); + var deserializedDate = JsonConvert.DeserializeObject(json); + + // Assert + Assert.NotNull(deserializedDate); + Assert.Equal(originalDate.Start, deserializedDate.Start); + Assert.Equal(originalDate.End, deserializedDate.End); + Assert.Equal(originalDate.TimeZone, deserializedDate.TimeZone); + Assert.True(deserializedDate.IncludeTime); + } +} From 42d7e798f663cf8189f09c6b6444c4771d89b6c0 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 12 Apr 2025 23:52:36 +0530 Subject: [PATCH 64/89] add explicit JsonIgnore attribute to IncludeTime property in Date class --- Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs index b79707db..66f9c6b6 100644 --- a/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs @@ -48,6 +48,7 @@ public class Date /// /// Whether to include time /// + [JsonIgnore] public bool IncludeTime { get; set; } = true; } } From 48ee22a8f1afecc05a8ae24f4b0d932b06b4baa9 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 00:49:23 +0530 Subject: [PATCH 65/89] ensure culture-invariant date formatting in DateCustomConverter --- .../Models/PropertyValue/DateCustomConverter.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs index d4af88f4..78f14cdb 100644 --- a/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs +++ b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using Newtonsoft.Json; namespace Notion.Client @@ -44,14 +45,14 @@ public override void WriteJson(JsonWriter writer, Date value, JsonSerializer ser { string startFormat = value.IncludeTime ? DateTimeFormat : DateFormat; writer.WritePropertyName("start"); - writer.WriteValue(value.Start.Value.ToString(startFormat)); + writer.WriteValue(value.Start.Value.ToString(startFormat, CultureInfo.InvariantCulture)); } if (value.End.HasValue) { string endFormat = value.IncludeTime ? DateTimeFormat : DateFormat; writer.WritePropertyName("end"); - writer.WriteValue(value.End.Value.ToString(endFormat)); + writer.WriteValue(value.End.Value.ToString(endFormat, CultureInfo.InvariantCulture)); } if (!string.IsNullOrEmpty(value.TimeZone)) @@ -74,7 +75,7 @@ public override void WriteJson(JsonWriter writer, Date value, JsonSerializer ser includeTime = dateTimeString.Contains("T") || dateTimeString.Contains(" "); - return DateTimeOffset.Parse(dateTimeString, null, System.Globalization.DateTimeStyles.AssumeUniversal).UtcDateTime; + return DateTimeOffset.Parse(dateTimeString, null, DateTimeStyles.AssumeUniversal).UtcDateTime; } } } From 4e9c6bebae87b314724e72942fe6243125debb9d Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 01:09:13 +0530 Subject: [PATCH 66/89] Use CultureInfo.InvariantCulture in DateTimeOffset.Parse to ensure consistent parsing of ISO 8601 dates across different environments Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs index 78f14cdb..37b84bc5 100644 --- a/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs +++ b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs @@ -75,7 +75,7 @@ public override void WriteJson(JsonWriter writer, Date value, JsonSerializer ser includeTime = dateTimeString.Contains("T") || dateTimeString.Contains(" "); - return DateTimeOffset.Parse(dateTimeString, null, DateTimeStyles.AssumeUniversal).UtcDateTime; + return DateTimeOffset.Parse(dateTimeString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).UtcDateTime; } } } From 3ea8bc4541087ecd7d738a516aa05c4f73760322 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 00:36:28 +0530 Subject: [PATCH 67/89] fix: creation and parsing of Date Mentions --- .../DatabasesCreateParameters/MentionInput.cs | 2 +- .../Database/RichText/RichTextMention.cs | 2 +- .../DatabasesClientTests.cs | 47 ++++++++++++++++++- .../PageClientTests.cs | 20 +++----- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/MentionInput.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/MentionInput.cs index 83d1e699..48b34948 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/MentionInput.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/MentionInput.cs @@ -17,6 +17,6 @@ public class MentionInput public ObjectId Database { get; set; } [JsonProperty("date")] - public DatePropertyValue Date { get; set; } + public Date Date { get; set; } } } diff --git a/Src/Notion.Client/Models/Database/RichText/RichTextMention.cs b/Src/Notion.Client/Models/Database/RichText/RichTextMention.cs index 02f6beb0..5a5b6d0c 100644 --- a/Src/Notion.Client/Models/Database/RichText/RichTextMention.cs +++ b/Src/Notion.Client/Models/Database/RichText/RichTextMention.cs @@ -25,7 +25,7 @@ public class Mention public ObjectId Database { get; set; } [JsonProperty("date")] - public DatePropertyValue Date { get; set; } + public Date Date { get; set; } } public class ObjectId diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs index d5278519..7abd7b4e 100644 --- a/Test/Notion.IntegrationTests/DatabasesClientTests.cs +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using FluentAssertions; @@ -140,4 +141,48 @@ private async Task CreateDatabaseWithAPageAsync(string databaseName) return createdDatabase; } + + [Fact] + public async Task Verify_mention_date_property_parsed_properly() + { + // Arrange + var createDbRequest = new DatabasesCreateParameters + { + Title = new List + { + new RichTextTextInput + { + Text = new Text + { + Content = "Test DB", + Link = null + } + }, + new RichTextMentionInput + { + Mention = new MentionInput + { + Date = new Date + { + Start = DateTime.UtcNow, + End = DateTime.UtcNow.AddDays(1) + } + } + } + }, + Properties = new Dictionary + { + { "Name", new TitlePropertySchema { Title = new Dictionary() } }, + }, + Parent = new ParentPageInput { PageId = _page.Id } + }; + + // Act + var createdDatabase = await Client.Databases.CreateAsync(createDbRequest); + + // Assert + var mention = createdDatabase.Title.OfType().First().Mention; + mention.Date.Start.Should().NotBeNull(); + mention.Date.End.Should().NotBeNull(); + } } diff --git a/Test/Notion.IntegrationTests/PageClientTests.cs b/Test/Notion.IntegrationTests/PageClientTests.cs index 31678d73..4938bcfa 100644 --- a/Test/Notion.IntegrationTests/PageClientTests.cs +++ b/Test/Notion.IntegrationTests/PageClientTests.cs @@ -400,23 +400,16 @@ public async Task Verify_date_property_is_parsed_correctly_in_mention_object() { Mention = new Mention() { - Page = new ObjectId() + Date = new Date() { - Id = _page.Id, - }, - Date = new DatePropertyValue() - { - Date = new Date() - { - Start = DateTime.UtcNow - } + Start = DateTime.UtcNow } } } } }) .Build(); - + var page = await Client.Pages.CreateAsync(pageRequest); page.Should().NotBeNull(); @@ -434,9 +427,8 @@ public async Task Verify_date_property_is_parsed_correctly_in_mention_object() PropertyId = pageProperty.Id }); - titleProperty.Results.First() - .As() - .Title.As() - .Mention.Date.Date.Should().NotBeNull(); + var mention = titleProperty.Results.First().As().Title.As().Mention; + mention.Date.Start.Should().NotBeNull(); + mention.Date.End.Should().BeNull(); } } From ae94eb5209d16464d1a410cd3e486a9efa5dcc36 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 12:27:38 +0530 Subject: [PATCH 68/89] =?UTF-8?q?add=20support=20for=20reading=20and=20wri?= =?UTF-8?q?ting=20Name=20&=20Caption=20properties=20to=20file=20blocks=20?= =?UTF-8?q?=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../File/FIleInput/ExternalFileInput.cs | 7 ++- .../Models/File/FIleInput/IFileObjectInput.cs | 10 ++++- .../File/FIleInput/UploadedFileInput.cs | 5 +++ .../BlocksClientTests.cs | 45 +++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs b/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs index 9c258ceb..38ad781c 100644 --- a/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs +++ b/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using Newtonsoft.Json; namespace Notion.Client { @@ -7,6 +8,10 @@ public class ExternalFileInput : IFileObjectInput [JsonProperty("external")] public Data External { get; set; } + public string Name { get; set; } + + public IEnumerable Caption { get; set; } + public class Data { [JsonProperty("url")] diff --git a/Src/Notion.Client/Models/File/FIleInput/IFileObjectInput.cs b/Src/Notion.Client/Models/File/FIleInput/IFileObjectInput.cs index 31df1573..5883b7c1 100644 --- a/Src/Notion.Client/Models/File/FIleInput/IFileObjectInput.cs +++ b/Src/Notion.Client/Models/File/FIleInput/IFileObjectInput.cs @@ -1,6 +1,14 @@ -namespace Notion.Client +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client { public interface IFileObjectInput { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("caption")] + public IEnumerable Caption { get; set; } } } diff --git a/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs b/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs index 52d7934d..dabca4e1 100644 --- a/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs +++ b/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Newtonsoft.Json; namespace Notion.Client @@ -8,6 +9,10 @@ public class UploadedFileInput : IFileObjectInput [JsonProperty("file")] public Data File { get; set; } + public string Name { get; set; } + + public IEnumerable Caption { get; set; } + public class Data { [JsonProperty("url")] diff --git a/Test/Notion.IntegrationTests/BlocksClientTests.cs b/Test/Notion.IntegrationTests/BlocksClientTests.cs index 5c8e4618..d52b8f64 100644 --- a/Test/Notion.IntegrationTests/BlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/BlocksClientTests.cs @@ -399,6 +399,51 @@ private static IEnumerable BlockData() .Subject.Should().BeOfType() .Subject.Text.Content.Should().Be("Data"); }) + }, + new object[] + { + new FileBlockRequest { + File = new ExternalFile + { + Name = "Test file", + External = new ExternalFile.Info + { + Url = "https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg" + }, + Caption = new List + { + new RichTextTextInput { Text = new Text { Content = "Test file" } } + } + } + }, + new FileUpdateBlock + { + File = new ExternalFileInput + { + Name = "Test file name", + External = new ExternalFileInput.Data + { + Url = "https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg" + }, + Caption = new List + { + new RichTextTextInput { Text = new Text { Content = "Test file caption" } } + } + } + }, + new Action((block, client) => + { + var fileBlock = block.Should().NotBeNull().And.BeOfType().Subject; + fileBlock.HasChildren.Should().BeFalse(); + + var file = fileBlock.File.Should().NotBeNull().And.BeOfType().Subject; + file.Name.Should().Be("Test file name.jpg"); + file.External.Should().NotBeNull(); + file.External.Url.Should().Be("https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg"); + file.Caption.Should().NotBeNull().And.ContainSingle() + .Subject.Should().BeOfType().Subject + .Text.Content.Should().Be("Test file caption"); + }) } }; } From 4af4559095c8ad46d55bc5c3b94f82235fad23f9 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 14:15:44 +0530 Subject: [PATCH 69/89] adding a [JsonProperty("name")] attribute for the Name property to ensure consistent JSON serialization Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs b/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs index dabca4e1..31715b12 100644 --- a/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs +++ b/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs @@ -9,6 +9,7 @@ public class UploadedFileInput : IFileObjectInput [JsonProperty("file")] public Data File { get; set; } + [JsonProperty("name")] public string Name { get; set; } public IEnumerable Caption { get; set; } From 93ad9654a5555402bb8809fd1f970aebd343f370 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 14:16:33 +0530 Subject: [PATCH 70/89] add a [JsonProperty("caption")] attribute for the Caption property to ensure it serializes consistently with the interface Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs b/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs index 31715b12..949df10c 100644 --- a/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs +++ b/Src/Notion.Client/Models/File/FIleInput/UploadedFileInput.cs @@ -12,6 +12,7 @@ public class UploadedFileInput : IFileObjectInput [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("caption")] public IEnumerable Caption { get; set; } public class Data From dd4e517d51e6ee5f66575724fe83ba7d6a26dae0 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 14:16:56 +0530 Subject: [PATCH 71/89] add a [JsonProperty("name")] attribute here for consistency with the JSON contract Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs b/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs index 38ad781c..8a602d38 100644 --- a/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs +++ b/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs @@ -8,6 +8,7 @@ public class ExternalFileInput : IFileObjectInput [JsonProperty("external")] public Data External { get; set; } + [JsonProperty("name")] public string Name { get; set; } public IEnumerable Caption { get; set; } From 28d6b212dbd50513734bd0a68d87accf8a38cb2e Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 14:17:18 +0530 Subject: [PATCH 72/89] add a [JsonProperty("caption")] attribute to ensure proper serialization Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs b/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs index 8a602d38..6e2627cf 100644 --- a/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs +++ b/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs @@ -11,6 +11,7 @@ public class ExternalFileInput : IFileObjectInput [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("caption")] public IEnumerable Caption { get; set; } public class Data From dcd3d98d06e503829a6f8e949750419d6e63fe89 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 14:22:07 +0530 Subject: [PATCH 73/89] =?UTF-8?q?add=20a=20comment=20to=20clarify=20why=20?= =?UTF-8?q?the=20file=20name=20is=20expected=20to=20automatically=20have?= =?UTF-8?q?=20a=20'.jpg'=20or=20other=20file=20extension=F0=9F=92=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Notion.Client/Models/File/FileObject.cs | 3 +++ Test/Notion.IntegrationTests/BlocksClientTests.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Src/Notion.Client/Models/File/FileObject.cs b/Src/Notion.Client/Models/File/FileObject.cs index aa7aed1b..0ac30a6c 100644 --- a/Src/Notion.Client/Models/File/FileObject.cs +++ b/Src/Notion.Client/Models/File/FileObject.cs @@ -12,6 +12,9 @@ public abstract class FileObject : IPageIcon [JsonProperty("caption")] public IEnumerable Caption { get; set; } + /// + /// The name of the file block, as shown in the Notion UI. Note that the UI may auto-append .pdf or other extensions. + /// [JsonProperty("name")] public string Name { get; set; } diff --git a/Test/Notion.IntegrationTests/BlocksClientTests.cs b/Test/Notion.IntegrationTests/BlocksClientTests.cs index d52b8f64..5f1ca25b 100644 --- a/Test/Notion.IntegrationTests/BlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/BlocksClientTests.cs @@ -437,7 +437,10 @@ private static IEnumerable BlockData() fileBlock.HasChildren.Should().BeFalse(); var file = fileBlock.File.Should().NotBeNull().And.BeOfType().Subject; + + // NOTE: The name of the file block, as shown in the Notion UI. Note that the UI may auto-append .pdf or other extensions. file.Name.Should().Be("Test file name.jpg"); + file.External.Should().NotBeNull(); file.External.Url.Should().Be("https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg"); file.Caption.Should().NotBeNull().And.ContainSingle() From 19568ad2eb99b3f5eab0a8dbf76a1e7021f48acd Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 15:17:23 +0530 Subject: [PATCH 74/89] Create dependabot.yml --- .github/dependabot.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..331a95d5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "nuget" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + commit-message: + prefix: "deps" From 419bd1f55948a4a925da42a65174bcd80ffcb578 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 13 Apr 2025 09:59:31 +0000 Subject: [PATCH 75/89] deps: bump coverlet.collector from 1.3.0 to 6.0.4 Bumps [coverlet.collector](https://github.com/coverlet-coverage/coverlet) from 1.3.0 to 6.0.4. - [Release notes](https://github.com/coverlet-coverage/coverlet/releases) - [Commits](https://github.com/coverlet-coverage/coverlet/commits/v6.0.4) --- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 6.0.4 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Test/Notion.UnitTests/Notion.UnitTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/Notion.UnitTests/Notion.UnitTests.csproj b/Test/Notion.UnitTests/Notion.UnitTests.csproj index 588ddc54..60bbd3ff 100644 --- a/Test/Notion.UnitTests/Notion.UnitTests.csproj +++ b/Test/Notion.UnitTests/Notion.UnitTests.csproj @@ -16,7 +16,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 85ebe93d52b59557e520362695abc0e950b4d3eb Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 15:30:10 +0530 Subject: [PATCH 76/89] Bump version to 4.3.0 --- Src/Notion.Client/Notion.Client.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Notion.Client/Notion.Client.csproj b/Src/Notion.Client/Notion.Client.csproj index c7e96e08..3e353339 100644 --- a/Src/Notion.Client/Notion.Client.csproj +++ b/Src/Notion.Client/Notion.Client.csproj @@ -1,7 +1,7 @@  - 4.2.0-preview + 4.3.0-preview netstandard2.0 9.0 From d0f1eac7bbd51e251219cbb28bb2d52af2b75b34 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 16:04:02 +0530 Subject: [PATCH 77/89] update outdated actions in publish code workflow --- .github/workflows/publish-code.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-code.yml b/.github/workflows/publish-code.yml index ef76a197..2073a733 100644 --- a/.github/workflows/publish-code.yml +++ b/.github/workflows/publish-code.yml @@ -36,7 +36,7 @@ jobs: dotnet pack --no-restore --no-build -o PackOutputs -c Release -p:Version=${{ github.event.release.tag_name }} -p:PackageReleaseNotes="See https://github.com/notion-dotnet/notion-sdk-net/releases/tag/${{ github.event.release.tag_name }}" -p:PackageReadmeFile=README.md - name: Upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Notion.Net path: PackOutputs/* @@ -45,7 +45,7 @@ jobs: run: dotnet nuget push PackOutputs/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} - name: Upload Nuget packages as release artifacts - uses: actions/github-script@v2 + uses: actions/github-script@v7 with: github-token: ${{secrets.GITHUB_TOKEN}} script: | From d6947cca04a07e600079dc999d6aa0b67f3f293f Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 13 Apr 2025 16:11:57 +0530 Subject: [PATCH 78/89] update test publish code github workflow --- .github/workflows/test-publish-code.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-publish-code.yml b/.github/workflows/test-publish-code.yml index e90afd73..ce6974e6 100644 --- a/.github/workflows/test-publish-code.yml +++ b/.github/workflows/test-publish-code.yml @@ -45,7 +45,7 @@ jobs: ls -l PackOutputs/ - name: Upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Notion.Net path: PackOutputs/* From ae01e9e253a22bf74cc470353a01136e1e7ceacf Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Tue, 15 Apr 2025 06:45:37 +0530 Subject: [PATCH 79/89] workflow to greet first-time contributors --- .github/workflows/greetings.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/greetings.yml diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml new file mode 100644 index 00000000..55a63c2c --- /dev/null +++ b/.github/workflows/greetings.yml @@ -0,0 +1,23 @@ +name: Greetings + +on: [pull_request_target, issues] + +jobs: + greet-first-time-contributors: + name: Greet First-Time Contributors + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + + steps: + - name: Send greeting to first-time contributors + uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: > + 👋 Hi there! Thanks for opening your first issue in this repository. + We appreciate your contribution. A maintainer will take a look soon. + pr-message: > + 🎉 Thanks for your first pull request! + The team will review it shortly. We’re excited to have you contribute! From 8a69e7d26725bd1f39058fbd4a8bbcc1421e0739 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 13 Apr 2025 09:57:03 +0000 Subject: [PATCH 80/89] deps: bump Microsoft.SourceLink.GitHub from 1.1.1 to 8.0.0 Bumps [Microsoft.SourceLink.GitHub](https://github.com/dotnet/sourcelink) from 1.1.1 to 8.0.0. - [Release notes](https://github.com/dotnet/sourcelink/releases) - [Commits](https://github.com/dotnet/sourcelink/compare/1.1.1...8.0.0) --- updated-dependencies: - dependency-name: Microsoft.SourceLink.GitHub dependency-version: 8.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Src/Notion.Client/Notion.Client.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/Notion.Client/Notion.Client.csproj b/Src/Notion.Client/Notion.Client.csproj index 3e353339..2a6555c3 100644 --- a/Src/Notion.Client/Notion.Client.csproj +++ b/Src/Notion.Client/Notion.Client.csproj @@ -1,4 +1,4 @@ - + 4.3.0-preview @@ -16,7 +16,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive From d9c3cd2cc23fa4f2457fa249dae2ea7286c25d16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 13 Apr 2025 09:57:44 +0000 Subject: [PATCH 81/89] deps: bump Microsoft.NET.Test.Sdk from 16.7.1 to 17.13.0 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.7.1 to 17.13.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md) - [Commits](https://github.com/microsoft/vstest/compare/v16.7.1...v17.13.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-version: 17.13.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Test/Notion.UnitTests/Notion.UnitTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/Notion.UnitTests/Notion.UnitTests.csproj b/Test/Notion.UnitTests/Notion.UnitTests.csproj index 588ddc54..ef5c1d34 100644 --- a/Test/Notion.UnitTests/Notion.UnitTests.csproj +++ b/Test/Notion.UnitTests/Notion.UnitTests.csproj @@ -8,7 +8,7 @@ - + From 966f95893fca1c855f136d536746bb26dfa0ff95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 13 Apr 2025 10:00:14 +0000 Subject: [PATCH 82/89] deps: bump xunit.runner.visualstudio from 2.4.3 to 3.0.2 Bumps [xunit.runner.visualstudio](https://github.com/xunit/visualstudio.xunit) from 2.4.3 to 3.0.2. - [Release notes](https://github.com/xunit/visualstudio.xunit/releases) - [Commits](https://github.com/xunit/visualstudio.xunit/compare/2.4.3...3.0.2) --- updated-dependencies: - dependency-name: xunit.runner.visualstudio dependency-version: 3.0.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Test/Notion.IntegrationTests/Notion.IntegrationTests.csproj | 2 +- Test/Notion.UnitTests/Notion.UnitTests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Test/Notion.IntegrationTests/Notion.IntegrationTests.csproj b/Test/Notion.IntegrationTests/Notion.IntegrationTests.csproj index 42a1975a..1284ee3f 100644 --- a/Test/Notion.IntegrationTests/Notion.IntegrationTests.csproj +++ b/Test/Notion.IntegrationTests/Notion.IntegrationTests.csproj @@ -15,7 +15,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Test/Notion.UnitTests/Notion.UnitTests.csproj b/Test/Notion.UnitTests/Notion.UnitTests.csproj index 2da01ae8..f04f3c8e 100644 --- a/Test/Notion.UnitTests/Notion.UnitTests.csproj +++ b/Test/Notion.UnitTests/Notion.UnitTests.csproj @@ -12,7 +12,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 744229db390be105aa419074f45e23d30ed6daa7 Mon Sep 17 00:00:00 2001 From: Mr-Bally <25254611+Mr-Bally@users.noreply.github.com> Date: Tue, 15 Apr 2025 10:39:47 +0000 Subject: [PATCH 83/89] Added revoke functionality --- Src/Notion.Client/Api/ApiEndpoints.cs | 1 + .../Authentication/IAuthenticationClient.cs | 11 ++++++++++ .../RevokeToken/AuthenticationClient.cs | 21 +++++++++++++++++++ .../Request/IRevokeTokenBodyParameters.cs | 13 ++++++++++++ .../RevokeToken/Request/RevokeTokenRequest.cs | 7 +++++++ 5 files changed, 53 insertions(+) create mode 100644 Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs create mode 100644 Src/Notion.Client/Api/Authentication/RevokeToken/Request/IRevokeTokenBodyParameters.cs create mode 100644 Src/Notion.Client/Api/Authentication/RevokeToken/Request/RevokeTokenRequest.cs diff --git a/Src/Notion.Client/Api/ApiEndpoints.cs b/Src/Notion.Client/Api/ApiEndpoints.cs index 4ed80bb1..86d703b3 100644 --- a/Src/Notion.Client/Api/ApiEndpoints.cs +++ b/Src/Notion.Client/Api/ApiEndpoints.cs @@ -135,6 +135,7 @@ public static string Create() public static class AuthenticationUrls { public static string CreateToken() => "/v1/oauth/token"; + public static string RevokeToken() => "/v1/oauth/revoke"; } } } diff --git a/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs b/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs index 0b4ebeb8..2aa3e7a8 100644 --- a/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs +++ b/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs @@ -18,5 +18,16 @@ Task CreateTokenAsync( CreateTokenRequest createTokenRequest, CancellationToken cancellationToken = default ); + + /// + /// Revokes an access token. + /// + /// + /// + /// + Task RevokeTokenAsync( + RevokeTokenRequest revokeTokenRequest, + CancellationToken cancellationToken = default + ); } } diff --git a/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs b/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs new file mode 100644 index 00000000..8cc5c85e --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs @@ -0,0 +1,21 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class AuthenticationClient + { + public async Task RevokeTokenAsync( + RevokeTokenRequest revokeTokenRequest, + CancellationToken cancellationToken = default) + { + var body = (IRevokeTokenBodyParameters)revokeTokenRequest; + + return (await _client.PostAsync( + ApiEndpoints.AuthenticationUrls.RevokeToken(), + body, + cancellationToken: cancellationToken + )).StatusCode; + } + } +} diff --git a/Src/Notion.Client/Api/Authentication/RevokeToken/Request/IRevokeTokenBodyParameters.cs b/Src/Notion.Client/Api/Authentication/RevokeToken/Request/IRevokeTokenBodyParameters.cs new file mode 100644 index 00000000..0a194516 --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/RevokeToken/Request/IRevokeTokenBodyParameters.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IRevokeTokenBodyParameters + { + /// + /// The token to be revoked. + /// + [JsonProperty("token")] + string Token { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Authentication/RevokeToken/Request/RevokeTokenRequest.cs b/Src/Notion.Client/Api/Authentication/RevokeToken/Request/RevokeTokenRequest.cs new file mode 100644 index 00000000..7e92ca01 --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/RevokeToken/Request/RevokeTokenRequest.cs @@ -0,0 +1,7 @@ +namespace Notion.Client +{ + public class RevokeTokenRequest : IRevokeTokenBodyParameters + { + public string Token { get; set; } + } +} From a96af1ab55464f49fd03acdbe630a02fec6766e8 Mon Sep 17 00:00:00 2001 From: Sam-Ballantyne <25254611+Sam-Ballantyne@users.noreply.github.com> Date: Wed, 16 Apr 2025 10:25:02 +0100 Subject: [PATCH 84/89] Updates from PR review --- .../Authentication/IAuthenticationClient.cs | 4 ++-- .../RevokeToken/AuthenticationClient.cs | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs b/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs index 2aa3e7a8..1973638f 100644 --- a/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs +++ b/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs @@ -18,14 +18,14 @@ Task CreateTokenAsync( CreateTokenRequest createTokenRequest, CancellationToken cancellationToken = default ); - + /// /// Revokes an access token. /// /// /// /// - Task RevokeTokenAsync( + Task RevokeTokenAsync( RevokeTokenRequest revokeTokenRequest, CancellationToken cancellationToken = default ); diff --git a/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs b/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs index 8cc5c85e..d9087aa4 100644 --- a/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs +++ b/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs @@ -1,21 +1,30 @@ +using System.Net.Http; using System.Threading; using System.Threading.Tasks; namespace Notion.Client { public sealed partial class AuthenticationClient - { - public async Task RevokeTokenAsync( + { + public async Task RevokeTokenAsync( RevokeTokenRequest revokeTokenRequest, CancellationToken cancellationToken = default) { var body = (IRevokeTokenBodyParameters)revokeTokenRequest; - - return (await _client.PostAsync( + + var response = await _client.PostAsync( ApiEndpoints.AuthenticationUrls.RevokeToken(), body, cancellationToken: cancellationToken - )).StatusCode; + ); + + if (!response.IsSuccessStatusCode) + { + throw new NotionApiException(response.StatusCode, + null, + "None success status code returned from revoke endpoint" + ); + } } } } From 0a9ed73fe62e9ecbc653a957978dea760c4f4d6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Apr 2025 11:53:18 +0000 Subject: [PATCH 85/89] deps: bump Microsoft.VisualStudio.VsixColorCompiler Bumps Microsoft.VisualStudio.VsixColorCompiler from 16.0.0 to 17.11.35325.10. --- updated-dependencies: - dependency-name: Microsoft.VisualStudio.VsixColorCompiler dependency-version: 17.11.35325.10 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Test/Notion.UnitTests/Notion.UnitTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/Notion.UnitTests/Notion.UnitTests.csproj b/Test/Notion.UnitTests/Notion.UnitTests.csproj index f04f3c8e..6a33f5c0 100644 --- a/Test/Notion.UnitTests/Notion.UnitTests.csproj +++ b/Test/Notion.UnitTests/Notion.UnitTests.csproj @@ -9,7 +9,7 @@ - + From 0cc805772d78e0a4b7f2ad8d18992d8889bcf67b Mon Sep 17 00:00:00 2001 From: Mr-Bally <25254611+Mr-Bally@users.noreply.github.com> Date: Thu, 17 Apr 2025 16:24:51 +0100 Subject: [PATCH 86/89] Update from PR review --- .../Authentication/RevokeToken/AuthenticationClient.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs b/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs index d9087aa4..0d67057b 100644 --- a/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs +++ b/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs @@ -12,19 +12,11 @@ public async Task RevokeTokenAsync( { var body = (IRevokeTokenBodyParameters)revokeTokenRequest; - var response = await _client.PostAsync( + await _client.PostAsync( ApiEndpoints.AuthenticationUrls.RevokeToken(), body, cancellationToken: cancellationToken ); - - if (!response.IsSuccessStatusCode) - { - throw new NotionApiException(response.StatusCode, - null, - "None success status code returned from revoke endpoint" - ); - } } } } From bb62d1e3b5ec057fc951d46d8cc964e1f790700e Mon Sep 17 00:00:00 2001 From: Mr-Bally <25254611+Mr-Bally@users.noreply.github.com> Date: Thu, 17 Apr 2025 16:52:20 +0100 Subject: [PATCH 87/89] Added empty object for HttpClient --- .../Api/Authentication/RevokeToken/AuthenticationClient.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs b/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs index 0d67057b..2c4d2c28 100644 --- a/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs +++ b/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs @@ -12,11 +12,15 @@ public async Task RevokeTokenAsync( { var body = (IRevokeTokenBodyParameters)revokeTokenRequest; - await _client.PostAsync( + await _client.PostAsync( ApiEndpoints.AuthenticationUrls.RevokeToken(), body, cancellationToken: cancellationToken ); } } + + internal class RevokeTokenResponse + { + } } From c7349ed96f35d1f38633dfa9788bac05c72b195f Mon Sep 17 00:00:00 2001 From: Sam-Ballantyne <25254611+Sam-Ballantyne@users.noreply.github.com> Date: Thu, 17 Apr 2025 18:45:15 +0100 Subject: [PATCH 88/89] moved class into separate file --- .../Api/Authentication/RevokeToken/AuthenticationClient.cs | 5 ----- .../RevokeToken/Response/RevokeTokenResponse.cs | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 Src/Notion.Client/Api/Authentication/RevokeToken/Response/RevokeTokenResponse.cs diff --git a/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs b/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs index 2c4d2c28..c1f3ab9d 100644 --- a/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs +++ b/Src/Notion.Client/Api/Authentication/RevokeToken/AuthenticationClient.cs @@ -1,4 +1,3 @@ -using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -19,8 +18,4 @@ await _client.PostAsync( ); } } - - internal class RevokeTokenResponse - { - } } diff --git a/Src/Notion.Client/Api/Authentication/RevokeToken/Response/RevokeTokenResponse.cs b/Src/Notion.Client/Api/Authentication/RevokeToken/Response/RevokeTokenResponse.cs new file mode 100644 index 00000000..428dd287 --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/RevokeToken/Response/RevokeTokenResponse.cs @@ -0,0 +1,6 @@ +namespace Notion.Client +{ + internal class RevokeTokenResponse + { + } +} From 237bb13e5656bd010f25839f10b12515d866d828 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 19 Apr 2025 06:06:11 +0530 Subject: [PATCH 89/89] remove lgtm yaml and links --- README.md | 3 --- lgtm.yml | 6 ------ 2 files changed, 9 deletions(-) delete mode 100644 lgtm.yml diff --git a/README.md b/README.md index 5ab47338..d74a4cc6 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,6 @@ [![Publish Code](https://github.com/notion-dotnet/notion-sdk-net/actions/workflows/publish-code.yml/badge.svg)](https://github.com/notion-dotnet/notion-sdk-net/actions/workflows/publish-code.yml) [![CodeQL](https://github.com/notion-dotnet/notion-sdk-net/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/notion-dotnet/notion-sdk-net/actions/workflows/codeql-analysis.yml) -[![LGTM Alerts](https://img.shields.io/lgtm/alerts/github/notion-dotnet/notion-sdk-net)](https://lgtm.com/projects/g/notion-dotnet/notion-sdk-net/alerts/?mode=list) -[![LGTM Grade](https://img.shields.io/lgtm/grade/csharp/github/notion-dotnet/notion-sdk-net)](https://lgtm.com/projects/g/notion-dotnet/notion-sdk-net/alerts/?mode=list) - [![GitHub last commit](https://img.shields.io/github/last-commit/notion-dotnet/notion-sdk-net)]() [![GitHub commit activity](https://img.shields.io/github/commit-activity/w/notion-dotnet/notion-sdk-net)]() [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/notion-dotnet/notion-sdk-net)]() diff --git a/lgtm.yml b/lgtm.yml deleted file mode 100644 index 5d5e1e4f..00000000 --- a/lgtm.yml +++ /dev/null @@ -1,6 +0,0 @@ -extraction: - csharp: - index: - all_solutions: true - dotnet: - version: 6.0.400