diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 00000000..92211a4f --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "jetbrains.resharper.globaltools": { + "version": "2022.2.3", + "commands": [ + "jb" + ] + } + } +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index f8d20ed2..1745f593 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,11 +1,52 @@ +root = true # EditorConfig is awesome: https://EditorConfig.org # top-most EditorConfig file -root = true # Don't use tabs for indentation. [*] indent_style = space + +[*.cs] + +# ReSharper properties + +# Blank lines +resharper_blank_lines_after_control_transfer_statements = 1 +resharper_blank_lines_after_multiline_statements = 1 +resharper_blank_lines_around_single_line_auto_property = 1 +resharper_blank_lines_around_single_line_local_method = 1 +resharper_blank_lines_around_single_line_property = 1 +resharper_blank_lines_before_block_statements = 1 +resharper_blank_lines_before_control_transfer_statements = 1 +resharper_blank_lines_before_multiline_statements = 1 +resharper_blank_lines_before_single_line_comment = 1 + +# Baces +resharper_braces_for_for = required +resharper_braces_for_foreach = required +resharper_braces_for_ifelse = required +resharper_braces_for_while = required +resharper_braces_redundant = false +resharper_indent_nested_fixed_stmt = true +resharper_indent_nested_foreach_stmt = true +resharper_indent_nested_for_stmt = true +resharper_indent_nested_lock_stmt = true +resharper_indent_nested_usings_stmt = true +resharper_indent_nested_while_stmt = true +resharper_max_enum_members_on_line = 1 + +resharper_csharp_force_attribute_style=separate +resharper_csharp_method_or_operator_body=expression_body +resharper_csharp_max_enum_members_on_line=1 +resharper_csharp_place_attribute_on_same_line=false +resharper_csharp_wrap_object_and_collection_initializer_style=chop_always +resharper_csharp_use_heuristics_for_body_style=true + +resharper_csharp_max_initializer_elements_on_line=0 + +# Standard properties +insert_final_newline = true # (Please don't specify an indent_size here; that has too many unintended consequences.) # Code files @@ -39,7 +80,7 @@ indent_size = 2 [*.{cs,vb}] # IDE0055: Fix formatting -dotnet_diagnostic.IDE0055.severity = warning +dotnet_diagnostic.ide0055.severity = warning # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = true @@ -102,7 +143,7 @@ dotnet_naming_symbols.static_fields.applicable_kinds = field dotnet_naming_symbols.static_fields.required_modifiers = static dotnet_naming_style.static_field_style.capitalization = camel_case -dotnet_naming_style.static_field_style.required_prefix = s_ +dotnet_naming_style.static_field_style.required_prefix = _ # Instance fields are camelCase and start with _ dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion @@ -143,23 +184,23 @@ dotnet_naming_symbols.all_members.applicable_kinds = * dotnet_naming_style.pascal_case_style.capitalization = pascal_case # error RS2008: Enable analyzer release tracking for the analyzer project containing rule '{0}' -dotnet_diagnostic.RS2008.severity = none +dotnet_diagnostic.rs2008.severity = none # IDE0073: File header # dotnet_diagnostic.IDE0073.severity = warning # file_header_template = # IDE0035: Remove unreachable code -dotnet_diagnostic.IDE0035.severity = warning +dotnet_diagnostic.ide0035.severity = warning # IDE0036: Order modifiers -dotnet_diagnostic.IDE0036.severity = warning +dotnet_diagnostic.ide0036.severity = warning # IDE0043: Format string contains invalid placeholder -dotnet_diagnostic.IDE0043.severity = warning +dotnet_diagnostic.ide0043.severity = warning # IDE0044: Make field readonly -dotnet_diagnostic.IDE0044.severity = warning +dotnet_diagnostic.ide0044.severity = warning # RS0016: Only enable if API files are present dotnet_public_api_analyzer.require_api_files = true @@ -236,39 +277,39 @@ csharp_preserve_single_line_statements = true [src/CodeStyle/**.{cs,vb}] # warning RS0005: Do not use generic CodeAction.Create to create CodeAction -dotnet_diagnostic.RS0005.severity = none +dotnet_diagnostic.rs0005.severity = none [src/{Analyzers,CodeStyle,Features,Workspaces,EditorFeatures,VisualStudio}/**/*.{cs,vb}] # IDE0011: Add braces csharp_prefer_braces = when_multiline:warning # NOTE: We need the below severity entry for Add Braces due to https://github.com/dotnet/roslyn/issues/44201 -dotnet_diagnostic.IDE0011.severity = warning +dotnet_diagnostic.ide0011.severity = warning # IDE0040: Add accessibility modifiers -dotnet_diagnostic.IDE0040.severity = warning +dotnet_diagnostic.ide0040.severity = warning # CONSIDER: Are IDE0051 and IDE0052 too noisy to be warnings for IDE editing scenarios? Should they be made build-only warnings? # IDE0051: Remove unused private member -dotnet_diagnostic.IDE0051.severity = warning +dotnet_diagnostic.ide0051.severity = warning # IDE0052: Remove unread private member -dotnet_diagnostic.IDE0052.severity = warning +dotnet_diagnostic.ide0052.severity = warning # IDE0059: Unnecessary assignment to a value -dotnet_diagnostic.IDE0059.severity = warning +dotnet_diagnostic.ide0059.severity = warning # IDE0060: Remove unused parameter -dotnet_diagnostic.IDE0060.severity = warning +dotnet_diagnostic.ide0060.severity = warning # CA1012: Abstract types should not have public constructors -dotnet_diagnostic.CA1012.severity = warning +dotnet_diagnostic.ca1012.severity = warning # CA1822: Make member static -dotnet_diagnostic.CA1822.severity = warning +dotnet_diagnostic.ca1822.severity = warning # Prefer "var" everywhere -dotnet_diagnostic.IDE0007.severity = warning +dotnet_diagnostic.ide0007.severity = warning csharp_style_var_for_built_in_types = true:warning csharp_style_var_when_type_is_apparent = true:warning csharp_style_var_elsewhere = true:warning @@ -277,4 +318,18 @@ csharp_style_var_elsewhere = true:warning # CA1822: Make member static # Not enforced as a build 'warning' for 'VisualStudio' layer due to large number of false positives from https://github.com/dotnet/roslyn-analyzers/issues/3857 and https://github.com/dotnet/roslyn-analyzers/issues/3858 # Additionally, there is a risk of accidentally breaking an internal API that partners rely on though IVT. -dotnet_diagnostic.CA1822.severity = suggestion \ No newline at end of file +dotnet_diagnostic.ca1822.severity = suggestion + +[*.{appxmanifest,asax,ascx,aspx,axaml,axml,build,config,cs,cshtml,csproj,css,dbml,discomap,dtd,htm,html,js,json,jsproj,jsx,lsproj,master,njsproj,nuspec,paml,proj,props,proto,razor,resjson,resw,resx,skin,StyleCop,targets,tasks,ts,tsx,vb,vbproj,xaml,xamlx,xml,xoml,xsd}] +indent_style = space +indent_size = 4 +tab_width = 4 + +[*.cs] +# IDE0130: Namespace does not match folder structure +dotnet_style_namespace_match_folder = false + +# IDE0130: Namespace does not match folder structure +dotnet_diagnostic.IDE0130.severity = silent + +resharper_check_namespace_highlighting=none 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" 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/scripts/check.sh b/.github/scripts/check.sh new file mode 100644 index 00000000..3006888a --- /dev/null +++ b/.github/scripts/check.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +dotnet jb inspectcode Notion.sln -f="Text" --no-build --include="**.cs" -o=".lint/CodeWarningResults.txt" + +totalLines=$(file .lint/CodeWarningResults.txt | nl | wc -l) + +if [[ "$totalLines" -gt 1 ]]; then + echo "There are few linter warnings - please fix them before running the pipeline" + cat .lint/CodeWarningResults.txt + exit 1 +fi diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index c69148e8..35959b57 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -21,15 +21,15 @@ jobs: - name: Restore dependencies run: dotnet restore - # Format the output of dotnet format - - name: Add dotnet-format problem matcher - uses: xt0rted/dotnet-format-problem-matcher@v1 - # Install dotnet format as a global tool - - name: Install dotnet format + - name: Install dotnet tools + run: dotnet tool restore + + - name: Run Linter run: | - dotnet tool install --global dotnet-format - dotnet format --verify-no-changes --verbosity diagnostic + sudo chmod +x ./.github/scripts/check.sh + ./.github/scripts/check.sh + shell: bash - name: Build run: dotnet build --no-restore 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! 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: | 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 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/* diff --git a/.gitignore b/.gitignore index dfcfd56f..5072687a 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,11 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ + +# Resharper linter +.lint/ + +# Rider +.idea/ + +.DS_Store diff --git a/Notion.sln.DotSettings b/Notion.sln.DotSettings new file mode 100644 index 00000000..833f39db --- /dev/null +++ b/Notion.sln.DotSettings @@ -0,0 +1,5 @@ + + PDF + API + JSON + URL diff --git a/README.md b/README.md index 10893f28..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)]() @@ -44,6 +41,7 @@ dotnet add package Notion.Net **Note:** default Notion-Version used by NuGet package versions | Package version | Notion-Version | | --- | --- | +| 4.0.0-preview-1.8.21.2022 | 2022-06-28 | | 3.0.0+ | 2022-02-22 | | 2.0.0+ | 2021-08-16 | | 1.0.0+ | 2021-05-13 | @@ -127,6 +125,9 @@ var complexFiler = new CompoundFilter( - [x] Retrieve block children - [x] Append block children - [x] Delete a block +- [x] Comments + - [x] Retrieve comments + - [x] Create comment - [x] Users - [x] Retrieve a User - [x] List all users diff --git a/Src/Notion.Client/Api/ApiEndpoints.cs b/Src/Notion.Client/Api/ApiEndpoints.cs index f9a9549b..86d703b3 100644 --- a/Src/Notion.Client/Api/ApiEndpoints.cs +++ b/Src/Notion.Client/Api/ApiEndpoints.cs @@ -1,65 +1,141 @@ -using System; - -namespace Notion.Client +namespace Notion.Client { public static class ApiEndpoints { public static class DatabasesApiUrls { - public static string Retrieve(string databaseId) => $"/v1/databases/{databaseId}"; - public static string List() => "/v1/databases"; - public static string Query(string databaseId) => $"/v1/databases/{databaseId}/query"; public static string Create => "/v1/databases"; - public static string Update(string databaseId) => $"/v1/databases/{databaseId}"; + + public static string Retrieve(string databaseId) + { + return $"/v1/databases/{databaseId}"; + } + + public static string Query(string databaseId) + { + return $"/v1/databases/{databaseId}/query"; + } + + public static string Update(string databaseId) + { + return $"/v1/databases/{databaseId}"; + } } public static class UsersApiUrls { - public static string Retrieve(string userId) => $"/v1/users/{userId}"; - public static string List() => "/v1/users"; + public static string Retrieve(string userId) + { + return $"/v1/users/{userId}"; + } + + public static string List() + { + return "/v1/users"; + } /// - /// Get the for retrieve your token's bot user. + /// Get the Uri for retrieve your token's bot user. /// - /// Returns a retrieve your token's bot user. - public static string Me() => "/v1/users/me"; + /// Returns a Uri retrieve your token's bot user. + public static string Me() + { + return "/v1/users/me"; + } } public static class BlocksApiUrls { - public static string Retrieve(string blockId) => $"/v1/blocks/{blockId}"; - public static string Update(string blockId) => $"/v1/blocks/{blockId}"; + public static string Retrieve(string blockId) + { + return $"/v1/blocks/{blockId}"; + } + + public static string Update(string blockId) + { + return $"/v1/blocks/{blockId}"; + } /// - /// Get the for deleting a block. + /// Get the Uri for deleting a block. /// /// Identifier for a Notion block - /// Returns a for deleting a block. - public static string Delete(string blockId) => $"/v1/blocks/{blockId}"; + /// Returns a Uri for deleting a block. + public static string Delete(string blockId) + { + return $"/v1/blocks/{blockId}"; + } + + public static string RetrieveChildren(string blockId) + { + return $"/v1/blocks/{blockId}/children"; + } - public static string RetrieveChildren(string blockId) => $"/v1/blocks/{blockId}/children"; - public static string AppendChildren(string blockId) => $"/v1/blocks/{blockId}/children"; + public static string AppendChildren(string blockId) + { + return $"/v1/blocks/{blockId}/children"; + } } public static class PagesApiUrls { - public static string Create() => $"/v1/pages"; - public static string Retrieve(string pageId) => $"/v1/pages/{pageId}"; - public static string Update(string pageId) => $"/v1/pages/{pageId}"; - public static string UpdateProperties(string pageId) => $"/v1/pages/{pageId}"; + public static string Create() + { + return "/v1/pages"; + } + + public static string Retrieve(string pageId) + { + return $"/v1/pages/{pageId}"; + } + + public static string Update(string pageId) + { + return $"/v1/pages/{pageId}"; + } + + public static string UpdateProperties(string pageId) + { + return $"/v1/pages/{pageId}"; + } /// - /// Get the for retrieve page property item + /// Get the Uri for retrieve page property item /// /// Identifier for a Notion Page /// Identifier for a Notion Property - /// - public static string RetrievePropertyItem(string pageId, string propertyId) => $"/v1/pages/{pageId}/properties/{propertyId}"; + /// Returns a Uri for Retrieve page property item + public static string RetrievePropertyItem(string pageId, string propertyId) + { + return $"/v1/pages/{pageId}/properties/{propertyId}"; + } } public static class SearchApiUrls { - public static string Search() => "/v1/search"; + public static string Search() + { + return "/v1/search"; + } + } + + public static class CommentsApiUrls + { + public static string Retrieve() + { + return "/v1/comments"; + } + + public static string Create() + { + return "/v1/comments"; + } + } + + 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/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..1973638f --- /dev/null +++ b/Src/Notion.Client/Api/Authentication/IAuthenticationClient.cs @@ -0,0 +1,33 @@ +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 + ); + + /// + /// 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..c1f3ab9d --- /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; + + await _client.PostAsync( + ApiEndpoints.AuthenticationUrls.RevokeToken(), + body, + cancellationToken: cancellationToken + ); + } + } +} 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; } + } +} 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 + { + } +} 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..50ce3c61 --- /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 = new BlockAppendChildrenBodyParameters(request); + + return await _client.PatchAsync(url, body, cancellationToken: cancellationToken); + } + } +} diff --git a/Src/Notion.Client/Api/Blocks/AppendChildren/Request/BlockAppendChildrenRequest.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/BlockAppendChildrenRequest.cs new file mode 100644 index 00000000..8a5a9cde --- /dev/null +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/BlockAppendChildrenRequest.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Notion.Client +{ + 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/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs new file mode 100644 index 00000000..ea6cef37 --- /dev/null +++ b/Src/Notion.Client/Api/Blocks/AppendChildren/Request/IBlockAppendChildrenBodyParameters.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IBlockAppendChildrenBodyParameters + { + [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; } + } + + internal class BlockAppendChildrenBodyParameters : IBlockAppendChildrenBodyParameters + { + public IEnumerable Children { get; set; } + + public string After { get; set; } + + public BlockAppendChildrenBodyParameters(BlockAppendChildrenRequest request) + { + Children = request.Children; + After = request.After; + } + } +} 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 cc06642e..92713a78 100644 --- a/Src/Notion.Client/Api/Blocks/BlocksClient.cs +++ b/Src/Notion.Client/Api/Blocks/BlocksClient.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; namespace Notion.Client { - public class BlocksClient : IBlocksClient + public sealed partial class BlocksClient : IBlocksClient { private readonly IRestClient _client; @@ -14,41 +15,7 @@ public BlocksClient(IRestClient client) _client = client; } - public async Task> RetrieveChildrenAsync(string blockId, BlocksRetrieveChildrenParameters parameters = null) - { - 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?.ToString() }, - { "page_size", queryParameters?.PageSize?.ToString() } - }; - - return await _client.GetAsync>(url, queryParams); - } - - public async Task> AppendChildrenAsync(string blockId, BlocksAppendChildrenParameters parameters = null) - { - if (string.IsNullOrWhiteSpace(blockId)) - { - throw new ArgumentNullException(nameof(blockId)); - } - - var url = BlocksApiUrls.AppendChildren(blockId); - - var body = (IBlocksAppendChildrenBodyParameters)parameters; - - return await _client.PatchAsync>(url, body); - } - - public async Task RetrieveAsync(string blockId) + public async Task RetrieveAsync(string blockId, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(blockId)) { @@ -57,10 +24,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)) { @@ -69,10 +36,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)) { @@ -81,7 +48,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 90ebf073..c5a64e59 100644 --- a/Src/Notion.Client/Api/Blocks/IBlocksClient.cs +++ b/Src/Notion.Client/Api/Blocks/IBlocksClient.cs @@ -1,38 +1,55 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; namespace Notion.Client { public interface IBlocksClient { /// - /// Retrieves a Block object using the ID specified. + /// Retrieves a Block object using the ID specified. /// /// /// 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. + /// Updates the content for the specified block_id based on the block type. /// /// /// /// Block - Task UpdateAsync(string blockId, IUpdateBlock updateBlock); + Task UpdateAsync(string blockId, IUpdateBlock updateBlock, + CancellationToken cancellationToken = default); - Task> RetrieveChildrenAsync(string blockId, BlocksRetrieveChildrenParameters parameters = null); + /// + /// 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. + /// 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); + Task AppendChildrenAsync( + BlockAppendChildrenRequest request, + CancellationToken cancellationToken = default + ); /// - /// 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); + Task DeleteAsync(string blockId, CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksAppendChildrenParameters.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksAppendChildrenParameters.cs deleted file mode 100644 index e78899bb..00000000 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksAppendChildrenParameters.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace Notion.Client -{ - public class BlocksAppendChildrenParameters : IBlocksAppendChildrenBodyParameters - { - public IEnumerable Children { get; set; } - } -} 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 ddc73a91..00000000 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksRetrieveChildrenParameters.cs +++ /dev/null @@ -1,8 +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/BlocksUpdateParameters/UpdateBlocks/AudioUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/AudioUpdateBlock.cs index 8747ad63..0f4b1acb 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/AudioUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/AudioUpdateBlock.cs @@ -1,9 +1,8 @@ -using System.Collections.Generic; -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Notion.Client { - public class AudioUpdateBlock : UpdateBlock, IUpdateBlock + public class AudioUpdateBlock : UpdateBlock { [JsonProperty("audio")] public IFileObjectInput Audio { get; set; } 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 c3333737..b147c587 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BookmarkUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BookmarkUpdateBlock.cs @@ -5,11 +5,11 @@ namespace Notion.Client { public class BookmarkUpdateBlock : IUpdateBlock { - public bool Archived { get; set; } - [JsonProperty("bookmark")] public Info Bookmark { get; set; } + public bool InTrash { get; set; } + public class Info { [JsonProperty("url")] 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 2bb8be38..260eca82 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BreadcrumbUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BreadcrumbUpdateBlock.cs @@ -4,18 +4,18 @@ namespace Notion.Client { public class BreadcrumbUpdateBlock : IUpdateBlock { - public bool Archived { get; set; } + public BreadcrumbUpdateBlock() + { + Breadcrumb = new Info(); + } [JsonProperty("breadcrumb")] public Info Breadcrumb { get; set; } - public class Info - { - } + public bool InTrash { get; set; } - public BreadcrumbUpdateBlock() + public class Info { - Breadcrumb = new Info(); } } } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BulletedListItemUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BulletedListItemUpdateBlock.cs index 9225942f..cb1fa405 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BulletedListItemUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/BulletedListItemUpdateBlock.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class BulletedListItemUpdateBlock : UpdateBlock, IUpdateBlock + public class BulletedListItemUpdateBlock : UpdateBlock { [JsonProperty("bulleted_list_item")] public Info BulletedListItem { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/CalloutUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/CalloutUpdateBlock.cs index f8562ff3..f4489ff8 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/CalloutUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/CalloutUpdateBlock.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class CalloutUpdateBlock : UpdateBlock, IUpdateBlock + public class CalloutUpdateBlock : UpdateBlock { [JsonProperty("callout")] public Info Callout { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/CodeUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/CodeUpdateBlock.cs index b4fcd6dc..164abb87 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/CodeUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/CodeUpdateBlock.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class CodeUpdateBlock : UpdateBlock, IUpdateBlock + public class CodeUpdateBlock : UpdateBlock { [JsonProperty("code")] public Info Code { get; set; } 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 6c5b447c..62b83451 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/DividerUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/DividerUpdateBlock.cs @@ -4,18 +4,18 @@ namespace Notion.Client { public class DividerUpdateBlock : IUpdateBlock { - public bool Archived { get; set; } + public DividerUpdateBlock() + { + Divider = new Info(); + } [JsonProperty("divider")] public Info Divider { get; set; } - public class Info - { - } + public bool InTrash { get; set; } - public DividerUpdateBlock() + public class Info { - Divider = new Info(); } } } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/EmbedUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/EmbedUpdateBlock.cs index b0419a23..8dba5a53 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/EmbedUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/EmbedUpdateBlock.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class EmbedUpdateBlock : UpdateBlock, IUpdateBlock + public class EmbedUpdateBlock : UpdateBlock { [JsonProperty("embed")] public Info Embed { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/EquationUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/EquationUpdateBlock.cs index b7cb0ad9..b809ba7c 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/EquationUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/EquationUpdateBlock.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class EquationUpdateBlock : UpdateBlock, IUpdateBlock + public class EquationUpdateBlock : UpdateBlock { [JsonProperty("equation")] public Info Equation { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/FileUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/FileUpdateBlock.cs index 30d0dd9c..10208c1a 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/FileUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/FileUpdateBlock.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class FileUpdateBlock : UpdateBlock, IUpdateBlock + public class FileUpdateBlock : UpdateBlock { [JsonProperty("file")] public IFileObjectInput File { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingOneUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingOneUpdateBlock.cs index aeb4e087..672c8c85 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingOneUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingOneUpdateBlock.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; namespace Notion.Client { - public class HeadingOneUpdateBlock : UpdateBlock, IUpdateBlock + public class HeadingOneUpdateBlock : UpdateBlock { [JsonProperty("heading_1")] + [SuppressMessage("ReSharper", "InconsistentNaming")] public Info Heading_1 { get; set; } public class Info diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingThreeeUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingThreeeUpdateBlock.cs index 574ea0f0..d2eb4861 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingThreeeUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingThreeeUpdateBlock.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; namespace Notion.Client { - public class HeadingThreeeUpdateBlock : UpdateBlock, IUpdateBlock + public class HeadingThreeUpdateBlock : UpdateBlock { [JsonProperty("heading_3")] + [SuppressMessage("ReSharper", "InconsistentNaming")] public Info Heading_3 { get; set; } public class Info diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingTwoUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingTwoUpdateBlock.cs index 0269a0ce..da1f2833 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingTwoUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/HeadingTwoUpdateBlock.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; namespace Notion.Client { - public class HeadingTwoUpdateBlock : UpdateBlock, IUpdateBlock + public class HeadingTwoUpdateBlock : UpdateBlock { [JsonProperty("heading_2")] + [SuppressMessage("ReSharper", "InconsistentNaming")] public Info Heading_2 { 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/ImageUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ImageUpdateBlock.cs index 6679c61b..791198e9 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ImageUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ImageUpdateBlock.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class ImageUpdateBlock : UpdateBlock, IUpdateBlock + public class ImageUpdateBlock : UpdateBlock { [JsonProperty("image")] public IFileObjectInput Image { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/LinkToPageUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/LinkToPageUpdateBlock.cs index f6407cd4..69e088c5 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/LinkToPageUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/LinkToPageUpdateBlock.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class LinkToPageUpdateBlock : UpdateBlock, IUpdateBlock + public class LinkToPageUpdateBlock : UpdateBlock { [JsonProperty("link_to_page")] public IPageParentInput LinkToPage { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/NumberedListItemUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/NumberedListItemUpdateBlock.cs index c27363d3..11f92394 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/NumberedListItemUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/NumberedListItemUpdateBlock.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class NumberedListItemUpdateBlock : UpdateBlock, IUpdateBlock + public class NumberedListItemUpdateBlock : UpdateBlock { [JsonProperty("numbered_list_item")] public Info NumberedListItem { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/PDFUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/PDFUpdateBlock.cs index 8c56b7ff..c6e9ba0e 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/PDFUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/PDFUpdateBlock.cs @@ -1,8 +1,10 @@ -using Newtonsoft.Json; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; namespace Notion.Client { - public class PDFUpdateBlock : UpdateBlock, IUpdateBlock + [SuppressMessage("ReSharper", "InconsistentNaming")] + public class PDFUpdateBlock : UpdateBlock { [JsonProperty("pdf")] public IFileObjectInput PDF { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ParagraphUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ParagraphUpdateBlock.cs index 2e49c64a..63aa2724 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ParagraphUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ParagraphUpdateBlock.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class ParagraphUpdateBlock : UpdateBlock, IUpdateBlock + public class ParagraphUpdateBlock : UpdateBlock { [JsonProperty("paragraph")] public Info Paragraph { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/QuoteUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/QuoteUpdateBlock.cs index fdfd189c..9222112e 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/QuoteUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/QuoteUpdateBlock.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class QuoteUpdateBlock : UpdateBlock, IUpdateBlock + public class QuoteUpdateBlock : UpdateBlock { [JsonProperty("quote")] public Info Quote { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/SyncedBlockUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/SyncedBlockUpdateBlock.cs index 9cb234d8..e275f371 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/SyncedBlockUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/SyncedBlockUpdateBlock.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class SyncedBlockUpdateBlock : UpdateBlock, IUpdateBlock + public class SyncedBlockUpdateBlock : UpdateBlock { [JsonProperty("synced_block")] public Info SyncedBlock { 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 36eee182..2e4adff9 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableOfContentsUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableOfContentsUpdateBlock.cs @@ -4,18 +4,18 @@ namespace Notion.Client { public class TableOfContentsUpdateBlock : IUpdateBlock { - public bool Archived { get; set; } + public TableOfContentsUpdateBlock() + { + TableOfContents = new Info(); + } [JsonProperty("table_of_contents")] public Info TableOfContents { get; set; } - public class Info - { - } + public bool InTrash { get; set; } - public TableOfContentsUpdateBlock() + public class Info { - TableOfContents = new Info(); } } } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableRowUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableRowUpdateBlock.cs index c228de66..143f3e2d 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableRowUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableRowUpdateBlock.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class TableRowUpdateBlock : UpdateBlock, IUpdateBlock + public class TableRowUpdateBlock : UpdateBlock { [JsonProperty("table_row")] public Info TableRow { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableUpdateBlock.cs index ef0e8933..7c1f8046 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TableUpdateBlock.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class TableUpdateBlock : UpdateBlock, IUpdateBlock + public class TableUpdateBlock : UpdateBlock { [JsonProperty("table")] public Info Table { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TemplateUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TemplateUpdateBlock.cs index 62457971..32a393cd 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TemplateUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/TemplateUpdateBlock.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class TemplateUpdateBlock : UpdateBlock, IUpdateBlock + public class TemplateUpdateBlock : UpdateBlock { [JsonProperty("template")] public Info Template { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ToDoUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ToDoUpdateBlock.cs index f1accfc8..9e244f44 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ToDoUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ToDoUpdateBlock.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class ToDoUpdateBlock : UpdateBlock, IUpdateBlock + public class ToDoUpdateBlock : UpdateBlock { [JsonProperty("to_do")] public Info ToDo { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ToggleUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ToggleUpdateBlock.cs index b87834d1..3d7e8e87 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ToggleUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/ToggleUpdateBlock.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class ToggleUpdateBlock : UpdateBlock, IUpdateBlock + public class ToggleUpdateBlock : UpdateBlock { [JsonProperty("toggle")] public Info Toggle { get; set; } 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/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/VideoUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/VideoUpdateBlock.cs index ec28aae3..a317139a 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/VideoUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/VideoUpdateBlock.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class VideoUpdateBlock : UpdateBlock, IUpdateBlock + public class VideoUpdateBlock : UpdateBlock { [JsonProperty("video")] public IFileObjectInput Video { get; set; } diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksAppendChildrenBodyParameters.cs b/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksAppendChildrenBodyParameters.cs deleted file mode 100644 index bdd4d324..00000000 --- a/Src/Notion.Client/Api/Blocks/RequestParams/IBlocksAppendChildrenBodyParameters.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - // TODO: need an input version of Block - public interface IBlocksAppendChildrenBodyParameters - { - [JsonProperty("children")] - IEnumerable Children { 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/Src/Notion.Client/Api/Comments/CommentsClient.cs b/Src/Notion.Client/Api/Comments/CommentsClient.cs new file mode 100644 index 00000000..51dadeff --- /dev/null +++ b/Src/Notion.Client/Api/Comments/CommentsClient.cs @@ -0,0 +1,12 @@ +namespace Notion.Client +{ + public partial class CommentsClient : ICommentsClient + { + private readonly IRestClient _client; + + public CommentsClient(IRestClient restClient) + { + _client = restClient; + } + } +} diff --git a/Src/Notion.Client/Api/Comments/Create/CommentsClient.cs b/Src/Notion.Client/Api/Comments/Create/CommentsClient.cs new file mode 100644 index 00000000..ac2244ea --- /dev/null +++ b/Src/Notion.Client/Api/Comments/Create/CommentsClient.cs @@ -0,0 +1,19 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public partial class CommentsClient + { + public async Task CreateAsync(CreateCommentParameters parameters, CancellationToken cancellationToken = default) + { + var body = (ICreateCommentsBodyParameters)parameters; + + return await _client.PostAsync( + ApiEndpoints.CommentsApiUrls.Create(), + body, + cancellationToken: cancellationToken + ); + } + } +} diff --git a/Src/Notion.Client/Api/Comments/Create/Request/CreateCommentParameters.cs b/Src/Notion.Client/Api/Comments/Create/Request/CreateCommentParameters.cs new file mode 100644 index 00000000..f9532726 --- /dev/null +++ b/Src/Notion.Client/Api/Comments/Create/Request/CreateCommentParameters.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface ICreateCommentsBodyParameters + { + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + } + + public interface ICreateDiscussionCommentBodyParameters : ICreateCommentsBodyParameters + { + [JsonProperty("discussion_id")] + public string DiscussionId { get; set; } + } + + public interface ICreatePageCommentBodyParameters : ICreateCommentsBodyParameters + { + [JsonProperty("parent")] + public ParentPageInput Parent { get; set; } + } + + public class CreateCommentParameters : ICreateDiscussionCommentBodyParameters, ICreatePageCommentBodyParameters + { + public string DiscussionId { get; set; } + + public IEnumerable RichText { get; set; } + + public ParentPageInput Parent { get; set; } + + public static CreateCommentParameters CreatePageComment( + ParentPageInput parent, + IEnumerable richText) + { + return new CreateCommentParameters + { + Parent = parent, + RichText = richText + }; + } + + public static CreateCommentParameters CreateDiscussionComment( + string discussionId, + IEnumerable richText) + { + return new CreateCommentParameters + { + DiscussionId = discussionId, + RichText = richText + }; + } + } +} diff --git a/Src/Notion.Client/Api/Comments/Create/Response/CreateCommentResponse.cs b/Src/Notion.Client/Api/Comments/Create/Response/CreateCommentResponse.cs new file mode 100644 index 00000000..0171d92d --- /dev/null +++ b/Src/Notion.Client/Api/Comments/Create/Response/CreateCommentResponse.cs @@ -0,0 +1,9 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Notion.Client +{ + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] + public class CreateCommentResponse : Comment + { + } +} diff --git a/Src/Notion.Client/Api/Comments/ICommentsClient.cs b/Src/Notion.Client/Api/Comments/ICommentsClient.cs new file mode 100644 index 00000000..7b7af943 --- /dev/null +++ b/Src/Notion.Client/Api/Comments/ICommentsClient.cs @@ -0,0 +1,12 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public interface ICommentsClient + { + Task CreateAsync(CreateCommentParameters createCommentParameters, CancellationToken cancellationToken = default); + + 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 new file mode 100644 index 00000000..45c64f00 --- /dev/null +++ b/Src/Notion.Client/Api/Comments/Retrieve/CommentsClient.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public partial class CommentsClient + { + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public async Task RetrieveAsync(RetrieveCommentsParameters parameters, CancellationToken cancellationToken = default) + { + var qp = (IRetrieveCommentsQueryParameters)parameters; + + var queryParams = new Dictionary + { + { "block_id", qp.BlockId }, + { "start_cursor", qp.StartCursor }, + { "page_size", qp.PageSize.ToString() } + }; + + return await _client.GetAsync( + ApiEndpoints.CommentsApiUrls.Retrieve(), + queryParams, + cancellationToken: cancellationToken + ); + } + } +} diff --git a/Src/Notion.Client/Api/Comments/Retrieve/Request/IRetrieveCommentsQueryParameters.cs b/Src/Notion.Client/Api/Comments/Retrieve/Request/IRetrieveCommentsQueryParameters.cs new file mode 100644 index 00000000..123a5844 --- /dev/null +++ b/Src/Notion.Client/Api/Comments/Retrieve/Request/IRetrieveCommentsQueryParameters.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IRetrieveCommentsQueryParameters : IPaginationParameters + { + [JsonProperty("block_id")] + string BlockId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Comments/Retrieve/Request/RetrieveCommentsParameters.cs b/Src/Notion.Client/Api/Comments/Retrieve/Request/RetrieveCommentsParameters.cs new file mode 100644 index 00000000..25d3d54d --- /dev/null +++ b/Src/Notion.Client/Api/Comments/Retrieve/Request/RetrieveCommentsParameters.cs @@ -0,0 +1,14 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Notion.Client +{ + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] + public class RetrieveCommentsParameters : IRetrieveCommentsQueryParameters + { + public string BlockId { get; set; } + + public string StartCursor { get; set; } + + public int? PageSize { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Comments/Retrieve/Response/Comment.cs b/Src/Notion.Client/Api/Comments/Retrieve/Response/Comment.cs new file mode 100644 index 00000000..9b9ef2ae --- /dev/null +++ b/Src/Notion.Client/Api/Comments/Retrieve/Response/Comment.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class Comment : IObject + { + [JsonProperty("parent")] + public ICommentParent Parent { get; set; } + + [JsonProperty("discussion_id")] + public string DiscussionId { get; set; } + + [JsonProperty("rich_text")] + public IEnumerable RichText { get; set; } + + [JsonProperty("created_by")] + public PartialUser CreatedBy { get; set; } + + [JsonProperty("created_time")] + public DateTime CreatedTime { get; set; } + + [JsonProperty("last_edited_time")] + public DateTime LastEditedTime { get; set; } + + public string Id { get; set; } + + public ObjectType Object => ObjectType.Comment; + } +} diff --git a/Src/Notion.Client/Api/Comments/Retrieve/Response/Comments.cs b/Src/Notion.Client/Api/Comments/Retrieve/Response/Comments.cs new file mode 100644 index 00000000..8b3b43b3 --- /dev/null +++ b/Src/Notion.Client/Api/Comments/Retrieve/Response/Comments.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class RetrieveCommentsResponse : PaginatedList + { + [JsonProperty("comment")] + public Dictionary Comment { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Comments/Retrieve/Response/ICommentParent.cs b/Src/Notion.Client/Api/Comments/Retrieve/Response/ICommentParent.cs new file mode 100644 index 00000000..9e05d019 --- /dev/null +++ b/Src/Notion.Client/Api/Comments/Retrieve/Response/ICommentParent.cs @@ -0,0 +1,12 @@ +using JsonSubTypes; +using Newtonsoft.Json; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PageParent), ParentType.PageId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(BlockParent), ParentType.BlockId)] + public interface ICommentParent + { + } +} diff --git a/Src/Notion.Client/Api/Databases/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/DatabasesClient.cs index 2ab17a8b..a3dc9a8c 100644 --- a/Src/Notion.Client/Api/Databases/DatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/DatabasesClient.cs @@ -1,9 +1,11 @@ -using System.Threading.Tasks; +using System; +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; @@ -12,30 +14,28 @@ 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)); - } - - public async Task> QueryAsync(string databaseId, DatabasesQueryParameters databasesQueryParameters) - { - var body = (IDatabaseQueryBodyParameters)databasesQueryParameters; + if (string.IsNullOrWhiteSpace(databaseId)) + { + throw new ArgumentNullException(nameof(databaseId)); + } - return await _client.PostAsync>(DatabasesApiUrls.Query(databaseId), body); + return await _client.GetAsync(DatabasesApiUrls.Retrieve(databaseId), 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 2b2c2746..98df1273 100644 --- a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs @@ -1,25 +1,48 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; namespace Notion.Client { public interface IDatabasesClient { - Task RetrieveAsync(string databaseId); - Task> QueryAsync(string databaseId, DatabasesQueryParameters databasesQueryParameters); + /// + /// Retrieves a Database object using the ID specified. + /// + /// Identifier for a Notion database + /// + /// + /// + Task RetrieveAsync(string databaseId, CancellationToken cancellationToken = default); + + /// + /// Gets a list of Pages contained in the database, filtered and ordered according to the + /// filter conditions and sort criteria provided in the request. The response may contain + /// fewer than page_size of results. + /// + /// + /// + /// + /// + /// + 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. + /// Creates a database as a subpage in the specified parent page, with the specified properties schema. /// /// - /// Database - Task CreateAsync(DatabasesCreateParameters databasesCreateParameters); + /// + /// + /// + Task CreateAsync(DatabasesCreateParameters databasesCreateParameters, CancellationToken cancellationToken = default); /// - /// Updates an existing database as specified by the parameters. + /// Updates an existing database as specified by the parameters. /// /// /// - /// Database - Task UpdateAsync(string databaseId, DatabasesUpdateParameters databasesUpdateParameters); + /// + /// + /// + Task UpdateAsync(string databaseId, DatabasesUpdateParameters databasesUpdateParameters, CancellationToken cancellationToken = default); } } 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 75% rename from Src/Notion.Client/Api/Databases/RequestParams/DatabasesQueryParameters.cs rename to Src/Notion.Client/Api/Databases/Query/Request/DatabasesQueryParameters.cs index 454961a2..2c2bb030 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesQueryParameters.cs +++ b/Src/Notion.Client/Api/Databases/Query/Request/DatabasesQueryParameters.cs @@ -2,11 +2,16 @@ namespace Notion.Client { - public class DatabasesQueryParameters : IDatabaseQueryBodyParameters + public class DatabasesQueryParameters : IDatabaseQueryBodyParameters, IDatabaseQueryQueryParameters { public Filter Filter { get; set; } + public List Sorts { get; set; } + public string StartCursor { get; set; } + public int? PageSize { get; set; } + + public List FilterProperties { get; set; } } } 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/Query/Request/IDatabaseQueryQueryParameters.cs b/Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryQueryParameters.cs new file mode 100644 index 00000000..f8ba1f41 --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Query/Request/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/Api/Databases/Query/Response/DatabaseQueryResponse.cs b/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs new file mode 100644 index 00000000..5b7c9ec6 --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs @@ -0,0 +1,12 @@ +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; } + } +} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/DatabasesCreateParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/DatabasesCreateParameters.cs index bafad0ec..9cb7086b 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/DatabasesCreateParameters.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/DatabasesCreateParameters.cs @@ -5,6 +5,12 @@ namespace Notion.Client { public class DatabasesCreateParameters : IDatabasesCreateBodyParameters, IDatabasesCreateQueryParameters { + [JsonProperty("icon")] + public IPageIcon Icon { get; set; } + + [JsonProperty("cover")] + public FileObject Cover { get; set; } + [JsonProperty("parent")] public ParentPageInput Parent { get; set; } @@ -14,12 +20,6 @@ public class DatabasesCreateParameters : IDatabasesCreateBodyParameters, IDataba [JsonProperty("title")] public List Title { get; set; } - [JsonProperty("icon")] - public IPageIcon Icon { get; set; } - - [JsonProperty("cover")] - public FileObject Cover { get; set; } - public bool? IsInline { get; set; } public List Description { get; set; } 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/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectOptionSchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectOptionSchema.cs index 89fdb0ab..a13d0930 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectOptionSchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectOptionSchema.cs @@ -1,5 +1,8 @@ -namespace Notion.Client +using System.Diagnostics.CodeAnalysis; + +namespace Notion.Client { + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] public class MultiSelectOptionSchema : SelectOptionSchema { } 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 bee17690..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 SynchedPropertyId { get; set; } - - [JsonProperty("synced_property_name")] - public string SynchedPropertyName { get; set; } - } + public RelationData Relation { get; set; } } } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesListParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesListParameters.cs deleted file mode 100644 index 51136e47..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesListParameters.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Notion.Client -{ - public class DatabasesListParameters : IDatabasesListQueryParmaters - { - public string StartCursor { get; set; } - public int? PageSize { 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 b9cb182e..5147a6b0 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateParameters.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateParameters.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Newtonsoft.Json; namespace Notion.Client { @@ -13,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/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CheckboxUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CheckboxUpdatePropertySchema.cs index a13f2911..a6890d6e 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CheckboxUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CheckboxUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class CheckboxUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class CheckboxUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("checkbox")] public Dictionary Checkbox { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedByUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedByUpdatePropertySchema.cs index 394868db..08a5cf74 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedByUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedByUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class CreatedByUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class CreatedByUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("created_by")] public Dictionary CreatedBy { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedTimeUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedTimeUpdatePropertySchema.cs index dee266f3..8089ecbb 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedTimeUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedTimeUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class CreatedTimeUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class CreatedTimeUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("created_time")] public Dictionary CreatedTime { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/DateUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/DateUpdatePropertySchema.cs index 0c2b2143..65487dd7 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/DateUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/DateUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class DateUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class DateUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("date")] public Dictionary Date { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/EmailUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/EmailUpdatePropertySchema.cs index 412c9115..5905e68e 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/EmailUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/EmailUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class EmailUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class EmailUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("email")] public Dictionary Email { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FilesUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FilesUpdatePropertySchema.cs index c7b84218..9fb3b531 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FilesUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FilesUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class FilesUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class FilesUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("files")] public Dictionary Files { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FormulaUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FormulaUpdatePropertySchema.cs index 158a42bb..40cc398a 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FormulaUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FormulaUpdatePropertySchema.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class FormulaUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class FormulaUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("formula")] public Formula Formula { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedByUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedByUpdatePropertySchema.cs index 939bc69d..c547538a 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedByUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedByUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class LastEditedByUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class LastEditedByUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("last_edited_by")] public Dictionary LastEditedBy { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedTimeUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedTimeUpdatePropertySchema.cs index f48ddf5a..28c9e55b 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedTimeUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedTimeUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class LastEditedTimeUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class LastEditedTimeUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("last_edited_time")] public Dictionary LastEditedTime { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/MultiSelectUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/MultiSelectUpdatePropertySchema.cs index a6b32ad3..0b7b1c0c 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/MultiSelectUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/MultiSelectUpdatePropertySchema.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class MultiSelectUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class MultiSelectUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("multi_select")] public OptionWrapper MultiSelect { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/NumberUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/NumberUpdatePropertySchema.cs index e1f0b734..23f3ea3a 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/NumberUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/NumberUpdatePropertySchema.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class NumberUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class NumberUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("number")] public Number Number { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PeopleUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PeopleUpdatePropertySchema.cs index 6fab728e..41a8892d 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PeopleUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PeopleUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class PeopleUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class PeopleUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("people")] public Dictionary People { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PhoneNumberUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PhoneNumberUpdatePropertySchema.cs index 7813671c..7d01f506 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PhoneNumberUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PhoneNumberUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class PhoneNumberUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class PhoneNumberUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("phone_number")] public Dictionary PhoneNumber { 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 2091df91..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, IUpdatePropertySchema + 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 SynchedPropertyId { get; set; } - - [JsonProperty("synced_property_name")] - public string SynchedPropertyName { get; set; } - } + public RelationData Relation { get; set; } } } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RichTextUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RichTextUpdatePropertySchema.cs index 3d6c5ec2..a20ca0ea 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RichTextUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RichTextUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class RichTextUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class RichTextUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("rich_text")] public Dictionary RichText { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RollupConfigUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RollupConfigUpdatePropertySchema.cs index 2f38731b..8ee2d908 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RollupConfigUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RollupConfigUpdatePropertySchema.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class RollupConfigUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class RollupConfigUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("relation_property_name")] public string RelationPropertyName { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/SelectUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/SelectUpdatePropertySchema.cs index b833d0bc..678e452d 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/SelectUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/SelectUpdatePropertySchema.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class SelectUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class SelectUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("select")] public OptionWrapper Select { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/TitleUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/TitleUpdatePropertySchema.cs index 1a74085c..54052dfc 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/TitleUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/TitleUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class TitleUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class TitleUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("title")] public Dictionary Title { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/URLUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/URLUpdatePropertySchema.cs index 7aa9c701..f56d6507 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/URLUpdatePropertySchema.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/URLUpdatePropertySchema.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class UrlUpdatePropertySchema : UpdatePropertySchema, IUpdatePropertySchema + public class UrlUpdatePropertySchema : UpdatePropertySchema { [JsonProperty("url")] public Dictionary Url { get; set; } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/Direction.cs b/Src/Notion.Client/Api/Databases/RequestParams/Direction.cs index c79d501d..059f42b3 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/Direction.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/Direction.cs @@ -1,7 +1,9 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum Direction { [EnumMember(Value = null)] diff --git a/Src/Notion.Client/Api/Databases/RequestParams/IDatabasesListQueryParmaters.cs b/Src/Notion.Client/Api/Databases/RequestParams/IDatabasesListQueryParmaters.cs deleted file mode 100644 index 4432f421..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/IDatabasesListQueryParmaters.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Notion.Client -{ - public interface IDatabasesListQueryParmaters : IPaginationParameters - { - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/Timestamp.cs b/Src/Notion.Client/Api/Databases/RequestParams/Timestamp.cs index 334b8c22..df2c69ca 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/Timestamp.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/Timestamp.cs @@ -1,7 +1,9 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum Timestamp { [EnumMember(Value = null)] diff --git a/Src/Notion.Client/Api/Pages/IPagesClient.cs b/Src/Notion.Client/Api/Pages/IPagesClient.cs index b4fc728f..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 @@ -6,37 +7,58 @@ namespace Notion.Client public interface IPagesClient { /// - /// Creates a new page in the specified database or as a child of an existing page. - /// - /// If the parent is a database, the property values of the new page in the properties parameter must conform to the parent database's property schema. - /// - /// If the parent is a page, the only valid property is title. + /// Creates a new page in the specified database or as a child of an existing page. + /// If the parent is a database, the + /// property values of the + /// new page in the properties parameter must conform to the parent + /// database's property schema. + /// If the parent is a page, the only valid property is title. /// /// Create page parameters - /// Created page. - Task CreateAsync(PagesCreateParameters pagesCreateParameters); + /// Created object. + Task CreateAsync(PagesCreateParameters pagesCreateParameters, CancellationToken cancellationToken = default); - Task RetrieveAsync(string pageId); + /// + /// Retrieves a Page object using the ID specified. + /// + /// Identifier for a Notion page + /// + /// + /// + Task RetrieveAsync(string pageId, CancellationToken cancellationToken = default); + /// + /// Updates page property values for the specified page. + /// Note: Properties that are not set via the properties parameter will remain unchanged. + /// + /// Identifier for a Notion page + /// + /// Property values to update for this page. The keys are the names or IDs of the property + /// and the values are property values. + /// + /// Updated object Task UpdatePropertiesAsync( string pageId, - IDictionary updatedProperties - ); + IDictionary updatedProperties, CancellationToken cancellationToken = default); /// - /// Updates page property values for the specified page. - /// Properties that are not set via the properties parameter will remain unchanged. + /// Updates page property values for the specified page. + /// Properties that are not set via the properties parameter will remain unchanged. /// - /// - /// - /// Updated page. - Task UpdateAsync(string pageId, PagesUpdateParameters pagesUpdateParameters); + /// Identifier for a Notion page + /// Update property parameters + /// Updated object + 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 returned will either be a value or a paginated list of property item values. + /// Retrieves a property_item object for a given pageId and propertyId. Depending on the property type, the object + /// returned will either be a value or a paginated list of property item values. /// - /// sdf sd - /// - Task RetrievePagePropertyItem(RetrievePropertyItemParameters retrievePropertyItemParameters); + /// Property body and query parameters + /// + /// + /// + Task RetrievePagePropertyItemAsync( + RetrievePropertyItemParameters retrievePropertyItemParameters, CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/Api/Pages/PagesClient.cs b/Src/Notion.Client/Api/Pages/PagesClient.cs index 5bce1904..76b3e41a 100644 --- a/Src/Notion.Client/Api/Pages/PagesClient.cs +++ b/Src/Notion.Client/Api/Pages/PagesClient.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading; using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; @@ -15,15 +17,16 @@ public PagesClient(IRestClient client) } /// - /// Creates a new page in the specified database or as a child of an existing page. - /// - /// If the parent is a database, the property values of the new page in the properties parameter must conform to the parent database's property schema. - /// - /// If the parent is a page, the only valid property is title. + /// Creates a new page in the specified database or as a child of an existing page. + /// If the parent is a database, the + /// property values of the + /// new page in the properties parameter must conform to the parent + /// database's property schema. + /// If the parent is a page, the only valid property is title. /// /// Create page parameters /// Created page. - public async Task CreateAsync(PagesCreateParameters pagesCreateParameters) + public async Task CreateAsync(PagesCreateParameters pagesCreateParameters, CancellationToken cancellationToken = default) { if (pagesCreateParameters is null) { @@ -42,50 +45,54 @@ 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 RetrievePagePropertyItem(RetrievePropertyItemParameters retrievePropertyItemParameters) + public async Task RetrievePagePropertyItemAsync( + RetrievePropertyItemParameters retrievePropertyItemParameters, CancellationToken cancellationToken = default) { var pathParameters = (IRetrievePropertyItemPathParameters)retrievePropertyItemParameters; var queryParameters = (IRetrievePropertyQueryParameters)retrievePropertyItemParameters; var url = PagesApiUrls.RetrievePropertyItem(pathParameters.PageId, pathParameters.PropertyId); - var queryParams = new Dictionary() + var queryParams = new Dictionary { { "start_cursor", queryParameters?.StartCursor }, { "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 obsolute. Use UpdateAsync instead. This API will be removed in future release")] + [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")] private class UpdatePropertiesParameters { public IDictionary Properties { 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/PagesCreateParameters/PagesCreateParameters.cs b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParameters.cs index 52cb0a89..08572811 100644 --- a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParameters.cs +++ b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParameters.cs @@ -5,9 +5,13 @@ namespace Notion.Client public class PagesCreateParameters : IPagesCreateBodyParameters, IPagesCreateQueryParameters { public IPageParentInput Parent { get; set; } + public IDictionary Properties { get; set; } + public IList Children { get; set; } + public IPageIcon Icon { get; set; } + public FileObject Cover { get; set; } } } diff --git a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParametersBuilder.cs b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParametersBuilder.cs index b86a207a..ed85117d 100644 --- a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParametersBuilder.cs +++ b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParametersBuilder.cs @@ -1,14 +1,16 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public class PagesCreateParametersBuilder { - private IPageParentInput parent; - private readonly Dictionary properties = new Dictionary(); - private readonly IList children = new List(); - private IPageIcon icon; - private FileObject cover; + private readonly IList _children = new List(); + private readonly Dictionary _properties = new(); + private FileObject _cover; + private IPageIcon _icon; + private IPageParentInput _parent; private PagesCreateParametersBuilder() { @@ -16,33 +18,34 @@ private PagesCreateParametersBuilder() public static PagesCreateParametersBuilder Create(IPageParentInput parent) { - return new PagesCreateParametersBuilder - { - parent = parent - }; + return new PagesCreateParametersBuilder { _parent = parent }; } public PagesCreateParametersBuilder AddProperty(string nameOrId, PropertyValue value) { - properties[nameOrId] = value; + _properties[nameOrId] = value; + return this; } public PagesCreateParametersBuilder AddPageContent(IBlock block) { - children.Add(block); + _children.Add(block); + return this; } public PagesCreateParametersBuilder SetIcon(IPageIcon pageIcon) { - icon = pageIcon; + _icon = pageIcon; + return this; } public PagesCreateParametersBuilder SetCover(FileObject pageCover) { - cover = pageCover; + _cover = pageCover; + return this; } @@ -50,11 +53,11 @@ public PagesCreateParameters Build() { return new PagesCreateParameters { - Parent = parent, - Properties = properties, - Children = children, - Icon = icon, - Cover = cover + Parent = _parent, + Properties = _properties, + Children = _children, + Icon = _icon, + Cover = _cover }; } } diff --git a/Src/Notion.Client/Api/Pages/RequestParams/PagesUpdateParameters.cs b/Src/Notion.Client/Api/Pages/RequestParams/PagesUpdateParameters.cs index 40f06b12..6845f27b 100644 --- a/Src/Notion.Client/Api/Pages/RequestParams/PagesUpdateParameters.cs +++ b/Src/Notion.Client/Api/Pages/RequestParams/PagesUpdateParameters.cs @@ -5,16 +5,16 @@ namespace Notion.Client { public class PagesUpdateParameters : IPagesUpdateBodyParameters { - [JsonProperty("archived")] - public bool Archived { get; set; } - - [JsonProperty("properties")] - public IDictionary Properties { get; set; } - [JsonProperty("icon")] public IPageIcon Icon { get; set; } [JsonProperty("cover")] public FileObject Cover { get; set; } + + [JsonProperty("in_trash")] + public bool InTrash { get; set; } + + [JsonProperty("properties")] + public IDictionary Properties { get; set; } } } diff --git a/Src/Notion.Client/Api/Search/ISearchClient.cs b/Src/Notion.Client/Api/Search/ISearchClient.cs index 883c86ba..accee1e1 100644 --- a/Src/Notion.Client/Api/Search/ISearchClient.cs +++ b/Src/Notion.Client/Api/Search/ISearchClient.cs @@ -1,9 +1,24 @@ -using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] public interface ISearchClient { - Task> SearchAsync(SearchParameters parameters); + /// + /// 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 + /// + /// + /// + /// + 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 59% rename from Src/Notion.Client/Api/Search/Parameters/SearchDirection.cs rename to Src/Notion.Client/Api/Search/Request/SearchDirection.cs index fdac0b59..da52b11b 100644 --- a/Src/Notion.Client/Api/Search/Parameters/SearchDirection.cs +++ b/Src/Notion.Client/Api/Search/Request/SearchDirection.cs @@ -1,7 +1,9 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum SearchDirection { [EnumMember(Value = "ascending")] diff --git a/Src/Notion.Client/Api/Search/Parameters/SearchFilter.cs b/Src/Notion.Client/Api/Search/Request/SearchFilter.cs similarity index 56% rename from Src/Notion.Client/Api/Search/Parameters/SearchFilter.cs rename to Src/Notion.Client/Api/Search/Request/SearchFilter.cs index cc84a9a3..b36ca873 100644 --- a/Src/Notion.Client/Api/Search/Parameters/SearchFilter.cs +++ b/Src/Notion.Client/Api/Search/Request/SearchFilter.cs @@ -1,12 +1,16 @@ -using Newtonsoft.Json; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace Notion.Client { + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] + [SuppressMessage("ReSharper", "UnusedMember.Global")] public class SearchFilter { [JsonConverter(typeof(StringEnumConverter))] public SearchObjectType Value { get; set; } + public string Property => "object"; } } diff --git a/Src/Notion.Client/Api/Search/Parameters/SearchObjectType.cs b/Src/Notion.Client/Api/Search/Request/SearchObjectType.cs similarity index 57% rename from Src/Notion.Client/Api/Search/Parameters/SearchObjectType.cs rename to Src/Notion.Client/Api/Search/Request/SearchObjectType.cs index 78a012df..e3e6181b 100644 --- a/Src/Notion.Client/Api/Search/Parameters/SearchObjectType.cs +++ b/Src/Notion.Client/Api/Search/Request/SearchObjectType.cs @@ -1,7 +1,9 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum SearchObjectType { [EnumMember(Value = "page")] 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 ae02c0f4..a9ac887f 100644 --- a/Src/Notion.Client/Api/Search/Parameters/SearchParameters.cs +++ b/Src/Notion.Client/Api/Search/Request/SearchRequest.cs @@ -1,11 +1,15 @@ namespace Notion.Client { - public class SearchParameters : ISearchBodyParameters + public class SearchRequest : ISearchBodyParameters { public string Query { get; set; } + public SearchSort Sort { get; set; } + public SearchFilter Filter { get; set; } + public string StartCursor { get; set; } + public int? PageSize { 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 87de9270..492e0940 100644 --- a/Src/Notion.Client/Api/Search/SearchClient.cs +++ b/Src/Notion.Client/Api/Search/SearchClient.cs @@ -1,24 +1,27 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; namespace Notion.Client { - public class SearchClient : ISearchClient + public sealed class SearchClient : ISearchClient { - private readonly IRestClient client; + private readonly IRestClient _client; public SearchClient(IRestClient client) { - this.client = client; + _client = client; } - public async Task> SearchAsync(SearchParameters parameters) + 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); + 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 95427f2b..bc0c3d8a 100644 --- a/Src/Notion.Client/Api/Users/IUsersClient.cs +++ b/Src/Notion.Client/Api/Users/IUsersClient.cs @@ -1,16 +1,51 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; +using Notion.Client.List.Request; namespace Notion.Client { public interface IUsersClient { - Task RetrieveAsync(string userId); - Task> ListAsync(); + /// + /// Retrieves a User using the ID specified. + /// + /// Identifier for a Notion user + /// + /// + /// + Task RetrieveAsync(string userId, CancellationToken cancellationToken = default); + + /// + /// Returns a paginated list of Users for the workspace. + /// The response may contain fewer than page_size of results. + /// + /// + /// + /// + /// + Task ListAsync(CancellationToken cancellationToken = default); + + /// + /// 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 + ); /// - /// Retrieves the bot User associated with the API token provided in the authorization header. + /// Retrieves the bot User associated with the API token provided in the authorization header. /// - /// User object of type bot having an owner field with information about the person who authorized the integration. - Task MeAsync(); + /// + /// object of type bot having an owner field with information about the person who authorized + /// the integration. + /// + Task MeAsync(CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/Api/Users/List/Request/ListUsersRequest.cs b/Src/Notion.Client/Api/Users/List/Request/ListUsersRequest.cs new file mode 100644 index 00000000..f3684d09 --- /dev/null +++ b/Src/Notion.Client/Api/Users/List/Request/ListUsersRequest.cs @@ -0,0 +1,13 @@ +namespace Notion.Client.List.Request +{ + public interface IListUsersQueryParameters : IPaginationParameters + { + } + + public class ListUsersRequest : IListUsersQueryParameters + { + public string StartCursor { get; set; } + + public int? PageSize { 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 new file mode 100644 index 00000000..ce13633a --- /dev/null +++ b/Src/Notion.Client/Api/Users/List/UsersClient.cs @@ -0,0 +1,38 @@ +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(CancellationToken cancellationToken = default) + { + return await _client.GetAsync( + ApiEndpoints.UsersApiUrls.List(), + cancellationToken: cancellationToken + ); + } + + public async Task ListAsync( + ListUsersRequest listUsersRequest, + CancellationToken cancellationToken = default + ) + { + var queryParameters = (IListUsersQueryParameters)listUsersRequest; + + 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 5c745f72..24681b53 100644 --- a/Src/Notion.Client/Api/Users/UsersClient.cs +++ b/Src/Notion.Client/Api/Users/UsersClient.cs @@ -1,9 +1,10 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using static Notion.Client.ApiEndpoints; namespace Notion.Client { - public class UsersClient : IUsersClient + public partial class UsersClient : IUsersClient { private readonly IRestClient _client; @@ -12,23 +13,21 @@ 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)); - } - - public async Task> ListAsync() - { - return await _client.GetAsync>(UsersApiUrls.List()); + return await _client.GetAsync(UsersApiUrls.Retrieve(userId), cancellationToken: cancellationToken); } /// - /// Retrieves the bot User associated with the API token provided in the authorization header. + /// Retrieves the bot User associated with the API token provided in the authorization header. /// - /// User object of type bot having an owner field with information about the person who authorized the integration. - public async Task MeAsync() + /// + /// User object of type bot having an owner field with information about the person who authorized the + /// integration. + /// + public async Task MeAsync(CancellationToken cancellationToken = default) { - return await _client.GetAsync(UsersApiUrls.Me()); + return await _client.GetAsync(UsersApiUrls.Me(), cancellationToken: cancellationToken); } } } diff --git a/Src/Notion.Client/Constants.cs b/Src/Notion.Client/Constants.cs index 5034edae..779bcb47 100644 --- a/Src/Notion.Client/Constants.cs +++ b/Src/Notion.Client/Constants.cs @@ -1,11 +1,12 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Notion.UnitTests")] + namespace Notion.Client { - internal class Constants + internal static class Constants { - internal static string BASE_URL = "https://api.notion.com/"; - internal static string DEFAULT_NOTION_VERSION = "2022-06-28"; + internal const string BaseUrl = "https://api.notion.com/"; + internal const string DefaultNotionVersion = "2022-06-28"; } } diff --git a/Src/Notion.Client/DI/ServiceCollectionExtensions.cs b/Src/Notion.Client/DI/ServiceCollectionExtensions.cs index a4aed7fd..9a658077 100644 --- a/Src/Notion.Client/DI/ServiceCollectionExtensions.cs +++ b/Src/Notion.Client/DI/ServiceCollectionExtensions.cs @@ -1,13 +1,18 @@ using System; +using System.Diagnostics.CodeAnalysis; using Notion.Client; namespace Microsoft.Extensions.DependencyInjection { + [SuppressMessage("ReSharper", "UnusedType.Global")] + [SuppressMessage("ReSharper", "UnusedMember.Global")] public static class ServiceCollectionExtensions { - public static IServiceCollection AddNotionClient(this IServiceCollection services, Action options) + public static IServiceCollection AddNotionClient( + this IServiceCollection services, + Action options) { - services.AddSingleton(sp => + services.AddSingleton(_ => { var clientOptions = new ClientOptions(); options?.Invoke(clientOptions); diff --git a/Src/Notion.Client/Extensions/EnumExtensions.cs b/Src/Notion.Client/Extensions/EnumExtensions.cs index 987104b8..cd60aebd 100644 --- a/Src/Notion.Client/Extensions/EnumExtensions.cs +++ b/Src/Notion.Client/Extensions/EnumExtensions.cs @@ -1,15 +1,18 @@ -using System.Linq; +using System; +using System.Linq; using System.Runtime.Serialization; namespace Notion.Client.Extensions { public static class EnumExtensions { - public static string GetEnumMemberValue(this T enumValue) where T : System.Enum + public static string GetEnumMemberValue(this T enumValue) where T : Enum { var enumType = typeof(T); var memInfo = enumType.GetMember(enumValue.ToString()); - var attr = memInfo.FirstOrDefault()?.GetCustomAttributes(false).OfType().FirstOrDefault(); + + var attr = memInfo.FirstOrDefault()?.GetCustomAttributes(false).OfType() + .FirstOrDefault(); if (attr != null) { diff --git a/Src/Notion.Client/Extensions/HttpResponseMessageExtensions.cs b/Src/Notion.Client/Extensions/HttpResponseMessageExtensions.cs index 9b01580d..cc6f9698 100644 --- a/Src/Notion.Client/Extensions/HttpResponseMessageExtensions.cs +++ b/Src/Notion.Client/Extensions/HttpResponseMessageExtensions.cs @@ -7,29 +7,19 @@ namespace Notion.Client.Extensions { internal static class HttpResponseMessageExtensions { - internal static async Task ParseStreamAsync(this HttpResponseMessage response, JsonSerializerSettings serializerSettings = null) + internal static async Task ParseStreamAsync( + this HttpResponseMessage response, + JsonSerializerSettings serializerSettings = null) { - using (Stream stream = await response.Content.ReadAsStreamAsync()) - { - using (StreamReader streamReader = new StreamReader(stream)) - { - using (JsonReader jsonReader = new JsonTextReader(streamReader)) - { - JsonSerializer serializer = null; + using var stream = await response.Content.ReadAsStreamAsync(); + using var streamReader = new StreamReader(stream); + using JsonReader jsonReader = new JsonTextReader(streamReader); - if (serializerSettings == null) - { - serializer = JsonSerializer.CreateDefault(); - } - else - { - serializer = JsonSerializer.Create(serializerSettings); - } + var serializer = serializerSettings == null + ? JsonSerializer.CreateDefault() + : JsonSerializer.Create(serializerSettings); - return serializer.Deserialize(jsonReader); - } - } - } + return serializer.Deserialize(jsonReader); } } } diff --git a/Src/Notion.Client/Logging/Log.cs b/Src/Notion.Client/Logging/Log.cs index 7fda66a5..47beea5e 100644 --- a/Src/Notion.Client/Logging/Log.cs +++ b/Src/Notion.Client/Logging/Log.cs @@ -1,25 +1,27 @@ using System; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Logging; namespace Notion.Client { internal static class Log { - internal static ILogger logger; + internal static ILogger Logger; internal static void Trace(string message, params object[] args) { - logger?.LogTrace(message, args); + Logger?.LogTrace(message, args); } + [SuppressMessage("ReSharper", "UnusedMember.Global")] internal static void Information(string message, params object[] args) { - logger?.LogInformation(message, args); + Logger?.LogInformation(message, args); } internal static void Error(Exception ex, string message, params object[] args) { - logger?.LogError(ex, message, args); + Logger?.LogError(ex, message, args); } } } diff --git a/Src/Notion.Client/Logging/NotionClientLogging.cs b/Src/Notion.Client/Logging/NotionClientLogging.cs index b77ff15e..07a18514 100644 --- a/Src/Notion.Client/Logging/NotionClientLogging.cs +++ b/Src/Notion.Client/Logging/NotionClientLogging.cs @@ -1,16 +1,19 @@ -using Microsoft.Extensions.Logging; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.Logging; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedType.Global")] + [SuppressMessage("ReSharper", "UnusedMember.Global")] public static class NotionClientLogging { - internal static ILoggerFactory factory; + private static ILoggerFactory _factory; public static void ConfigureLogger(ILoggerFactory loggerFactory) { - factory = loggerFactory; + _factory = loggerFactory; - Log.logger = Log.logger == null ? factory?.CreateLogger("Notion.Client") : Log.logger; + Log.Logger = Log.Logger == null ? _factory?.CreateLogger("Notion.Client") : Log.Logger; } } } diff --git a/Src/Notion.Client/Models/Blocks/AudioBlock.cs b/Src/Notion.Client/Models/Blocks/AudioBlock.cs index 040f346b..1ba1a4a3 100644 --- a/Src/Notion.Client/Models/Blocks/AudioBlock.cs +++ b/Src/Notion.Client/Models/Blocks/AudioBlock.cs @@ -4,9 +4,9 @@ namespace Notion.Client { public class AudioBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Audio; - [JsonProperty("audio")] public FileObject Audio { get; set; } + + public override BlockType Type => BlockType.Audio; } } diff --git a/Src/Notion.Client/Models/Blocks/Block.cs b/Src/Notion.Client/Models/Blocks/Block.cs index 1baf2533..fa1ef612 100644 --- a/Src/Notion.Client/Models/Blocks/Block.cs +++ b/Src/Notion.Client/Models/Blocks/Block.cs @@ -1,5 +1,4 @@ using System; -using Notion.Client.Models.Blocks; namespace Notion.Client { @@ -17,12 +16,14 @@ 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; } /// - /// Information about the block's parent. + /// Information about the block's parent. /// public IBlockParent Parent { get; set; } } diff --git a/Src/Notion.Client/Models/Blocks/BlockType.cs b/Src/Notion.Client/Models/Blocks/BlockType.cs index f3181b22..92de4b6b 100644 --- a/Src/Notion.Client/Models/Blocks/BlockType.cs +++ b/Src/Notion.Client/Models/Blocks/BlockType.cs @@ -1,4 +1,5 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { @@ -8,12 +9,15 @@ public enum BlockType Paragraph, [EnumMember(Value = "heading_1")] + [SuppressMessage("ReSharper", "InconsistentNaming")] Heading_1, [EnumMember(Value = "heading_2")] + [SuppressMessage("ReSharper", "InconsistentNaming")] Heading_2, [EnumMember(Value = "heading_3")] + [SuppressMessage("ReSharper", "InconsistentNaming")] Heading_3, [EnumMember(Value = "bulleted_list_item")] @@ -97,6 +101,9 @@ public enum BlockType [EnumMember(Value = "table_row")] TableRow, + [EnumMember(Value = "link_preview")] + LinkPreview, + [EnumMember(Value = "unsupported")] Unsupported } diff --git a/Src/Notion.Client/Models/Blocks/BookmarkBlock.cs b/Src/Notion.Client/Models/Blocks/BookmarkBlock.cs index 735b1725..73099c82 100644 --- a/Src/Notion.Client/Models/Blocks/BookmarkBlock.cs +++ b/Src/Notion.Client/Models/Blocks/BookmarkBlock.cs @@ -5,11 +5,11 @@ namespace Notion.Client { public class BookmarkBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Bookmark; - [JsonProperty("bookmark")] public Info Bookmark { get; set; } + public override BlockType Type => BlockType.Bookmark; + public class Info { [JsonProperty("url")] diff --git a/Src/Notion.Client/Models/Blocks/BreadcrumbBlock.cs b/Src/Notion.Client/Models/Blocks/BreadcrumbBlock.cs index 73ae614d..d5585a40 100644 --- a/Src/Notion.Client/Models/Blocks/BreadcrumbBlock.cs +++ b/Src/Notion.Client/Models/Blocks/BreadcrumbBlock.cs @@ -4,11 +4,11 @@ namespace Notion.Client { public class BreadcrumbBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Breadcrumb; - [JsonProperty("breadcrumb")] public Data Breadcrumb { get; set; } + public override BlockType Type => BlockType.Breadcrumb; + public class Data { } diff --git a/Src/Notion.Client/Models/Blocks/BulletedListItemBlock.cs b/Src/Notion.Client/Models/Blocks/BulletedListItemBlock.cs index 7eca3397..c823b4bd 100644 --- a/Src/Notion.Client/Models/Blocks/BulletedListItemBlock.cs +++ b/Src/Notion.Client/Models/Blocks/BulletedListItemBlock.cs @@ -6,11 +6,11 @@ namespace Notion.Client { public class BulletedListItemBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.BulletedListItem; - [JsonProperty("bulleted_list_item")] public Info BulletedListItem { get; set; } + public override BlockType Type => BlockType.BulletedListItem; + public class Info { [JsonProperty("rich_text")] diff --git a/Src/Notion.Client/Models/Blocks/CalloutBlock.cs b/Src/Notion.Client/Models/Blocks/CalloutBlock.cs index 8cc4bb7a..d4ef61c4 100644 --- a/Src/Notion.Client/Models/Blocks/CalloutBlock.cs +++ b/Src/Notion.Client/Models/Blocks/CalloutBlock.cs @@ -6,11 +6,11 @@ namespace Notion.Client { public class CalloutBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Callout; - [JsonProperty("callout")] public Info Callout { get; set; } + public override BlockType Type => BlockType.Callout; + public class Info { [JsonProperty("rich_text")] diff --git a/Src/Notion.Client/Models/Blocks/ChildDatabaseBlock.cs b/Src/Notion.Client/Models/Blocks/ChildDatabaseBlock.cs index 273836a9..e56fcadb 100644 --- a/Src/Notion.Client/Models/Blocks/ChildDatabaseBlock.cs +++ b/Src/Notion.Client/Models/Blocks/ChildDatabaseBlock.cs @@ -4,11 +4,11 @@ namespace Notion.Client { public class ChildDatabaseBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.ChildDatabase; - [JsonProperty("child_database")] public Info ChildDatabase { get; set; } + public override BlockType Type => BlockType.ChildDatabase; + public class Info { [JsonProperty("title")] diff --git a/Src/Notion.Client/Models/Blocks/ChildPageBlock.cs b/Src/Notion.Client/Models/Blocks/ChildPageBlock.cs index 91c8f343..216b0d82 100644 --- a/Src/Notion.Client/Models/Blocks/ChildPageBlock.cs +++ b/Src/Notion.Client/Models/Blocks/ChildPageBlock.cs @@ -4,11 +4,11 @@ namespace Notion.Client { public class ChildPageBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.ChildPage; - [JsonProperty("child_page")] public Info ChildPage { get; set; } + public override BlockType Type => BlockType.ChildPage; + public class Info { [JsonProperty("title")] diff --git a/Src/Notion.Client/Models/Blocks/CodeBlock.cs b/Src/Notion.Client/Models/Blocks/CodeBlock.cs index 5eb1456b..9cb2c350 100644 --- a/Src/Notion.Client/Models/Blocks/CodeBlock.cs +++ b/Src/Notion.Client/Models/Blocks/CodeBlock.cs @@ -5,11 +5,11 @@ namespace Notion.Client { public class CodeBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Code; - [JsonProperty("code")] public Info Code { get; set; } + public override BlockType Type => BlockType.Code; + public class Info { [JsonProperty("rich_text")] diff --git a/Src/Notion.Client/Models/Blocks/Color.cs b/Src/Notion.Client/Models/Blocks/Color.cs index b4682a7b..46e38e2a 100644 --- a/Src/Notion.Client/Models/Blocks/Color.cs +++ b/Src/Notion.Client/Models/Blocks/Color.cs @@ -1,7 +1,9 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum Color { [EnumMember(Value = "default")] @@ -59,6 +61,6 @@ public enum Color PinkBackground, [EnumMember(Value = "red_background")] - RedBackground, + RedBackground } } diff --git a/Src/Notion.Client/Models/Blocks/ColumnListBlock.cs b/Src/Notion.Client/Models/Blocks/ColumnListBlock.cs index f86ecba0..59bd6245 100644 --- a/Src/Notion.Client/Models/Blocks/ColumnListBlock.cs +++ b/Src/Notion.Client/Models/Blocks/ColumnListBlock.cs @@ -5,11 +5,11 @@ namespace Notion.Client { public class ColumnListBlock : Block, INonColumnBlock { - public override BlockType Type => BlockType.ColumnList; - [JsonProperty("column_list")] public Info ColumnList { get; set; } + public override BlockType Type => BlockType.ColumnList; + public class Info { [JsonProperty("children")] diff --git a/Src/Notion.Client/Models/Blocks/DividerBlock.cs b/Src/Notion.Client/Models/Blocks/DividerBlock.cs index 61e0301b..26c55783 100644 --- a/Src/Notion.Client/Models/Blocks/DividerBlock.cs +++ b/Src/Notion.Client/Models/Blocks/DividerBlock.cs @@ -4,11 +4,11 @@ namespace Notion.Client { public class DividerBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Divider; - [JsonProperty("divider")] public Data Divider { get; set; } + public override BlockType Type => BlockType.Divider; + public class Data { } diff --git a/Src/Notion.Client/Models/Blocks/EmbedBlock.cs b/Src/Notion.Client/Models/Blocks/EmbedBlock.cs index bbd93e10..92c1dfdd 100644 --- a/Src/Notion.Client/Models/Blocks/EmbedBlock.cs +++ b/Src/Notion.Client/Models/Blocks/EmbedBlock.cs @@ -5,11 +5,11 @@ namespace Notion.Client { public class EmbedBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Embed; - [JsonProperty("embed")] public Info Embed { get; set; } + public override BlockType Type => BlockType.Embed; + public class Info { [JsonProperty("url")] @@ -17,7 +17,6 @@ public class Info [JsonProperty("caption")] public IEnumerable Caption { get; set; } - } } } diff --git a/Src/Notion.Client/Models/Blocks/EquationBlock.cs b/Src/Notion.Client/Models/Blocks/EquationBlock.cs index 310a76df..411c4e3b 100644 --- a/Src/Notion.Client/Models/Blocks/EquationBlock.cs +++ b/Src/Notion.Client/Models/Blocks/EquationBlock.cs @@ -4,11 +4,11 @@ namespace Notion.Client { public class EquationBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Equation; - [JsonProperty("equation")] public Info Equation { get; set; } + public override BlockType Type => BlockType.Equation; + public class Info { [JsonProperty("expression")] diff --git a/Src/Notion.Client/Models/Blocks/FileBlock.cs b/Src/Notion.Client/Models/Blocks/FileBlock.cs index 5495e4bc..7749a693 100644 --- a/Src/Notion.Client/Models/Blocks/FileBlock.cs +++ b/Src/Notion.Client/Models/Blocks/FileBlock.cs @@ -4,9 +4,9 @@ namespace Notion.Client { public class FileBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.File; - [JsonProperty("file")] public FileObject File { get; set; } + + public override BlockType Type => BlockType.File; } } diff --git a/Src/Notion.Client/Models/Blocks/HeadingOneBlock.cs b/Src/Notion.Client/Models/Blocks/HeadingOneBlock.cs index 853f9ae5..1e8474a4 100644 --- a/Src/Notion.Client/Models/Blocks/HeadingOneBlock.cs +++ b/Src/Notion.Client/Models/Blocks/HeadingOneBlock.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -6,12 +7,11 @@ namespace Notion.Client { public class HeadingOneBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Heading_1; - [JsonProperty("heading_1")] + [SuppressMessage("ReSharper", "InconsistentNaming")] public Info Heading_1 { get; set; } - public override bool HasChildren => false; + public override BlockType Type => BlockType.Heading_1; public class Info { @@ -21,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 67% rename from Src/Notion.Client/Models/Blocks/HeadingThreeeBlock.cs rename to Src/Notion.Client/Models/Blocks/HeadingThreeBlock.cs index 99d9b861..e300a511 100644 --- a/Src/Notion.Client/Models/Blocks/HeadingThreeeBlock.cs +++ b/Src/Notion.Client/Models/Blocks/HeadingThreeBlock.cs @@ -1,17 +1,17 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace Notion.Client { - public class HeadingThreeeBlock : Block, IColumnChildrenBlock, INonColumnBlock + public class HeadingThreeBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Heading_3; - [JsonProperty("heading_3")] + [SuppressMessage("ReSharper", "InconsistentNaming")] public Info Heading_3 { get; set; } - public override bool HasChildren => false; + public override BlockType Type => BlockType.Heading_3; public class Info { @@ -21,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 ea074e8a..3be849a8 100644 --- a/Src/Notion.Client/Models/Blocks/HeadingTwoBlock.cs +++ b/Src/Notion.Client/Models/Blocks/HeadingTwoBlock.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -6,12 +7,11 @@ namespace Notion.Client { public class HeadingTwoBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Heading_2; - [JsonProperty("heading_2")] + [SuppressMessage("ReSharper", "InconsistentNaming")] public Info Heading_2 { get; set; } - public override bool HasChildren => false; + public override BlockType Type => BlockType.Heading_2; public class Info { @@ -21,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/IBlock.cs b/Src/Notion.Client/Models/Blocks/IBlock.cs index 58b17b93..b06a3646 100644 --- a/Src/Notion.Client/Models/Blocks/IBlock.cs +++ b/Src/Notion.Client/Models/Blocks/IBlock.cs @@ -1,42 +1,43 @@ using JsonSubTypes; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -using Notion.Client.Models.Blocks; namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(AudioBlock), BlockType.Audio)] - [JsonSubtypes.KnownSubType(typeof(BookmarkBlock), BlockType.Bookmark)] - [JsonSubtypes.KnownSubType(typeof(BreadcrumbBlock), BlockType.Breadcrumb)] - [JsonSubtypes.KnownSubType(typeof(BulletedListItemBlock), BlockType.BulletedListItem)] - [JsonSubtypes.KnownSubType(typeof(CalloutBlock), BlockType.Callout)] - [JsonSubtypes.KnownSubType(typeof(ChildPageBlock), BlockType.ChildPage)] - [JsonSubtypes.KnownSubType(typeof(ChildDatabaseBlock), BlockType.ChildDatabase)] - [JsonSubtypes.KnownSubType(typeof(CodeBlock), BlockType.Code)] - [JsonSubtypes.KnownSubType(typeof(ColumnBlock), BlockType.Column)] - [JsonSubtypes.KnownSubType(typeof(ColumnListBlock), BlockType.ColumnList)] - [JsonSubtypes.KnownSubType(typeof(DividerBlock), BlockType.Divider)] - [JsonSubtypes.KnownSubType(typeof(EmbedBlock), BlockType.Embed)] - [JsonSubtypes.KnownSubType(typeof(EquationBlock), BlockType.Equation)] - [JsonSubtypes.KnownSubType(typeof(FileBlock), BlockType.File)] - [JsonSubtypes.KnownSubType(typeof(HeadingOneBlock), BlockType.Heading_1)] - [JsonSubtypes.KnownSubType(typeof(HeadingTwoBlock), BlockType.Heading_2)] - [JsonSubtypes.KnownSubType(typeof(HeadingThreeeBlock), BlockType.Heading_3)] - [JsonSubtypes.KnownSubType(typeof(ImageBlock), BlockType.Image)] - [JsonSubtypes.KnownSubType(typeof(LinkToPageBlock), BlockType.LinkToPage)] - [JsonSubtypes.KnownSubType(typeof(NumberedListItemBlock), BlockType.NumberedListItem)] - [JsonSubtypes.KnownSubType(typeof(ParagraphBlock), BlockType.Paragraph)] - [JsonSubtypes.KnownSubType(typeof(PDFBlock), BlockType.PDF)] - [JsonSubtypes.KnownSubType(typeof(QuoteBlock), BlockType.Quote)] - [JsonSubtypes.KnownSubType(typeof(TableBlock), BlockType.Table)] - [JsonSubtypes.KnownSubType(typeof(TableRowBlock), BlockType.TableRow)] - [JsonSubtypes.KnownSubType(typeof(TableOfContentsBlock), BlockType.TableOfContents)] - [JsonSubtypes.KnownSubType(typeof(TemplateBlock), BlockType.Template)] - [JsonSubtypes.KnownSubType(typeof(ToDoBlock), BlockType.ToDo)] - [JsonSubtypes.KnownSubType(typeof(ToggleBlock), BlockType.Toggle)] - [JsonSubtypes.KnownSubType(typeof(VideoBlock), BlockType.Video)] - [JsonSubtypes.KnownSubType(typeof(UnsupportedBlock), BlockType.Unsupported)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(AudioBlock), BlockType.Audio)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(BookmarkBlock), BlockType.Bookmark)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(BreadcrumbBlock), BlockType.Breadcrumb)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(BulletedListItemBlock), BlockType.BulletedListItem)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CalloutBlock), BlockType.Callout)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ChildPageBlock), BlockType.ChildPage)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ChildDatabaseBlock), BlockType.ChildDatabase)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CodeBlock), BlockType.Code)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ColumnBlock), BlockType.Column)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ColumnListBlock), BlockType.ColumnList)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DividerBlock), BlockType.Divider)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(EmbedBlock), BlockType.Embed)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(EquationBlock), BlockType.Equation)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FileBlock), BlockType.File)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(HeadingOneBlock), BlockType.Heading_1)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(HeadingTwoBlock), BlockType.Heading_2)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(HeadingThreeBlock), BlockType.Heading_3)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ImageBlock), BlockType.Image)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(LinkPreviewBlock), BlockType.LinkPreview)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(LinkToPageBlock), BlockType.LinkToPage)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(NumberedListItemBlock), BlockType.NumberedListItem)] + [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)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(TemplateBlock), BlockType.Template)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ToDoBlock), BlockType.ToDo)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ToggleBlock), BlockType.Toggle)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(VideoBlock), BlockType.Video)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(UnsupportedBlock), BlockType.Unsupported)] public interface IBlock : IObject, IObjectModificationData { [JsonProperty("type")] @@ -46,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/Blocks/IBlockParent.cs b/Src/Notion.Client/Models/Blocks/IBlockParent.cs index 4e1d7a17..b2f8783f 100644 --- a/Src/Notion.Client/Models/Blocks/IBlockParent.cs +++ b/Src/Notion.Client/Models/Blocks/IBlockParent.cs @@ -1,14 +1,14 @@ using JsonSubTypes; using Newtonsoft.Json; -namespace Notion.Client.Models.Blocks +namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(DatabaseParent), ParentType.DatabaseId)] - [JsonSubtypes.KnownSubType(typeof(PageParent), ParentType.PageId)] - [JsonSubtypes.KnownSubType(typeof(WorkspaceParent), ParentType.Workspace)] - [JsonSubtypes.KnownSubType(typeof(BlockParent), ParentType.BlockId)] - public interface IBlockParent + [JsonSubtypes.KnownSubTypeAttribute(typeof(DatabaseParent), ParentType.DatabaseId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PageParent), ParentType.PageId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(WorkspaceParent), ParentType.Workspace)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(BlockParent), ParentType.BlockId)] + public interface IBlockParent : IParent { } } diff --git a/Src/Notion.Client/Models/Blocks/IColumnChildrenBlock.cs b/Src/Notion.Client/Models/Blocks/IColumnChildrenBlock.cs index 673bc156..769487c8 100644 --- a/Src/Notion.Client/Models/Blocks/IColumnChildrenBlock.cs +++ b/Src/Notion.Client/Models/Blocks/IColumnChildrenBlock.cs @@ -1,6 +1,6 @@ namespace Notion.Client { - public interface ITemplateChildrendBlock : IBlock + public interface ITemplateChildrenBlock : IBlock { } @@ -8,7 +8,7 @@ public interface ISyncedBlockChildren : IBlock { } - public interface IColumnChildrenBlock : IBlock, ITemplateChildrendBlock, ISyncedBlockChildren + public interface IColumnChildrenBlock : ITemplateChildrenBlock, ISyncedBlockChildren { } diff --git a/Src/Notion.Client/Models/Blocks/ImageBlock.cs b/Src/Notion.Client/Models/Blocks/ImageBlock.cs index 17aa6bae..cd6b055f 100644 --- a/Src/Notion.Client/Models/Blocks/ImageBlock.cs +++ b/Src/Notion.Client/Models/Blocks/ImageBlock.cs @@ -4,9 +4,9 @@ namespace Notion.Client { public class ImageBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Image; - [JsonProperty("image")] public FileObject Image { get; set; } + + public override BlockType Type => BlockType.Image; } } diff --git a/Src/Notion.Client/Models/Blocks/LinkPreviewBlock.cs b/Src/Notion.Client/Models/Blocks/LinkPreviewBlock.cs new file mode 100644 index 00000000..72107e48 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/LinkPreviewBlock.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LinkPreviewBlock : Block, IColumnChildrenBlock, INonColumnBlock + { + [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/LinkToPageBlock.cs b/Src/Notion.Client/Models/Blocks/LinkToPageBlock.cs index 30d3d7dd..ad688ca2 100644 --- a/Src/Notion.Client/Models/Blocks/LinkToPageBlock.cs +++ b/Src/Notion.Client/Models/Blocks/LinkToPageBlock.cs @@ -4,9 +4,9 @@ namespace Notion.Client { public class LinkToPageBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.LinkToPage; - [JsonProperty("link_to_page")] public IPageParent LinkToPage { get; set; } + + public override BlockType Type => BlockType.LinkToPage; } } diff --git a/Src/Notion.Client/Models/Blocks/NumberedListItemBlock.cs b/Src/Notion.Client/Models/Blocks/NumberedListItemBlock.cs index 3fe0d76a..f4a645e9 100644 --- a/Src/Notion.Client/Models/Blocks/NumberedListItemBlock.cs +++ b/Src/Notion.Client/Models/Blocks/NumberedListItemBlock.cs @@ -6,11 +6,11 @@ namespace Notion.Client { public class NumberedListItemBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.NumberedListItem; - [JsonProperty("numbered_list_item")] public Info NumberedListItem { get; set; } + public override BlockType Type => BlockType.NumberedListItem; + public class Info { [JsonProperty("rich_text")] diff --git a/Src/Notion.Client/Models/Blocks/PDFBlock.cs b/Src/Notion.Client/Models/Blocks/PDFBlock.cs index 85458796..6d7486d7 100644 --- a/Src/Notion.Client/Models/Blocks/PDFBlock.cs +++ b/Src/Notion.Client/Models/Blocks/PDFBlock.cs @@ -1,12 +1,14 @@ -using Newtonsoft.Json; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; namespace Notion.Client { + [SuppressMessage("ReSharper", "InconsistentNaming")] public class PDFBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.PDF; - [JsonProperty("pdf")] public FileObject PDF { get; set; } + + public override BlockType Type => BlockType.PDF; } } diff --git a/Src/Notion.Client/Models/Blocks/ParagraphBlock.cs b/Src/Notion.Client/Models/Blocks/ParagraphBlock.cs index 67458b3c..f3b73f36 100644 --- a/Src/Notion.Client/Models/Blocks/ParagraphBlock.cs +++ b/Src/Notion.Client/Models/Blocks/ParagraphBlock.cs @@ -6,11 +6,11 @@ namespace Notion.Client { public class ParagraphBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Paragraph; - [JsonProperty("paragraph")] public Info Paragraph { get; set; } + public override BlockType Type => BlockType.Paragraph; + public class Info { [JsonProperty("rich_text")] diff --git a/Src/Notion.Client/Models/Blocks/QuoteBlock.cs b/Src/Notion.Client/Models/Blocks/QuoteBlock.cs index 5fdad7da..e1466be6 100644 --- a/Src/Notion.Client/Models/Blocks/QuoteBlock.cs +++ b/Src/Notion.Client/Models/Blocks/QuoteBlock.cs @@ -6,11 +6,11 @@ namespace Notion.Client { public class QuoteBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Quote; - [JsonProperty("quote")] public Info Quote { get; set; } + public override BlockType Type => BlockType.Quote; + public class Info { [JsonProperty("rich_text")] 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; + } +} diff --git a/Src/Notion.Client/Models/Blocks/SyncedBlockBlock.cs b/Src/Notion.Client/Models/Blocks/SyncedBlockBlock.cs index 33c4dd25..98aa1d0f 100644 --- a/Src/Notion.Client/Models/Blocks/SyncedBlockBlock.cs +++ b/Src/Notion.Client/Models/Blocks/SyncedBlockBlock.cs @@ -5,11 +5,11 @@ namespace Notion.Client { public class SyncedBlockBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.SyncedBlock; - [JsonProperty("synced_block")] public Data SyncedBlock { get; set; } + public override BlockType Type => BlockType.SyncedBlock; + public class Data { [JsonProperty("synced_from")] diff --git a/Src/Notion.Client/Models/Blocks/TableBlock.cs b/Src/Notion.Client/Models/Blocks/TableBlock.cs index dd20d94b..80fe72bc 100644 --- a/Src/Notion.Client/Models/Blocks/TableBlock.cs +++ b/Src/Notion.Client/Models/Blocks/TableBlock.cs @@ -1,15 +1,16 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using Newtonsoft.Json; namespace Notion.Client { public class TableBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Table; - [JsonProperty("table")] - public TableInfo Table { get; set; } + public Info Table { get; set; } + + public override BlockType Type => BlockType.Table; - public class TableInfo + public class Info { [JsonProperty("table_width")] public int TableWidth { get; set; } @@ -21,7 +22,7 @@ public class TableInfo public bool HasRowHeader { get; set; } [JsonProperty("children")] - public TableRowBlock Children { get; set; } + public IEnumerable Children { get; set; } } } } diff --git a/Src/Notion.Client/Models/Blocks/TableOfContentsBlock.cs b/Src/Notion.Client/Models/Blocks/TableOfContentsBlock.cs index 991ff903..0a6c9f26 100644 --- a/Src/Notion.Client/Models/Blocks/TableOfContentsBlock.cs +++ b/Src/Notion.Client/Models/Blocks/TableOfContentsBlock.cs @@ -5,11 +5,11 @@ namespace Notion.Client { public class TableOfContentsBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.TableOfContents; - [JsonProperty("table_of_contents")] public Data TableOfContents { get; set; } + public override BlockType Type => BlockType.TableOfContents; + public class Data { [JsonProperty("color")] diff --git a/Src/Notion.Client/Models/Blocks/TableRowBlock.cs b/Src/Notion.Client/Models/Blocks/TableRowBlock.cs index e7214e6c..be105447 100644 --- a/Src/Notion.Client/Models/Blocks/TableRowBlock.cs +++ b/Src/Notion.Client/Models/Blocks/TableRowBlock.cs @@ -5,11 +5,11 @@ namespace Notion.Client { public class TableRowBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.TableRow; - [JsonProperty("table_row")] public Info TableRow { get; set; } + public override BlockType Type => BlockType.TableRow; + public class Info { [JsonProperty("cells")] diff --git a/Src/Notion.Client/Models/Blocks/TemplateBlock.cs b/Src/Notion.Client/Models/Blocks/TemplateBlock.cs index 69a78b62..867e7c85 100644 --- a/Src/Notion.Client/Models/Blocks/TemplateBlock.cs +++ b/Src/Notion.Client/Models/Blocks/TemplateBlock.cs @@ -5,18 +5,18 @@ namespace Notion.Client { public class TemplateBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Template; - [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; } + public IEnumerable Children { get; set; } } } } diff --git a/Src/Notion.Client/Models/Blocks/ToDoBlock.cs b/Src/Notion.Client/Models/Blocks/ToDoBlock.cs index 8b153f3b..0c52201a 100644 --- a/Src/Notion.Client/Models/Blocks/ToDoBlock.cs +++ b/Src/Notion.Client/Models/Blocks/ToDoBlock.cs @@ -6,11 +6,11 @@ namespace Notion.Client { public class ToDoBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.ToDo; - [JsonProperty("to_do")] public Info ToDo { get; set; } + public override BlockType Type => BlockType.ToDo; + public class Info { [JsonProperty("rich_text")] diff --git a/Src/Notion.Client/Models/Blocks/ToggleBlock.cs b/Src/Notion.Client/Models/Blocks/ToggleBlock.cs index 6646e9be..f61a1368 100644 --- a/Src/Notion.Client/Models/Blocks/ToggleBlock.cs +++ b/Src/Notion.Client/Models/Blocks/ToggleBlock.cs @@ -6,11 +6,11 @@ namespace Notion.Client { public class ToggleBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Toggle; - [JsonProperty("toggle")] public Info Toggle { get; set; } + public override BlockType Type => BlockType.Toggle; + public class Info { [JsonProperty("rich_text")] diff --git a/Src/Notion.Client/Models/Blocks/VideoBlock.cs b/Src/Notion.Client/Models/Blocks/VideoBlock.cs index 015bed96..7713ff7b 100644 --- a/Src/Notion.Client/Models/Blocks/VideoBlock.cs +++ b/Src/Notion.Client/Models/Blocks/VideoBlock.cs @@ -4,9 +4,9 @@ namespace Notion.Client { public class VideoBlock : Block, IColumnChildrenBlock, INonColumnBlock { - public override BlockType Type => BlockType.Video; - [JsonProperty("video")] public FileObject Video { get; set; } + + public override BlockType Type => BlockType.Video; } } diff --git a/Src/Notion.Client/Models/Common/IObjectModificationData.cs b/Src/Notion.Client/Models/Common/IObjectModificationData.cs index 06177ccd..0e70ffcf 100644 --- a/Src/Notion.Client/Models/Common/IObjectModificationData.cs +++ b/Src/Notion.Client/Models/Common/IObjectModificationData.cs @@ -6,25 +6,25 @@ namespace Notion.Client public interface IObjectModificationData { /// - /// Date and time when this object was created. + /// Date and time when this object was created. /// [JsonProperty("created_time")] DateTime CreatedTime { get; set; } /// - /// Date and time when this object was updated. + /// Date and time when this object was updated. /// [JsonProperty("last_edited_time")] DateTime LastEditedTime { get; set; } /// - /// User who created the object. + /// User who created the object. /// [JsonProperty("created_by")] PartialUser CreatedBy { get; set; } /// - /// User who last modified the object. + /// User who last modified the object. /// [JsonProperty("last_edited_by")] PartialUser LastEditedBy { get; set; } 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/Database/Database.cs b/Src/Notion.Client/Models/Database/Database.cs index 502d8a5a..be288ea0 100644 --- a/Src/Notion.Client/Models/Database/Database.cs +++ b/Src/Notion.Client/Models/Database/Database.cs @@ -4,18 +4,8 @@ namespace Notion.Client { - public class Database : IObject, IObjectModificationData + public class Database : IObject, IObjectModificationData, IWikiDatabase { - public ObjectType Object => ObjectType.Database; - - public string Id { get; set; } - - [JsonProperty("created_time")] - public DateTime CreatedTime { get; set; } - - [JsonProperty("last_edited_time")] - public DateTime LastEditedTime { get; set; } - [JsonProperty("title")] public List Title { get; set; } @@ -32,25 +22,38 @@ public class Database : IObject, IObjectModificationData public FileObject Cover { get; set; } /// - /// The URL of the Notion database. + /// The URL of the Notion database. /// [JsonProperty("url")] public string Url { get; set; } - /// - /// The archived status of the database. - /// - [JsonProperty("archived")] - public bool Archived { get; set; } - - public PartialUser CreatedBy { get; set; } - - public PartialUser LastEditedBy { get; set; } + [JsonProperty("in_trash")] + public bool InTrash { get; set; } [JsonProperty("is_inline")] public bool IsInline { get; set; } [JsonProperty("description")] public IEnumerable Description { get; set; } + + public ObjectType Object => ObjectType.Database; + + public string Id { get; set; } + + [JsonProperty("created_time")] + public DateTime CreatedTime { get; set; } + + [JsonProperty("last_edited_time")] + public DateTime LastEditedTime { get; set; } + + 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/Database/IDatabaseParent.cs b/Src/Notion.Client/Models/Database/IDatabaseParent.cs index 59233c38..768f815b 100644 --- a/Src/Notion.Client/Models/Database/IDatabaseParent.cs +++ b/Src/Notion.Client/Models/Database/IDatabaseParent.cs @@ -4,9 +4,9 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(PageParent), ParentType.PageId)] - [JsonSubtypes.KnownSubType(typeof(WorkspaceParent), ParentType.Workspace)] - [JsonSubtypes.KnownSubType(typeof(BlockParent), ParentType.BlockId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PageParent), ParentType.PageId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(WorkspaceParent), ParentType.Workspace)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(BlockParent), ParentType.BlockId)] public interface IDatabaseParent : IParent { } diff --git a/Src/Notion.Client/Models/Database/IWikiDatabase.cs b/Src/Notion.Client/Models/Database/IWikiDatabase.cs new file mode 100644 index 00000000..59969175 --- /dev/null +++ b/Src/Notion.Client/Models/Database/IWikiDatabase.cs @@ -0,0 +1,12 @@ +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/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 1f61b0dc..6392bbaf 100644 --- a/Src/Notion.Client/Models/Database/Properties/Property.cs +++ b/Src/Notion.Client/Models/Database/Properties/Property.cs @@ -5,26 +5,28 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(CheckboxProperty), PropertyType.Checkbox)] - [JsonSubtypes.KnownSubType(typeof(CreatedByProperty), PropertyType.CreatedBy)] - [JsonSubtypes.KnownSubType(typeof(CreatedTimeProperty), PropertyType.CreatedTime)] - [JsonSubtypes.KnownSubType(typeof(DateProperty), PropertyType.Date)] - [JsonSubtypes.KnownSubType(typeof(EmailProperty), PropertyType.Email)] - [JsonSubtypes.KnownSubType(typeof(FilesProperty), PropertyType.Files)] - [JsonSubtypes.KnownSubType(typeof(FormulaProperty), PropertyType.Formula)] - [JsonSubtypes.KnownSubType(typeof(LastEditedByProperty), PropertyType.LastEditedBy)] - [JsonSubtypes.KnownSubType(typeof(LastEditedTimeProperty), PropertyType.LastEditedTime)] - [JsonSubtypes.KnownSubType(typeof(MultiSelectProperty), PropertyType.MultiSelect)] - [JsonSubtypes.KnownSubType(typeof(NumberProperty), PropertyType.Number)] - [JsonSubtypes.KnownSubType(typeof(PeopleProperty), PropertyType.People)] - [JsonSubtypes.KnownSubType(typeof(PhoneNumberProperty), PropertyType.PhoneNumber)] - [JsonSubtypes.KnownSubType(typeof(RelationProperty), PropertyType.Relation)] - [JsonSubtypes.KnownSubType(typeof(RichTextProperty), PropertyType.RichText)] - [JsonSubtypes.KnownSubType(typeof(RollupProperty), PropertyType.Rollup)] - [JsonSubtypes.KnownSubType(typeof(SelectProperty), PropertyType.Select)] - [JsonSubtypes.KnownSubType(typeof(StatusProperty), PropertyType.Status)] - [JsonSubtypes.KnownSubType(typeof(TitleProperty), PropertyType.Title)] - [JsonSubtypes.KnownSubType(typeof(UrlProperty), PropertyType.Url)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CheckboxProperty), PropertyType.Checkbox)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CreatedByProperty), PropertyType.CreatedBy)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CreatedTimeProperty), PropertyType.CreatedTime)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DateProperty), PropertyType.Date)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(EmailProperty), PropertyType.Email)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FilesProperty), PropertyType.Files)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FormulaProperty), PropertyType.Formula)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(LastEditedByProperty), PropertyType.LastEditedBy)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(LastEditedTimeProperty), PropertyType.LastEditedTime)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(MultiSelectProperty), PropertyType.MultiSelect)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(NumberProperty), PropertyType.Number)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PeopleProperty), PropertyType.People)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PhoneNumberProperty), PropertyType.PhoneNumber)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RelationProperty), PropertyType.Relation)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RichTextProperty), PropertyType.RichText)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RollupProperty), PropertyType.Rollup)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(SelectProperty), PropertyType.Select)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(StatusProperty), PropertyType.Status)] + [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 a67b8cd8..206f9fe2 100644 --- a/Src/Notion.Client/Models/Database/Properties/PropertyType.cs +++ b/Src/Notion.Client/Models/Database/Properties/PropertyType.cs @@ -1,7 +1,9 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum PropertyType { [EnumMember(Value = null)] @@ -66,5 +68,11 @@ public enum PropertyType [EnumMember(Value = "status")] Status, + + [EnumMember(Value = "unique_id")] + UniqueId, + + [EnumMember(Value = "button")] + Button, } } diff --git a/Src/Notion.Client/Models/Database/Properties/RelationProperty.cs b/Src/Notion.Client/Models/Database/Properties/RelationProperty.cs deleted file mode 100644 index 48ffc4e3..00000000 --- a/Src/Notion.Client/Models/Database/Properties/RelationProperty.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class RelationProperty : Property - { - public override PropertyType Type => PropertyType.Relation; - - - [JsonProperty("relation")] - public Relation Relation { get; set; } - } - - public class Relation - { - [JsonProperty("database_id")] - public string DatabaseId { get; set; } - - [JsonProperty("synced_property_name")] - public string SyncedPropertyName { get; set; } - - [JsonProperty("synced_property_id")] - public string SyncedPropertyId { get; set; } - } -} diff --git a/Src/Notion.Client/Models/Database/Properties/RelationProperty/DualPropertyRelation.cs b/Src/Notion.Client/Models/Database/Properties/RelationProperty/DualPropertyRelation.cs new file mode 100644 index 00000000..f1c8c1ec --- /dev/null +++ b/Src/Notion.Client/Models/Database/Properties/RelationProperty/DualPropertyRelation.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DualPropertyRelation : RelationData + { + public override RelationType Type => RelationType.Dual; + + [JsonProperty("dual_property")] + public Data DualProperty { get; set; } + + public class Data + { + [JsonProperty("synced_property_name")] + public string SyncedPropertyName { get; set; } + + [JsonProperty("synced_property_id")] + public string SyncedPropertyId { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Database/Properties/RelationProperty/RelationData.cs b/Src/Notion.Client/Models/Database/Properties/RelationProperty/RelationData.cs new file mode 100644 index 00000000..d129acc6 --- /dev/null +++ b/Src/Notion.Client/Models/Database/Properties/RelationProperty/RelationData.cs @@ -0,0 +1,19 @@ +using JsonSubTypes; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(SinglePropertyRelation), RelationType.Single)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DualPropertyRelation), RelationType.Dual)] + public abstract class RelationData + { + [JsonProperty("database_id")] + public string DatabaseId { get; set; } + + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public virtual RelationType Type { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Database/Properties/RelationProperty/RelationProperty.cs b/Src/Notion.Client/Models/Database/Properties/RelationProperty/RelationProperty.cs new file mode 100644 index 00000000..382e7088 --- /dev/null +++ b/Src/Notion.Client/Models/Database/Properties/RelationProperty/RelationProperty.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class RelationProperty : Property + { + public override PropertyType Type => PropertyType.Relation; + + [JsonProperty("relation")] + public RelationData Relation { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Database/Properties/RelationProperty/RelationType.cs b/Src/Notion.Client/Models/Database/Properties/RelationProperty/RelationType.cs new file mode 100644 index 00000000..89ce1c56 --- /dev/null +++ b/Src/Notion.Client/Models/Database/Properties/RelationProperty/RelationType.cs @@ -0,0 +1,13 @@ +using System.Runtime.Serialization; + +namespace Notion.Client +{ + public enum RelationType + { + [EnumMember(Value = "single_property")] + Single, + + [EnumMember(Value = "dual_property")] + Dual + } +} diff --git a/Src/Notion.Client/Models/Database/Properties/RelationProperty/SinglePropertyRelation.cs b/Src/Notion.Client/Models/Database/Properties/RelationProperty/SinglePropertyRelation.cs new file mode 100644 index 00000000..9ba8ae12 --- /dev/null +++ b/Src/Notion.Client/Models/Database/Properties/RelationProperty/SinglePropertyRelation.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class SinglePropertyRelation : RelationData + { + public override RelationType Type => RelationType.Single; + + [JsonProperty("single_property")] + public Dictionary SingleProperty { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Database/Properties/SelectProperty.cs b/Src/Notion.Client/Models/Database/Properties/SelectProperty.cs index 3ed99234..f9675443 100644 --- a/Src/Notion.Client/Models/Database/Properties/SelectProperty.cs +++ b/Src/Notion.Client/Models/Database/Properties/SelectProperty.cs @@ -1,12 +1,15 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")] public class SelectProperty : Property { public override PropertyType Type => PropertyType.Select; + public OptionWrapper Select { get; set; } } @@ -19,19 +22,20 @@ public class OptionWrapper public class SelectOption { /// - /// Name of the option as it appears in Notion. + /// Name of the option as it appears in Notion. /// [JsonProperty("name")] public string Name { get; set; } /// - /// ID of the option. + /// ID of the option. /// [JsonProperty("id")] public string Id { get; set; } /// - /// Color of the option. Possible values are: "default", "gray", "brown", "red", "orange", "yellow", "green", "blue", "purple", "pink". Defaults to "default". + /// Color of the option. Possible values are: "default", "gray", "brown", "red", "orange", "yellow", "green", "blue", + /// "purple", "pink". Defaults to "default". /// [JsonProperty("color")] [JsonConverter(typeof(StringEnumConverter))] 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..4a9e9d5d --- /dev/null +++ b/Src/Notion.Client/Models/Database/Properties/UniqueIdProperty.cs @@ -0,0 +1,14 @@ +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/Src/Notion.Client/Models/Database/RichText/RichTextBase.cs b/Src/Notion.Client/Models/Database/RichText/RichTextBase.cs index 88af1acd..3f10d578 100644 --- a/Src/Notion.Client/Models/Database/RichText/RichTextBase.cs +++ b/Src/Notion.Client/Models/Database/RichText/RichTextBase.cs @@ -5,9 +5,9 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(RichTextText), RichTextType.Text)] - [JsonSubtypes.KnownSubType(typeof(RichTextEquation), RichTextType.Equation)] - [JsonSubtypes.KnownSubType(typeof(RichTextMention), RichTextType.Mention)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RichTextText), RichTextType.Text)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RichTextEquation), RichTextType.Equation)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RichTextMention), RichTextType.Mention)] public class RichTextBase { [JsonProperty("plain_text")] 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/Src/Notion.Client/Models/Database/RichText/RichTextType.cs b/Src/Notion.Client/Models/Database/RichText/RichTextType.cs index 59bc414f..91031138 100644 --- a/Src/Notion.Client/Models/Database/RichText/RichTextType.cs +++ b/Src/Notion.Client/Models/Database/RichText/RichTextType.cs @@ -1,7 +1,9 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum RichTextType { [EnumMember(Value = null)] diff --git a/Src/Notion.Client/Models/EmojiObject.cs b/Src/Notion.Client/Models/EmojiObject.cs index 95c67b61..9b5c64df 100644 --- a/Src/Notion.Client/Models/EmojiObject.cs +++ b/Src/Notion.Client/Models/EmojiObject.cs @@ -4,10 +4,10 @@ namespace Notion.Client { public class EmojiObject : IPageIcon { - [JsonProperty("type")] - public string Type { get; set; } - [JsonProperty("emoji")] public string Emoji { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } } } diff --git a/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs b/Src/Notion.Client/Models/File/FIleInput/ExternalFileInput.cs index 9c258ceb..6e2627cf 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,12 @@ public class ExternalFileInput : IFileObjectInput [JsonProperty("external")] public Data External { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("caption")] + 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..949df10c 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,12 @@ public class UploadedFileInput : IFileObjectInput [JsonProperty("file")] public Data File { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("caption")] + public IEnumerable Caption { get; set; } + public class Data { [JsonProperty("url")] diff --git a/Src/Notion.Client/Models/File/FileObject.cs b/Src/Notion.Client/Models/File/FileObject.cs index ce4d02f0..0ac30a6c 100644 --- a/Src/Notion.Client/Models/File/FileObject.cs +++ b/Src/Notion.Client/Models/File/FileObject.cs @@ -5,14 +5,20 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(UploadedFile), "file")] - [JsonSubtypes.KnownSubType(typeof(ExternalFile), "external")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(UploadedFile), "file")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ExternalFile), "external")] public abstract class FileObject : IPageIcon { - [JsonProperty("type")] - public virtual string Type { get; set; } - [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; } + + [JsonProperty("type")] + public virtual string Type { get; set; } } } diff --git a/Src/Notion.Client/Models/File/FileObjectWithName.cs b/Src/Notion.Client/Models/File/FileObjectWithName.cs index a7381929..855a5e0f 100644 --- a/Src/Notion.Client/Models/File/FileObjectWithName.cs +++ b/Src/Notion.Client/Models/File/FileObjectWithName.cs @@ -4,8 +4,8 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(UploadedFileWithName), "file")] - [JsonSubtypes.KnownSubType(typeof(ExternalFileWithName), "external")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(UploadedFileWithName), "file")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ExternalFileWithName), "external")] public abstract class FileObjectWithName { [JsonProperty("type")] diff --git a/Src/Notion.Client/Models/Filters/CheckboxFilter.cs b/Src/Notion.Client/Models/Filters/CheckboxFilter.cs index da144aec..53343e35 100644 --- a/Src/Notion.Client/Models/Filters/CheckboxFilter.cs +++ b/Src/Notion.Client/Models/Filters/CheckboxFilter.cs @@ -1,35 +1,34 @@ -using System; -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Notion.Client { public class CheckboxFilter : SinglePropertyFilter, IRollupSubPropertyFilter { - [JsonProperty("checkbox")] - public Condition Checkbox { get; set; } - public CheckboxFilter( string propertyName, bool? equal = null, bool? doesNotEqual = null) { Property = propertyName; - Checkbox = new Condition(equal: equal, doesNotEqual: doesNotEqual); + Checkbox = new Condition(equal, doesNotEqual); } + [JsonProperty("checkbox")] + public Condition Checkbox { get; set; } + public class Condition { + public Condition(bool? equal = null, bool? doesNotEqual = null) + { + Equal = equal; + DoesNotEqual = doesNotEqual; + } + [JsonProperty("equals")] public bool? Equal { get; set; } [JsonProperty("does_not_equal")] public bool? DoesNotEqual { get; set; } - - public Condition(Nullable equal = null, Nullable doesNotEqual = null) - { - Equal = equal; - DoesNotEqual = doesNotEqual; - } } } } diff --git a/Src/Notion.Client/Models/Filters/DateFilter.cs b/Src/Notion.Client/Models/Filters/DateFilter.cs index 51b38dc2..dde7ad47 100644 --- a/Src/Notion.Client/Models/Filters/DateFilter.cs +++ b/Src/Notion.Client/Models/Filters/DateFilter.cs @@ -7,9 +7,6 @@ namespace Notion.Client { public class DateFilter : SinglePropertyFilter, IRollupSubPropertyFilter { - [JsonProperty("date")] - public Condition Date { get; set; } - public DateFilter( string propertyName, DateTime? equal = null, @@ -27,25 +24,59 @@ public DateFilter( bool? isNotEmpty = null) { Property = propertyName; + Date = new Condition( - equal: equal, - before: before, - after: after, - onOrBefore: onOrBefore, - onOrAfter: onOrAfter, - pastWeek: pastWeek, - pastMonth: pastMonth, - pastYear: pastYear, - nextWeek: nextWeek, - nextMonth: nextMonth, - nextYear: nextYear, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + equal, + before, + after, + onOrBefore, + onOrAfter, + pastWeek, + pastMonth, + pastYear, + nextWeek, + nextMonth, + nextYear, + isEmpty, + isNotEmpty ); } + [JsonProperty("date")] + public Condition Date { get; set; } + public class Condition { + public Condition( + DateTime? equal = null, + DateTime? before = null, + DateTime? after = null, + DateTime? onOrBefore = null, + DateTime? onOrAfter = null, + Dictionary pastWeek = null, + Dictionary pastMonth = null, + Dictionary pastYear = null, + Dictionary nextWeek = null, + Dictionary nextMonth = null, + Dictionary nextYear = null, + bool? isEmpty = null, + bool? isNotEmpty = null) + { + Equal = equal; + Before = before; + After = after; + OnOrBefore = onOrBefore; + OnOrAfter = onOrAfter; + PastWeek = pastWeek; + PastMonth = pastMonth; + PastYear = pastYear; + NextWeek = nextWeek; + NextMonth = nextMonth; + NextYear = nextYear; + IsEmpty = isEmpty; + IsNotEmpty = isNotEmpty; + } + [JsonProperty("equals")] [JsonConverter(typeof(IsoDateTimeConverter))] public DateTime? Equal { get; set; } @@ -89,36 +120,6 @@ public class Condition [JsonProperty("is_not_empty")] public bool? IsNotEmpty { get; set; } - - public Condition( - DateTime? equal = null, - DateTime? before = null, - DateTime? after = null, - DateTime? onOrBefore = null, - DateTime? onOrAfter = null, - Dictionary pastWeek = null, - Dictionary pastMonth = null, - Dictionary pastYear = null, - Dictionary nextWeek = null, - Dictionary nextMonth = null, - Dictionary nextYear = null, - bool? isEmpty = null, - bool? isNotEmpty = null) - { - Equal = equal; - Before = before; - After = after; - OnOrBefore = onOrBefore; - OnOrAfter = onOrAfter; - PastWeek = pastWeek; - PastMonth = pastMonth; - PastYear = pastYear; - NextWeek = nextWeek; - NextMonth = nextMonth; - NextYear = nextYear; - IsEmpty = isEmpty; - IsNotEmpty = isNotEmpty; - } } } } diff --git a/Src/Notion.Client/Models/Filters/EmailFilter.cs b/Src/Notion.Client/Models/Filters/EmailFilter.cs index ff5feda9..36bc3dde 100644 --- a/Src/Notion.Client/Models/Filters/EmailFilter.cs +++ b/Src/Notion.Client/Models/Filters/EmailFilter.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class EmailFilter : SinglePropertyFilter { - [JsonProperty("email")] - public TextFilter.Condition Email { get; set; } - public EmailFilter( string propertyName, string equal = null, @@ -19,16 +16,20 @@ public EmailFilter( bool? isNotEmpty = null) { Property = propertyName; + Email = new TextFilter.Condition( - equal: equal, - doesNotEqual: doesNotEqual, - contains: contains, - doesNotContain: doesNotContain, - startsWith: startsWith, - endsWith: endsWith, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + equal, + doesNotEqual, + contains, + doesNotContain, + startsWith, + endsWith, + isEmpty, + isNotEmpty ); } + + [JsonProperty("email")] + public TextFilter.Condition Email { get; set; } } } diff --git a/Src/Notion.Client/Models/Filters/FilesFilter.cs b/Src/Notion.Client/Models/Filters/FilesFilter.cs index a32d4d7b..6c4b23c6 100644 --- a/Src/Notion.Client/Models/Filters/FilesFilter.cs +++ b/Src/Notion.Client/Models/Filters/FilesFilter.cs @@ -4,26 +4,20 @@ namespace Notion.Client { public class FilesFilter : SinglePropertyFilter, IRollupSubPropertyFilter { - [JsonProperty("files")] - public Condition Files { get; set; } - public FilesFilter( string propertyName, bool? isEmpty = null, bool? isNotEmpty = null) { Property = propertyName; - Files = new Condition(isEmpty: isEmpty, isNotEmpty: isNotEmpty); + Files = new Condition(isEmpty, isNotEmpty); } + [JsonProperty("files")] + public Condition Files { get; set; } + public class Condition { - [JsonProperty("is_empty")] - public bool? IsEmpty { get; set; } - - [JsonProperty("is_not_empty")] - public bool? IsNotEmpty { get; set; } - public Condition( bool? isEmpty = null, bool? isNotEmpty = null) @@ -31,6 +25,12 @@ public Condition( IsEmpty = isEmpty; IsNotEmpty = isNotEmpty; } + + [JsonProperty("is_empty")] + public bool? IsEmpty { get; set; } + + [JsonProperty("is_not_empty")] + public bool? IsNotEmpty { get; set; } } } } diff --git a/Src/Notion.Client/Models/Filters/Filter.cs b/Src/Notion.Client/Models/Filters/Filter.cs index 61f81f7e..47eced53 100644 --- a/Src/Notion.Client/Models/Filters/Filter.cs +++ b/Src/Notion.Client/Models/Filters/Filter.cs @@ -5,7 +5,6 @@ namespace Notion.Client { public class Filter { - } public class SinglePropertyFilter : Filter @@ -16,16 +15,16 @@ public class SinglePropertyFilter : Filter public class CompoundFilter : Filter { - [JsonProperty("or")] - public List Or { get; set; } - - [JsonProperty("and")] - public List And { get; set; } - public CompoundFilter(List or = null, List and = null) { Or = or; And = and; } + + [JsonProperty("or")] + public List Or { get; set; } + + [JsonProperty("and")] + public List And { get; set; } } } diff --git a/Src/Notion.Client/Models/Filters/FormulaFilter.cs b/Src/Notion.Client/Models/Filters/FormulaFilter.cs index eee9fc52..5aec5e00 100644 --- a/Src/Notion.Client/Models/Filters/FormulaFilter.cs +++ b/Src/Notion.Client/Models/Filters/FormulaFilter.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class FormulaFilter : SinglePropertyFilter { - [JsonProperty("formula")] - public Condition Formula { get; set; } - public FormulaFilter( string propertyName, TextFilter.Condition @string = null, @@ -15,28 +12,20 @@ public FormulaFilter( DateFilter.Condition date = null) { Property = propertyName; + Formula = new Condition( - @string: @string, - checkbox: checkbox, - number: number, - date: date + @string, + checkbox, + number, + date ); } + [JsonProperty("formula")] + public Condition Formula { get; set; } + public class Condition { - [JsonProperty("string")] - public TextFilter.Condition String { get; set; } - - [JsonProperty("checkbox")] - public CheckboxFilter.Condition Checkbox { get; set; } - - [JsonProperty("number")] - public NumberFilter.Condition Number { get; set; } - - [JsonProperty("date")] - public DateFilter.Condition Date { get; set; } - public Condition( TextFilter.Condition @string = null, CheckboxFilter.Condition checkbox = null, @@ -48,6 +37,18 @@ public Condition( Number = number; Date = date; } + + [JsonProperty("string")] + public TextFilter.Condition String { get; set; } + + [JsonProperty("checkbox")] + public CheckboxFilter.Condition Checkbox { get; set; } + + [JsonProperty("number")] + public NumberFilter.Condition Number { get; set; } + + [JsonProperty("date")] + public DateFilter.Condition Date { get; set; } } } } diff --git a/Src/Notion.Client/Models/Filters/MultiSelectFilter.cs b/Src/Notion.Client/Models/Filters/MultiSelectFilter.cs index 14aec6d5..011a127e 100644 --- a/Src/Notion.Client/Models/Filters/MultiSelectFilter.cs +++ b/Src/Notion.Client/Models/Filters/MultiSelectFilter.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class MultiSelectFilter : SinglePropertyFilter, IRollupSubPropertyFilter { - [JsonProperty("multi_select")] - public Condition MultiSelect { get; set; } - public MultiSelectFilter( string propertyName, string contains = null, @@ -15,29 +12,20 @@ public MultiSelectFilter( bool? isNotEmpty = null) { Property = propertyName; + MultiSelect = new Condition( - contains: contains, - doesNotContain: doesNotContain, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + contains, + doesNotContain, + isEmpty, + isNotEmpty ); } + [JsonProperty("multi_select")] + public Condition MultiSelect { get; set; } public class Condition { - [JsonProperty("contains")] - public string Contains { get; set; } - - [JsonProperty("does_not_contain")] - public string DoesNotContain { get; set; } - - [JsonProperty("is_empty")] - public bool? IsEmpty { get; set; } - - [JsonProperty("is_not_empty")] - public bool? IsNotEmpty { get; set; } - public Condition( string contains = null, string doesNotContain = null, @@ -49,7 +37,18 @@ public Condition( IsEmpty = isEmpty; IsNotEmpty = isNotEmpty; } - } + [JsonProperty("contains")] + public string Contains { get; set; } + + [JsonProperty("does_not_contain")] + public string DoesNotContain { get; set; } + + [JsonProperty("is_empty")] + public bool? IsEmpty { get; set; } + + [JsonProperty("is_not_empty")] + public bool? IsNotEmpty { get; set; } + } } } diff --git a/Src/Notion.Client/Models/Filters/NumberFilter.cs b/Src/Notion.Client/Models/Filters/NumberFilter.cs index 4895d3e8..1a2f6879 100644 --- a/Src/Notion.Client/Models/Filters/NumberFilter.cs +++ b/Src/Notion.Client/Models/Filters/NumberFilter.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class NumberFilter : SinglePropertyFilter, IRollupSubPropertyFilter { - [JsonProperty("number")] - public Condition Number { get; set; } - public NumberFilter( string propertyName, double? equal = null, @@ -19,20 +16,44 @@ public NumberFilter( bool? isNotEmpty = null) { Property = propertyName; + Number = new Condition( - equal: equal, - doesNotEqual: doesNotEqual, - greaterThan: greaterThan, - lessThan: lessThan, - greaterThanOrEqualTo: greaterThanOrEqualTo, - lessThanOrEqualTo: lessThanOrEqualTo, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + equal, + doesNotEqual, + greaterThan, + lessThan, + greaterThanOrEqualTo, + lessThanOrEqualTo, + isEmpty, + isNotEmpty ); } + [JsonProperty("number")] + public Condition Number { get; set; } + public class Condition { + public Condition( + double? equal = null, + double? doesNotEqual = null, + double? greaterThan = null, + double? lessThan = null, + double? greaterThanOrEqualTo = null, + double? lessThanOrEqualTo = null, + bool? isEmpty = null, + bool? isNotEmpty = null) + { + Equal = equal; + DoesNotEqual = doesNotEqual; + GreaterThan = greaterThan; + LessThan = lessThan; + GreaterThanOrEqualTo = greaterThanOrEqualTo; + LessThanOrEqualTo = lessThanOrEqualTo; + IsEmpty = isEmpty; + IsNotEmpty = isNotEmpty; + } + [JsonProperty("equals")] public double? Equal { get; set; } @@ -56,27 +77,6 @@ public class Condition [JsonProperty("is_not_empty")] public bool? IsNotEmpty { get; set; } - - public Condition( - double? equal = null, - double? doesNotEqual = null, - double? greaterThan = null, - double? lessThan = null, - double? greaterThanOrEqualTo = null, - double? lessThanOrEqualTo = null, - bool? isEmpty = null, - bool? isNotEmpty = null) - { - Equal = equal; - DoesNotEqual = doesNotEqual; - GreaterThan = greaterThan; - LessThan = lessThan; - GreaterThanOrEqualTo = greaterThanOrEqualTo; - LessThanOrEqualTo = lessThanOrEqualTo; - IsEmpty = isEmpty; - IsNotEmpty = isNotEmpty; - } } - } } diff --git a/Src/Notion.Client/Models/Filters/PeopleFilter.cs b/Src/Notion.Client/Models/Filters/PeopleFilter.cs index af1067c4..6b83dda4 100644 --- a/Src/Notion.Client/Models/Filters/PeopleFilter.cs +++ b/Src/Notion.Client/Models/Filters/PeopleFilter.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class PeopleFilter : SinglePropertyFilter, IRollupSubPropertyFilter { - [JsonProperty("people")] - public Condition People { get; set; } - public PeopleFilter( string propertyName, string contains = null, @@ -15,28 +12,20 @@ public PeopleFilter( bool? isNotEmpty = null) { Property = propertyName; + People = new Condition( - contains: contains, - doesNotContain: doesNotContain, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + contains, + doesNotContain, + isEmpty, + isNotEmpty ); } + [JsonProperty("people")] + public Condition People { get; set; } + public class Condition { - [JsonProperty("contains")] - public string Contains { get; set; } - - [JsonProperty("does_not_contain")] - public string DoesNotContain { get; set; } - - [JsonProperty("is_empty")] - public bool? IsEmpty { get; set; } - - [JsonProperty("is_not_empty")] - public bool? IsNotEmpty { get; set; } - public Condition( string contains = null, string doesNotContain = null, @@ -48,6 +37,18 @@ public Condition( IsEmpty = isEmpty; IsNotEmpty = isNotEmpty; } + + [JsonProperty("contains")] + public string Contains { get; set; } + + [JsonProperty("does_not_contain")] + public string DoesNotContain { get; set; } + + [JsonProperty("is_empty")] + public bool? IsEmpty { get; set; } + + [JsonProperty("is_not_empty")] + public bool? IsNotEmpty { get; set; } } } } diff --git a/Src/Notion.Client/Models/Filters/PhoneNumberFilter.cs b/Src/Notion.Client/Models/Filters/PhoneNumberFilter.cs index 758a65db..9ea9cf68 100644 --- a/Src/Notion.Client/Models/Filters/PhoneNumberFilter.cs +++ b/Src/Notion.Client/Models/Filters/PhoneNumberFilter.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class PhoneNumberFilter : SinglePropertyFilter { - [JsonProperty("phone_number")] - public TextFilter.Condition Text { get; set; } - public PhoneNumberFilter( string propertyName, string equal = null, @@ -19,16 +16,20 @@ public PhoneNumberFilter( bool? isNotEmpty = null) { Property = propertyName; + Text = new TextFilter.Condition( - equal: equal, - doesNotEqual: doesNotEqual, - contains: contains, - doesNotContain: doesNotContain, - startsWith: startsWith, - endsWith: endsWith, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + equal, + doesNotEqual, + contains, + doesNotContain, + startsWith, + endsWith, + isEmpty, + isNotEmpty ); } + + [JsonProperty("phone_number")] + public TextFilter.Condition Text { get; set; } } } diff --git a/Src/Notion.Client/Models/Filters/RelationFilter.cs b/Src/Notion.Client/Models/Filters/RelationFilter.cs index b7e2924d..bff5f498 100644 --- a/Src/Notion.Client/Models/Filters/RelationFilter.cs +++ b/Src/Notion.Client/Models/Filters/RelationFilter.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class RelationFilter : SinglePropertyFilter, IRollupSubPropertyFilter { - [JsonProperty("relation")] - public Condition Relation { get; set; } - public RelationFilter( string propertyName, string contains = null, @@ -15,28 +12,20 @@ public RelationFilter( bool? isNotEmpty = null) { Property = propertyName; + Relation = new Condition( - contains: contains, - doesNotContain: doesNotContain, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + contains, + doesNotContain, + isEmpty, + isNotEmpty ); } + [JsonProperty("relation")] + public Condition Relation { get; set; } + public class Condition { - [JsonProperty("contains")] - public string Contains { get; set; } - - [JsonProperty("does_not_contain")] - public string DoesNotContain { get; set; } - - [JsonProperty("is_empty")] - public bool? IsEmpty { get; set; } - - [JsonProperty("is_not_empty")] - public bool? IsNotEmpty { get; set; } - public Condition( string contains = null, string doesNotContain = null, @@ -48,6 +37,18 @@ public Condition( IsEmpty = isEmpty; IsNotEmpty = isNotEmpty; } + + [JsonProperty("contains")] + public string Contains { get; set; } + + [JsonProperty("does_not_contain")] + public string DoesNotContain { get; set; } + + [JsonProperty("is_empty")] + public bool? IsEmpty { get; set; } + + [JsonProperty("is_not_empty")] + public bool? IsNotEmpty { get; set; } } } } diff --git a/Src/Notion.Client/Models/Filters/RichTextFilter.cs b/Src/Notion.Client/Models/Filters/RichTextFilter.cs index 90bae02e..733b93ba 100644 --- a/Src/Notion.Client/Models/Filters/RichTextFilter.cs +++ b/Src/Notion.Client/Models/Filters/RichTextFilter.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class RichTextFilter : SinglePropertyFilter, IRollupSubPropertyFilter { - [JsonProperty("rich_text")] - public TextFilter.Condition RichText { get; set; } - public RichTextFilter( string propertyName, string equal = null, @@ -19,23 +16,47 @@ public RichTextFilter( bool? isNotEmpty = null) { Property = propertyName; + RichText = new TextFilter.Condition( - equal: equal, - doesNotEqual: doesNotEqual, - contains: contains, - doesNotContain: doesNotContain, - startsWith: startsWith, - endsWith: endsWith, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + equal, + doesNotEqual, + contains, + doesNotContain, + startsWith, + endsWith, + isEmpty, + isNotEmpty ); } + + [JsonProperty("rich_text")] + public TextFilter.Condition RichText { get; set; } } public static class TextFilter { public class Condition { + public Condition( + string equal = null, + string doesNotEqual = null, + string contains = null, + string doesNotContain = null, + string startsWith = null, + string endsWith = null, + bool? isEmpty = null, + bool? isNotEmpty = null) + { + Equal = equal; + DoesNotEqual = doesNotEqual; + Contains = contains; + DoesNotContain = doesNotContain; + StartsWith = startsWith; + EndsWith = endsWith; + IsEmpty = isEmpty; + IsNotEmpty = isNotEmpty; + } + [JsonProperty("equals")] public string Equal { get; set; } @@ -59,26 +80,6 @@ public class Condition [JsonProperty("is_not_empty")] public bool? IsNotEmpty { get; set; } - - public Condition( - string equal = null, - string doesNotEqual = null, - string contains = null, - string doesNotContain = null, - string startsWith = null, - string endsWith = null, - bool? isEmpty = null, - bool? isNotEmpty = null) - { - Equal = equal; - DoesNotEqual = doesNotEqual; - Contains = contains; - DoesNotContain = doesNotContain; - StartsWith = startsWith; - EndsWith = endsWith; - IsEmpty = isEmpty; - IsNotEmpty = isNotEmpty; - } } } } diff --git a/Src/Notion.Client/Models/Filters/Rollup/RollupFilter.cs b/Src/Notion.Client/Models/Filters/Rollup/RollupFilter.cs index 41cb759e..df641729 100644 --- a/Src/Notion.Client/Models/Filters/Rollup/RollupFilter.cs +++ b/Src/Notion.Client/Models/Filters/Rollup/RollupFilter.cs @@ -4,18 +4,16 @@ namespace Notion.Client { public class RollupFilter : SinglePropertyFilter { - [JsonProperty("rollup")] - public Condition Rollup { get; set; } - public RollupFilter( - string propertyName - , IRollupSubPropertyFilter any = null - , IRollupSubPropertyFilter none = null - , IRollupSubPropertyFilter every = null - , DateFilter.Condition date = null - , NumberFilter.Condition number = null) + string propertyName, + IRollupSubPropertyFilter any = null, + IRollupSubPropertyFilter none = null, + IRollupSubPropertyFilter every = null, + DateFilter.Condition date = null, + NumberFilter.Condition number = null) { Property = propertyName; + Rollup = new Condition( any, none, @@ -25,14 +23,17 @@ string propertyName ); } + [JsonProperty("rollup")] + public Condition Rollup { get; set; } + public class Condition { public Condition( - IRollupSubPropertyFilter any = null - , IRollupSubPropertyFilter none = null - , IRollupSubPropertyFilter every = null - , DateFilter.Condition date = null - , NumberFilter.Condition number = null) + IRollupSubPropertyFilter any = null, + IRollupSubPropertyFilter none = null, + IRollupSubPropertyFilter every = null, + DateFilter.Condition date = null, + NumberFilter.Condition number = null) { Any = any; None = none; diff --git a/Src/Notion.Client/Models/Filters/SelectFilter.cs b/Src/Notion.Client/Models/Filters/SelectFilter.cs index 6f0887a4..064334f1 100644 --- a/Src/Notion.Client/Models/Filters/SelectFilter.cs +++ b/Src/Notion.Client/Models/Filters/SelectFilter.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class SelectFilter : SinglePropertyFilter, IRollupSubPropertyFilter { - [JsonProperty("select")] - public Condition Select { get; set; } - public SelectFilter( string propertyName, string equal = null, @@ -15,28 +12,20 @@ public SelectFilter( bool? isNotEmpty = null) { Property = propertyName; + Select = new Condition( - equal: equal, - doesNotEqual: doesNotEqual, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + equal, + doesNotEqual, + isEmpty, + isNotEmpty ); } + [JsonProperty("select")] + public Condition Select { get; set; } + public class Condition { - [JsonProperty("equals")] - public string Equal { get; set; } - - [JsonProperty("does_not_equal")] - public string DoesNotEqual { get; set; } - - [JsonProperty("is_empty")] - public bool? IsEmpty { get; set; } - - [JsonProperty("is_not_empty")] - public bool? IsNotEmpty { get; set; } - public Condition( string equal = null, string doesNotEqual = null, @@ -48,6 +37,18 @@ public Condition( IsEmpty = isEmpty; IsNotEmpty = isNotEmpty; } + + [JsonProperty("equals")] + public string Equal { get; set; } + + [JsonProperty("does_not_equal")] + public string DoesNotEqual { get; set; } + + [JsonProperty("is_empty")] + public bool? IsEmpty { get; set; } + + [JsonProperty("is_not_empty")] + public bool? IsNotEmpty { get; set; } } } } diff --git a/Src/Notion.Client/Models/Filters/StatusFilter.cs b/Src/Notion.Client/Models/Filters/StatusFilter.cs new file mode 100644 index 00000000..0af0a22c --- /dev/null +++ b/Src/Notion.Client/Models/Filters/StatusFilter.cs @@ -0,0 +1,54 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class StatusFilter : SinglePropertyFilter, IRollupSubPropertyFilter + { + public StatusFilter( + string propertyName, + string equal = null, + string doesNotEqual = null, + bool? isEmpty = null, + bool? isNotEmpty = null) + { + Property = propertyName; + + Status = new Condition( + equal, + doesNotEqual, + isEmpty, + isNotEmpty + ); + } + + [JsonProperty("status")] + public Condition Status { get; set; } + + public class Condition + { + public Condition( + string equal = null, + string doesNotEqual = null, + bool? isEmpty = null, + bool? isNotEmpty = null) + { + Equal = equal; + DoesNotEqual = doesNotEqual; + IsEmpty = isEmpty; + IsNotEmpty = isNotEmpty; + } + + [JsonProperty("equals")] + public string Equal { get; set; } + + [JsonProperty("does_not_equal")] + public string DoesNotEqual { get; set; } + + [JsonProperty("is_empty")] + public bool? IsEmpty { get; set; } + + [JsonProperty("is_not_empty")] + public bool? IsNotEmpty { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Filters/TimestampCreatedTimeFilter.cs b/Src/Notion.Client/Models/Filters/TimestampCreatedTimeFilter.cs index ac8f2244..80f9dcf4 100644 --- a/Src/Notion.Client/Models/Filters/TimestampCreatedTimeFilter.cs +++ b/Src/Notion.Client/Models/Filters/TimestampCreatedTimeFilter.cs @@ -6,12 +6,6 @@ namespace Notion.Client { public class TimestampCreatedTimeFilter : Filter { - [JsonProperty("timestamp")] - public string Timestamp = "created_time"; - - [JsonProperty("created_time")] - public DateFilter.Condition CreatedTime { get; set; } - public TimestampCreatedTimeFilter( DateTime? equal = null, DateTime? before = null, @@ -28,20 +22,26 @@ public TimestampCreatedTimeFilter( bool? isNotEmpty = null) { CreatedTime = new DateFilter.Condition( - equal: equal, - before: before, - after: after, - onOrBefore: onOrBefore, - onOrAfter: onOrAfter, - pastWeek: pastWeek, - pastMonth: pastMonth, - pastYear: pastYear, - nextWeek: nextWeek, - nextMonth: nextMonth, - nextYear: nextYear, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + equal, + before, + after, + onOrBefore, + onOrAfter, + pastWeek, + pastMonth, + pastYear, + nextWeek, + nextMonth, + nextYear, + isEmpty, + isNotEmpty ); } + + [JsonProperty("timestamp")] + public string Timestamp => "created_time"; + + [JsonProperty("created_time")] + public DateFilter.Condition CreatedTime { get; set; } } } diff --git a/Src/Notion.Client/Models/Filters/TimestampLastEditedTimeFilter.cs b/Src/Notion.Client/Models/Filters/TimestampLastEditedTimeFilter.cs index 1d6acb7f..1cd22974 100644 --- a/Src/Notion.Client/Models/Filters/TimestampLastEditedTimeFilter.cs +++ b/Src/Notion.Client/Models/Filters/TimestampLastEditedTimeFilter.cs @@ -6,12 +6,6 @@ namespace Notion.Client { public class TimestampLastEditedTimeFilter : Filter { - [JsonProperty("timestamp")] - public string Timestamp = "last_modified_time"; - - [JsonProperty("last_edited_time")] - public DateFilter.Condition LastEditedTime { get; set; } - public TimestampLastEditedTimeFilter( DateTime? equal = null, DateTime? before = null, @@ -28,20 +22,26 @@ public TimestampLastEditedTimeFilter( bool? isNotEmpty = null) { LastEditedTime = new DateFilter.Condition( - equal: equal, - before: before, - after: after, - onOrBefore: onOrBefore, - onOrAfter: onOrAfter, - pastWeek: pastWeek, - pastMonth: pastMonth, - pastYear: pastYear, - nextWeek: nextWeek, - nextMonth: nextMonth, - nextYear: nextYear, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + equal, + before, + after, + onOrBefore, + onOrAfter, + pastWeek, + pastMonth, + pastYear, + nextWeek, + nextMonth, + nextYear, + isEmpty, + isNotEmpty ); } + + [JsonProperty("timestamp")] + public string Timestamp => "last_edited_time"; + + [JsonProperty("last_edited_time")] + public DateFilter.Condition LastEditedTime { get; set; } } } diff --git a/Src/Notion.Client/Models/Filters/TitleFilter.cs b/Src/Notion.Client/Models/Filters/TitleFilter.cs index 7c21bb33..1e0d4303 100644 --- a/Src/Notion.Client/Models/Filters/TitleFilter.cs +++ b/Src/Notion.Client/Models/Filters/TitleFilter.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class TitleFilter : SinglePropertyFilter { - [JsonProperty("title")] - public TextFilter.Condition Title { get; set; } - public TitleFilter( string propertyName, string equal = null, @@ -19,16 +16,20 @@ public TitleFilter( bool? isNotEmpty = null) { Property = propertyName; + Title = new TextFilter.Condition( - equal: equal, - doesNotEqual: doesNotEqual, - contains: contains, - doesNotContain: doesNotContain, - startsWith: startsWith, - endsWith: endsWith, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + equal, + doesNotEqual, + contains, + doesNotContain, + startsWith, + endsWith, + isEmpty, + isNotEmpty ); } + + [JsonProperty("title")] + public TextFilter.Condition Title { get; set; } } } diff --git a/Src/Notion.Client/Models/Filters/URLFilter.cs b/Src/Notion.Client/Models/Filters/URLFilter.cs index b6a1fe6b..7c722832 100644 --- a/Src/Notion.Client/Models/Filters/URLFilter.cs +++ b/Src/Notion.Client/Models/Filters/URLFilter.cs @@ -1,12 +1,11 @@ -using Newtonsoft.Json; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; namespace Notion.Client { + [SuppressMessage("ReSharper", "InconsistentNaming")] public class URLFilter : SinglePropertyFilter { - [JsonProperty("url")] - public TextFilter.Condition URL { get; set; } - public URLFilter( string propertyName, string equal = null, @@ -19,16 +18,20 @@ public URLFilter( bool? isNotEmpty = null) { Property = propertyName; + URL = new TextFilter.Condition( - equal: equal, - doesNotEqual: doesNotEqual, - contains: contains, - doesNotContain: doesNotContain, - startsWith: startsWith, - endsWith: endsWith, - isEmpty: isEmpty, - isNotEmpty: isNotEmpty + equal, + doesNotEqual, + contains, + doesNotContain, + startsWith, + endsWith, + isEmpty, + isNotEmpty ); } + + [JsonProperty("url")] + public TextFilter.Condition URL { get; set; } } } diff --git a/Src/Notion.Client/Models/IObject.cs b/Src/Notion.Client/Models/IObject.cs index 2f72f929..b8ab1108 100644 --- a/Src/Notion.Client/Models/IObject.cs +++ b/Src/Notion.Client/Models/IObject.cs @@ -5,10 +5,10 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "object")] - [JsonSubtypes.KnownSubType(typeof(Page), ObjectType.Page)] - [JsonSubtypes.KnownSubType(typeof(Database), ObjectType.Database)] - [JsonSubtypes.KnownSubType(typeof(IBlock), ObjectType.Block)] - [JsonSubtypes.KnownSubType(typeof(User), ObjectType.User)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(Page), ObjectType.Page)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(Database), ObjectType.Database)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(IBlock), ObjectType.Block)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(User), ObjectType.User)] public interface IObject { [JsonProperty("id")] diff --git a/Src/Notion.Client/Models/ObjectType.cs b/Src/Notion.Client/Models/ObjectType.cs index d493254c..4a9dc77d 100644 --- a/Src/Notion.Client/Models/ObjectType.cs +++ b/Src/Notion.Client/Models/ObjectType.cs @@ -15,5 +15,8 @@ public enum ObjectType [EnumMember(Value = "user")] User, + + [EnumMember(Value = "comment")] + Comment } } diff --git a/Src/Notion.Client/Models/Page/IPageIcon.cs b/Src/Notion.Client/Models/Page/IPageIcon.cs index a89184fe..5d692185 100644 --- a/Src/Notion.Client/Models/Page/IPageIcon.cs +++ b/Src/Notion.Client/Models/Page/IPageIcon.cs @@ -4,9 +4,10 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(EmojiObject), "emoji")] - [JsonSubtypes.KnownSubType(typeof(FileObject), "file")] - [JsonSubtypes.KnownSubType(typeof(FileObject), "external")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(EmojiObject), "emoji")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CustomEmojiObject), "custom_emoji")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FileObject), "file")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FileObject), "external")] public interface IPageIcon { [JsonProperty("type")] diff --git a/Src/Notion.Client/Models/Page/IPageParent.cs b/Src/Notion.Client/Models/Page/IPageParent.cs index 439b1a3f..b9111d91 100644 --- a/Src/Notion.Client/Models/Page/IPageParent.cs +++ b/Src/Notion.Client/Models/Page/IPageParent.cs @@ -4,10 +4,10 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(DatabaseParent), ParentType.DatabaseId)] - [JsonSubtypes.KnownSubType(typeof(PageParent), ParentType.PageId)] - [JsonSubtypes.KnownSubType(typeof(WorkspaceParent), ParentType.Workspace)] - [JsonSubtypes.KnownSubType(typeof(BlockParent), ParentType.BlockId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DatabaseParent), ParentType.DatabaseId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PageParent), ParentType.PageId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(WorkspaceParent), ParentType.Workspace)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(BlockParent), ParentType.BlockId)] public interface IPageParent : IParent { } diff --git a/Src/Notion.Client/Models/Page/Page.cs b/Src/Notion.Client/Models/Page/Page.cs index a429d92d..fe4eb0de 100644 --- a/Src/Notion.Client/Models/Page/Page.cs +++ b/Src/Notion.Client/Models/Page/Page.cs @@ -4,68 +4,74 @@ namespace Notion.Client { - public class Page : IObject, IObjectModificationData + public class Page : IObject, IObjectModificationData, IWikiDatabase { /// - /// Object type + /// The parent of this page. Can be a database, page, or workspace. /// - public ObjectType Object => ObjectType.Page; + [JsonProperty("parent")] + public IPageParent Parent { get; set; } /// - /// Unique identifier of the page. + /// Indicates whether the page is currently in the trash. /// - public string Id { get; set; } + [JsonProperty("in_trash")] + public bool InTrash { get; set; } /// - /// The parent of this page. Can be a database, page, or workspace. + /// Property values of this page. /// - [JsonProperty("parent")] - public IPageParent Parent { get; set; } + [JsonProperty("properties")] + public IDictionary Properties { get; set; } /// - /// Date and time when this page was created. + /// The URL of the Notion page. /// - [JsonProperty("created_time")] - public DateTime CreatedTime { get; set; } + [JsonProperty("url")] + public string Url { get; set; } /// - /// Date and time when this page was updated. + /// Page icon. /// - [JsonProperty("last_edited_time")] - public DateTime LastEditedTime { get; set; } + [JsonProperty("icon")] + public IPageIcon Icon { get; set; } /// - /// The archived status of the page. + /// Page cover image. /// - [JsonProperty("archived")] - public bool IsArchived { get; set; } + [JsonProperty("cover")] + public FileObject Cover { get; set; } /// - /// Property values of this page. + /// Object type /// - [JsonProperty("properties")] - public IDictionary Properties { get; set; } + public ObjectType Object => ObjectType.Page; /// - /// The URL of the Notion page. + /// Unique identifier of the page. /// - [JsonProperty("url")] - public string Url { get; set; } + public string Id { get; set; } /// - /// Page icon. + /// Date and time when this page was created. /// - [JsonProperty("icon")] - public IPageIcon Icon { get; set; } + [JsonProperty("created_time")] + public DateTime CreatedTime { get; set; } /// - /// Page cover image. + /// Date and time when this page was updated. /// - [JsonProperty("cover")] - public FileObject Cover { get; set; } + [JsonProperty("last_edited_time")] + public DateTime LastEditedTime { get; set; } 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/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; } } } diff --git a/Src/Notion.Client/Models/Parents/BlockParent.cs b/Src/Notion.Client/Models/Parents/BlockParent.cs index e0a9af48..e3fd7749 100644 --- a/Src/Notion.Client/Models/Parents/BlockParent.cs +++ b/Src/Notion.Client/Models/Parents/BlockParent.cs @@ -2,17 +2,17 @@ namespace Notion.Client { - public class BlockParent : IPageParent, IDatabaseParent + public class BlockParent : IPageParent, IDatabaseParent, IBlockParent, ICommentParent { /// - /// Always has a value "block_id" + /// The ID of the block that the element belongs to. /// - public ParentType Type { get; set; } + [JsonProperty("block_id")] + public string BlockId { get; set; } /// - /// The ID of the block that the element belongs to. + /// Always has a value "block_id" /// - [JsonProperty("block_id")] - public string BlockId { get; set; } + public ParentType Type { get; set; } } } diff --git a/Src/Notion.Client/Models/Parents/DatabaseParent.cs b/Src/Notion.Client/Models/Parents/DatabaseParent.cs index c3e028e7..878dbe89 100644 --- a/Src/Notion.Client/Models/Parents/DatabaseParent.cs +++ b/Src/Notion.Client/Models/Parents/DatabaseParent.cs @@ -2,17 +2,17 @@ namespace Notion.Client { - public class DatabaseParent : IPageParent + public class DatabaseParent : IPageParent, IBlockParent { /// - /// Always "database_id" + /// The ID of the database that this page belongs to. /// - public ParentType Type { get; set; } + [JsonProperty("database_id")] + public string DatabaseId { get; set; } /// - /// The ID of the database that this page belongs to. + /// Always "database_id" /// - [JsonProperty("database_id")] - public string DatabaseId { get; set; } + public ParentType Type { get; set; } } } diff --git a/Src/Notion.Client/Models/Parents/IParent.cs b/Src/Notion.Client/Models/Parents/IParent.cs index e2c50e5f..ccf3999b 100644 --- a/Src/Notion.Client/Models/Parents/IParent.cs +++ b/Src/Notion.Client/Models/Parents/IParent.cs @@ -1,8 +1,10 @@ -using Newtonsoft.Json; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] public interface IParent { [JsonConverter(typeof(StringEnumConverter))] diff --git a/Src/Notion.Client/Models/Parents/PageParent.cs b/Src/Notion.Client/Models/Parents/PageParent.cs index ff185747..565f7ccc 100644 --- a/Src/Notion.Client/Models/Parents/PageParent.cs +++ b/Src/Notion.Client/Models/Parents/PageParent.cs @@ -2,17 +2,17 @@ namespace Notion.Client { - public class PageParent : IPageParent, IDatabaseParent + public class PageParent : IPageParent, IDatabaseParent, IBlockParent, ICommentParent { /// - /// Always "page_id". + /// The ID of the page that this page belongs to. /// - public ParentType Type { get; set; } + [JsonProperty("page_id")] + public string PageId { get; set; } /// - /// The ID of the page that this page belongs to. + /// Always "page_id". /// - [JsonProperty("page_id")] - public string PageId { get; set; } + public ParentType Type { get; set; } } } diff --git a/Src/Notion.Client/Models/Parents/ParentType.cs b/Src/Notion.Client/Models/Parents/ParentType.cs index 96c2a00d..347414f9 100644 --- a/Src/Notion.Client/Models/Parents/ParentType.cs +++ b/Src/Notion.Client/Models/Parents/ParentType.cs @@ -1,7 +1,9 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum ParentType { [EnumMember(Value = null)] @@ -17,6 +19,6 @@ public enum ParentType Workspace, [EnumMember(Value = "block_id")] - BlockId, + BlockId } } diff --git a/Src/Notion.Client/Models/Parents/WorkspaceParent.cs b/Src/Notion.Client/Models/Parents/WorkspaceParent.cs index fc645b60..a0b5e1c4 100644 --- a/Src/Notion.Client/Models/Parents/WorkspaceParent.cs +++ b/Src/Notion.Client/Models/Parents/WorkspaceParent.cs @@ -1,9 +1,9 @@ namespace Notion.Client { - public class WorkspaceParent : IPageParent, IDatabaseParent + public class WorkspaceParent : IPageParent, IDatabaseParent, IBlockParent { /// - /// Always "workspace". + /// Always "workspace". /// public ParentType Type { get; set; } } diff --git a/Src/Notion.Client/Models/PropertyItems/IPropertyItemObject.cs b/Src/Notion.Client/Models/PropertyItems/IPropertyItemObject.cs index 5ebc7730..58db1a7d 100644 --- a/Src/Notion.Client/Models/PropertyItems/IPropertyItemObject.cs +++ b/Src/Notion.Client/Models/PropertyItems/IPropertyItemObject.cs @@ -4,8 +4,8 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "object")] - [JsonSubtypes.KnownSubType(typeof(SimplePropertyItem), "property_item")] - [JsonSubtypes.KnownSubType(typeof(ListPropertyItem), "list")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(SimplePropertyItem), "property_item")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ListPropertyItem), "list")] public interface IPropertyItemObject { [JsonProperty("object")] @@ -18,7 +18,8 @@ public interface IPropertyItemObject string Id { get; } /// - /// Only present in paginated property values with another page of results. If present, the url the user can request to get the next page of results. + /// Only present in paginated property values with another page of results. If present, the url the user can request to + /// get the next page of results. /// [JsonProperty("next_url")] string NextURL { get; } diff --git a/Src/Notion.Client/Models/PropertyItems/ListPropertyItem.cs b/Src/Notion.Client/Models/PropertyItems/ListPropertyItem.cs index f539fcd6..d337ccfd 100644 --- a/Src/Notion.Client/Models/PropertyItems/ListPropertyItem.cs +++ b/Src/Notion.Client/Models/PropertyItems/ListPropertyItem.cs @@ -1,19 +1,13 @@ using System.Collections.Generic; -using JsonSubTypes; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; namespace Notion.Client { + [SuppressMessage("ReSharper", "ClassWithVirtualMembersNeverInherited.Global")] + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")] public class ListPropertyItem : IPropertyItemObject { - public string Object => "list"; - - public virtual string Type { get; set; } - - public string Id { get; set; } - - public string NextURL { get; set; } - [JsonProperty("results")] public IEnumerable Results { get; set; } @@ -25,5 +19,13 @@ public class ListPropertyItem : IPropertyItemObject [JsonProperty("property_item")] public SimplePropertyItem PropertyItem { get; set; } + + public string Object => "list"; + + public virtual string Type { get; set; } + + public string Id { get; set; } + + public string NextURL { get; set; } } } diff --git a/Src/Notion.Client/Models/PropertyItems/NumberPropertyItem.cs b/Src/Notion.Client/Models/PropertyItems/NumberPropertyItem.cs index 144fc627..ea2ab0ad 100644 --- a/Src/Notion.Client/Models/PropertyItems/NumberPropertyItem.cs +++ b/Src/Notion.Client/Models/PropertyItems/NumberPropertyItem.cs @@ -7,6 +7,6 @@ public class NumberPropertyItem : SimplePropertyItem public override string Type => "number"; [JsonProperty("number")] - public Number Number { get; set; } + public double? Number { get; set; } } } diff --git a/Src/Notion.Client/Models/PropertyItems/RichTextPropertyItem.cs b/Src/Notion.Client/Models/PropertyItems/RichTextPropertyItem.cs index 513b7300..f9ce925a 100644 --- a/Src/Notion.Client/Models/PropertyItems/RichTextPropertyItem.cs +++ b/Src/Notion.Client/Models/PropertyItems/RichTextPropertyItem.cs @@ -1,9 +1,12 @@ -namespace Notion.Client +using Newtonsoft.Json; + +namespace Notion.Client { public class RichTextPropertyItem : SimplePropertyItem { public override string Type => "rich_text"; + [JsonProperty("rich_text")] public RichTextBase RichText { get; set; } } } diff --git a/Src/Notion.Client/Models/PropertyItems/RollupPropertyItem.cs b/Src/Notion.Client/Models/PropertyItems/RollupPropertyItem.cs new file mode 100644 index 00000000..04d7da7b --- /dev/null +++ b/Src/Notion.Client/Models/PropertyItems/RollupPropertyItem.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class RollupPropertyItem : SimplePropertyItem + { + public override string Type => "rollup"; + + [JsonProperty("rollup")] + public Data Rollup { get; set; } + + public class Data + { + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("function")] + public string Function { get; set; } + + [JsonProperty("number")] + public double? Number { get; set; } + + [JsonProperty("date")] + public Date Date { get; set; } + + [JsonProperty("array")] + public IEnumerable> Array { get; set; } + + [JsonProperty("unsupported")] + public Dictionary Unsupported { get; set; } + + [JsonProperty("incomplete")] + public Dictionary Incomplete { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/PropertyItems/SimplePropertyItem.cs b/Src/Notion.Client/Models/PropertyItems/SimplePropertyItem.cs index da753319..6ba77c67 100644 --- a/Src/Notion.Client/Models/PropertyItems/SimplePropertyItem.cs +++ b/Src/Notion.Client/Models/PropertyItems/SimplePropertyItem.cs @@ -1,27 +1,31 @@ -using JsonSubTypes; +using System.Diagnostics.CodeAnalysis; +using JsonSubTypes; using Newtonsoft.Json; namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(NumberPropertyItem), "number")] - [JsonSubtypes.KnownSubType(typeof(UrlPropertyItem), "url")] - [JsonSubtypes.KnownSubType(typeof(SelectPropertyItem), "select")] - [JsonSubtypes.KnownSubType(typeof(MultiSelectPropertyItem), "multi_select")] - [JsonSubtypes.KnownSubType(typeof(DatePropertyItem), "date")] - [JsonSubtypes.KnownSubType(typeof(EmailPropertyItem), "email")] - [JsonSubtypes.KnownSubType(typeof(PhoneNumberPropertyItem), "phone_number")] - [JsonSubtypes.KnownSubType(typeof(CheckboxPropertyItem), "checkbox")] - [JsonSubtypes.KnownSubType(typeof(FilesPropertyItem), "files")] - [JsonSubtypes.KnownSubType(typeof(CreatedByPropertyItem), "created_by")] - [JsonSubtypes.KnownSubType(typeof(CreatedTimePropertyItem), "created_time")] - [JsonSubtypes.KnownSubType(typeof(LastEditedByPropertyItem), "last_edited_by")] - [JsonSubtypes.KnownSubType(typeof(LastEditedTimePropertyItem), "last_edited_time")] - [JsonSubtypes.KnownSubType(typeof(FormulaPropertyItem), "formula")] - [JsonSubtypes.KnownSubType(typeof(TitlePropertyItem), "title")] - [JsonSubtypes.KnownSubType(typeof(RichTextPropertyItem), "rich_text")] - [JsonSubtypes.KnownSubType(typeof(PeoplePropertyItem), "people")] - [JsonSubtypes.KnownSubType(typeof(RelationPropertyItem), "relation")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(NumberPropertyItem), "number")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(UrlPropertyItem), "url")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(SelectPropertyItem), "select")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(MultiSelectPropertyItem), "multi_select")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(StatusPropertyItem), "status")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DatePropertyItem), "date")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(EmailPropertyItem), "email")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PhoneNumberPropertyItem), "phone_number")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CheckboxPropertyItem), "checkbox")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FilesPropertyItem), "files")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CreatedByPropertyItem), "created_by")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CreatedTimePropertyItem), "created_time")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(LastEditedByPropertyItem), "last_edited_by")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(LastEditedTimePropertyItem), "last_edited_time")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FormulaPropertyItem), "formula")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(TitlePropertyItem), "title")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RichTextPropertyItem), "rich_text")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PeoplePropertyItem), "people")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RelationPropertyItem), "relation")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RollupPropertyItem), "rollup")] + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")] public abstract class SimplePropertyItem : IPropertyItemObject { public string Object => "property_item"; diff --git a/Src/Notion.Client/Models/PropertyItems/StatusPropertyItem.cs b/Src/Notion.Client/Models/PropertyItems/StatusPropertyItem.cs new file mode 100644 index 00000000..6b6b863c --- /dev/null +++ b/Src/Notion.Client/Models/PropertyItems/StatusPropertyItem.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class StatusPropertyItem : SimplePropertyItem + { + public override string Type => "status"; + + [JsonProperty("status")] + public SelectOption Status { get; set; } + } +} 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/CheckboxPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/CheckboxPropertyValue.cs index 1f3fec50..422eb9b7 100644 --- a/Src/Notion.Client/Models/PropertyValue/CheckboxPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/CheckboxPropertyValue.cs @@ -3,7 +3,7 @@ namespace Notion.Client { /// - /// Checkbox property value objects contain a boolean within the checkbox property. + /// Checkbox property value objects contain a boolean within the checkbox property. /// public class CheckboxPropertyValue : PropertyValue { diff --git a/Src/Notion.Client/Models/PropertyValue/CreatedByPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/CreatedByPropertyValue.cs index 17fa4ef4..31cf5f5b 100644 --- a/Src/Notion.Client/Models/PropertyValue/CreatedByPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/CreatedByPropertyValue.cs @@ -3,14 +3,14 @@ namespace Notion.Client { /// - /// Created by property value object + /// Created by property value object /// public class CreatedByPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.CreatedBy; /// - /// Describes the user who created this page. + /// Describes the user who created this page. /// [JsonProperty("created_by")] public User CreatedBy { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/CreatedTimePropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/CreatedTimePropertyValue.cs index 0b20b2dc..e0550d13 100644 --- a/Src/Notion.Client/Models/PropertyValue/CreatedTimePropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/CreatedTimePropertyValue.cs @@ -3,14 +3,14 @@ namespace Notion.Client { /// - /// Created time property value object. + /// Created time property value object. /// public class CreatedTimePropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.CreatedTime; /// - /// The date and time when this page was created. + /// The date and time when this page was created. /// [JsonProperty("created_time")] public string CreatedTime { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs new file mode 100644 index 00000000..37b84bc5 --- /dev/null +++ b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs @@ -0,0 +1,81 @@ +using System; +using System.Globalization; +using Newtonsoft.Json; + +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) + { + 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 ? DateTimeFormat : DateFormat; + writer.WritePropertyName("start"); + 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, CultureInfo.InvariantCulture)); + } + + 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, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).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 aeb3cd8e..66f9c6b6 100644 --- a/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/DatePropertyValue.cs @@ -1,43 +1,54 @@ using System; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace Notion.Client { /// - /// Date property value object. + /// Date property value object. /// public class DatePropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.Date; /// - /// Date + /// Date /// [JsonProperty("date", NullValueHandling = NullValueHandling.Include)] public Date Date { get; set; } } /// - /// Date value object. + /// Date value object. /// + [JsonConverter(typeof(DateCustomConverter))] public class Date { /// - /// Start date with optional time. + /// 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. + /// 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 based on the time zones from Moment.js. + /// Optional time zone information for start and end. Possible values are extracted from the IANA database and they are + /// based on the time zones from Moment.js. /// [JsonProperty("time_zone")] public string TimeZone { get; set; } + + /// + /// Whether to include time + /// + [JsonIgnore] + public bool IncludeTime { get; set; } = true; } } diff --git a/Src/Notion.Client/Models/PropertyValue/EmailPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/EmailPropertyValue.cs index 1869fc85..a8ac4806 100644 --- a/Src/Notion.Client/Models/PropertyValue/EmailPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/EmailPropertyValue.cs @@ -3,16 +3,16 @@ namespace Notion.Client { /// - /// Email property value object. + /// Email property value object. /// public class EmailPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.Email; /// - /// Describes an email address. + /// Describes an email address. /// - [JsonProperty("email")] + [JsonProperty("email", NullValueHandling = NullValueHandling.Include)] public string Email { get; set; } } } diff --git a/Src/Notion.Client/Models/PropertyValue/FilesPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/FilesPropertyValue.cs index 41580fdb..67bc864a 100644 --- a/Src/Notion.Client/Models/PropertyValue/FilesPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/FilesPropertyValue.cs @@ -4,14 +4,14 @@ namespace Notion.Client { /// - /// File property value object. + /// File property value object. /// public class FilesPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.Files; /// - /// Array of File Object with name. + /// Array of File Object with name. /// [JsonProperty("files")] public List Files { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/FormulaPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/FormulaPropertyValue.cs index e85fd5bd..a1242f47 100644 --- a/Src/Notion.Client/Models/PropertyValue/FormulaPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/FormulaPropertyValue.cs @@ -3,50 +3,50 @@ namespace Notion.Client { /// - /// Formula property value object. + /// Formula property value object. /// public class FormulaPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.Formula; /// - /// A formula described in the database's properties. + /// A formula described in the database's properties. /// [JsonProperty("formula")] public FormulaValue Formula { get; set; } } /// - /// Formula value object. + /// Formula value object. /// public class FormulaValue { /// - /// Formula value type + /// Formula value type /// [JsonProperty("type")] public string Type { get; set; } /// - /// String formula value. + /// String formula value. /// [JsonProperty("string")] public string String { get; set; } /// - /// Number formula value. + /// Number formula value. /// [JsonProperty("number")] public double? Number { get; set; } /// - /// Boolean formula value. + /// Boolean formula value. /// [JsonProperty("boolean")] public bool? Boolean { get; set; } /// - /// Date formula value + /// Date formula value /// [JsonProperty("date")] public Date Date { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/LastEditedByPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/LastEditedByPropertyValue.cs index b5e26efc..a536ad60 100644 --- a/Src/Notion.Client/Models/PropertyValue/LastEditedByPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/LastEditedByPropertyValue.cs @@ -3,14 +3,14 @@ namespace Notion.Client { /// - /// Last edited by property value object. + /// Last edited by property value object. /// public class LastEditedByPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.LastEditedBy; /// - /// Describes the user who last updated this page. + /// Describes the user who last updated this page. /// [JsonProperty("last_edited_by")] public User LastEditedBy { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/LastEditedTimePropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/LastEditedTimePropertyValue.cs index 785ac3bc..25d3100d 100644 --- a/Src/Notion.Client/Models/PropertyValue/LastEditedTimePropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/LastEditedTimePropertyValue.cs @@ -3,14 +3,14 @@ namespace Notion.Client { /// - /// Last edited time property value object. + /// Last edited time property value object. /// public class LastEditedTimePropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.LastEditedTime; /// - /// The date and time when this page was last updated. + /// The date and time when this page was last updated. /// [JsonProperty("last_edited_time")] public string LastEditedTime { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/MultiSelectPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/MultiSelectPropertyValue.cs index a5ee4f0a..ff820527 100644 --- a/Src/Notion.Client/Models/PropertyValue/MultiSelectPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/MultiSelectPropertyValue.cs @@ -4,14 +4,14 @@ namespace Notion.Client { /// - /// Multi-select property value object. + /// Multi-select property value object. /// public class MultiSelectPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.MultiSelect; /// - /// An array of multi-select option values. + /// An array of multi-select option values. /// [JsonProperty("multi_select")] public List MultiSelect { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/NumberPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/NumberPropertyValue.cs index a98a34d4..a709e4f5 100644 --- a/Src/Notion.Client/Models/PropertyValue/NumberPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/NumberPropertyValue.cs @@ -3,16 +3,16 @@ namespace Notion.Client { /// - /// Number formula property value object. + /// Number formula property value object. /// public class NumberPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.Number; /// - /// Value of number + /// Value of number /// - [JsonProperty("number")] + [JsonProperty("number", NullValueHandling = NullValueHandling.Include)] public double? Number { get; set; } } } diff --git a/Src/Notion.Client/Models/PropertyValue/PeoplePropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/PeoplePropertyValue.cs index 047d33ee..62557560 100644 --- a/Src/Notion.Client/Models/PropertyValue/PeoplePropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/PeoplePropertyValue.cs @@ -4,14 +4,14 @@ namespace Notion.Client { /// - /// People property value object. + /// People property value object. /// public class PeoplePropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.People; /// - /// List of users. + /// List of users. /// [JsonProperty("people")] public List People { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/PhoneNumberPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/PhoneNumberPropertyValue.cs index be5e482e..f7c37a19 100644 --- a/Src/Notion.Client/Models/PropertyValue/PhoneNumberPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/PhoneNumberPropertyValue.cs @@ -3,16 +3,16 @@ namespace Notion.Client { /// - /// Phone number property value object. + /// Phone number property value object. /// public class PhoneNumberPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.PhoneNumber; /// - /// Phone number value + /// 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/PropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs index 8437b4f8..e1289046 100644 --- a/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/PropertyValue.cs @@ -1,37 +1,43 @@ -using JsonSubTypes; +using System.Diagnostics.CodeAnalysis; +using JsonSubTypes; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace Notion.Client { /// - /// An object describing the identifier, type, and value of a page property. + /// An object describing the identifier, type, and value of a page property. /// [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(CheckboxPropertyValue), PropertyValueType.Checkbox)] - [JsonSubtypes.KnownSubType(typeof(CreatedByPropertyValue), PropertyValueType.CreatedBy)] - [JsonSubtypes.KnownSubType(typeof(CreatedTimePropertyValue), PropertyValueType.CreatedTime)] - [JsonSubtypes.KnownSubType(typeof(DatePropertyValue), PropertyValueType.Date)] - [JsonSubtypes.KnownSubType(typeof(EmailPropertyValue), PropertyValueType.Email)] - [JsonSubtypes.KnownSubType(typeof(FilesPropertyValue), PropertyValueType.Files)] - [JsonSubtypes.KnownSubType(typeof(FormulaPropertyValue), PropertyValueType.Formula)] - [JsonSubtypes.KnownSubType(typeof(LastEditedByPropertyValue), PropertyValueType.LastEditedBy)] - [JsonSubtypes.KnownSubType(typeof(LastEditedTimePropertyValue), PropertyValueType.LastEditedTime)] - [JsonSubtypes.KnownSubType(typeof(MultiSelectPropertyValue), PropertyValueType.MultiSelect)] - [JsonSubtypes.KnownSubType(typeof(NumberPropertyValue), PropertyValueType.Number)] - [JsonSubtypes.KnownSubType(typeof(PeoplePropertyValue), PropertyValueType.People)] - [JsonSubtypes.KnownSubType(typeof(PhoneNumberPropertyValue), PropertyValueType.PhoneNumber)] - [JsonSubtypes.KnownSubType(typeof(RelationPropertyValue), PropertyValueType.Relation)] - [JsonSubtypes.KnownSubType(typeof(RichTextPropertyValue), PropertyValueType.RichText)] - [JsonSubtypes.KnownSubType(typeof(RollupPropertyValue), PropertyValueType.Rollup)] - [JsonSubtypes.KnownSubType(typeof(SelectPropertyValue), PropertyValueType.Select)] - [JsonSubtypes.KnownSubType(typeof(StatusPropertyValue), PropertyValueType.Status)] - [JsonSubtypes.KnownSubType(typeof(TitlePropertyValue), PropertyValueType.Title)] - [JsonSubtypes.KnownSubType(typeof(UrlPropertyValue), PropertyValueType.Url)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CheckboxPropertyValue), PropertyValueType.Checkbox)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CreatedByPropertyValue), PropertyValueType.CreatedBy)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CreatedTimePropertyValue), PropertyValueType.CreatedTime)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DatePropertyValue), PropertyValueType.Date)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(EmailPropertyValue), PropertyValueType.Email)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FilesPropertyValue), PropertyValueType.Files)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FormulaPropertyValue), PropertyValueType.Formula)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(LastEditedByPropertyValue), PropertyValueType.LastEditedBy)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(LastEditedTimePropertyValue), PropertyValueType.LastEditedTime)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(MultiSelectPropertyValue), PropertyValueType.MultiSelect)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(NumberPropertyValue), PropertyValueType.Number)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PeoplePropertyValue), PropertyValueType.People)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PhoneNumberPropertyValue), PropertyValueType.PhoneNumber)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RelationPropertyValue), PropertyValueType.Relation)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RichTextPropertyValue), PropertyValueType.RichText)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RollupPropertyValue), PropertyValueType.Rollup)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(SelectPropertyValue), PropertyValueType.Select)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(StatusPropertyValue), PropertyValueType.Status)] + [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")] public class PropertyValue { /// - /// Underlying identifier of the property. + /// Underlying identifier of the property. /// [JsonProperty("id")] public string Id { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs b/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs index fcbeae61..574138e9 100644 --- a/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs +++ b/Src/Notion.Client/Models/PropertyValue/PropertyValueType.cs @@ -1,10 +1,12 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { /// - /// Types of Property Value + /// Types of Property Value /// + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum PropertyValueType { [EnumMember(Value = null)] @@ -69,5 +71,14 @@ public enum PropertyValueType [EnumMember(Value = "status")] Status, + + [EnumMember(Value = "unique_id")] + UniqueId, + + [EnumMember(Value = "verification")] + Verification, + + [EnumMember(Value = "button")] + Button, } } diff --git a/Src/Notion.Client/Models/PropertyValue/RelationPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/RelationPropertyValue.cs index 3d11a096..6f9e0ec8 100644 --- a/Src/Notion.Client/Models/PropertyValue/RelationPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/RelationPropertyValue.cs @@ -4,14 +4,14 @@ namespace Notion.Client { /// - /// Relation property value object. + /// Relation property value object. /// public class RelationPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.Relation; /// - /// Array of page references + /// Array of page references /// [JsonProperty("relation")] public List Relation { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/RichTextPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/RichTextPropertyValue.cs index 028ed046..90e8d0be 100644 --- a/Src/Notion.Client/Models/PropertyValue/RichTextPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/RichTextPropertyValue.cs @@ -4,14 +4,14 @@ namespace Notion.Client { /// - /// Rich Text property value object. + /// Rich Text property value object. /// public class RichTextPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.RichText; /// - /// List of rich text objects + /// List of rich text objects /// [JsonProperty("rich_text")] public List RichText { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/RollupPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/RollupPropertyValue.cs index 7c573081..92020c61 100644 --- a/Src/Notion.Client/Models/PropertyValue/RollupPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/RollupPropertyValue.cs @@ -4,7 +4,7 @@ namespace Notion.Client { /// - /// Rollup property value object. + /// Rollup property value object. /// public class RollupPropertyValue : PropertyValue { @@ -15,31 +15,31 @@ public class RollupPropertyValue : PropertyValue } /// - /// Object containing rollup type-specific data. + /// Object containing rollup type-specific data. /// public class RollupValue { /// - /// The type of rollup. Possible values are "number", "date", and "array". + /// The type of rollup. Possible values are "number", "date", and "array". /// [JsonProperty("type")] public string Type { get; set; } /// - /// Number rollup property values contain a number + /// Number rollup property values contain a number /// [JsonProperty("number")] public double? Number { get; set; } /// - /// Date rollup property values contain a date property value. + /// 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. - /// Array containing the property value object will not contain value for Id field + /// Array rollup property values contain an array of element objects. + /// Array containing the property value object will not contain value for Id field /// [JsonProperty("array")] public List Array { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/SelectPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/SelectPropertyValue.cs index 07b2a346..63d333d9 100644 --- a/Src/Notion.Client/Models/PropertyValue/SelectPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/SelectPropertyValue.cs @@ -3,13 +3,13 @@ namespace Notion.Client { /// - /// Select property value object. + /// Select property value object. /// public class SelectPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.Select; - [JsonProperty("select")] + [JsonProperty("select", NullValueHandling = NullValueHandling.Include)] public SelectOption Select { get; set; } } } diff --git a/Src/Notion.Client/Models/PropertyValue/StatusPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/StatusPropertyValue.cs index 497e4c18..921ff810 100644 --- a/Src/Notion.Client/Models/PropertyValue/StatusPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/StatusPropertyValue.cs @@ -1,42 +1,18 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace Notion.Client { /// - /// Status property value objects contain page status + /// Status property value objects contain page status /// public class StatusPropertyValue : PropertyValue { - public override PropertyValueType Type => PropertyValueType.Status; - - [JsonProperty("status")] - public Data Status { get; set; } - - public class Data - { - /// - /// ID of the option. - /// - [JsonProperty("id")] - public string Id { get; set; } - - /// - /// Name of the option as it appears in Notion. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Color of the option. - /// - [JsonProperty("color")] - [JsonConverter(typeof(StringEnumConverter))] - public Color? Color { get; set; } - } - - public enum Color + [SuppressMessage("ReSharper", "UnusedMember.Global")] + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] + public enum StatusColor { [EnumMember(Value = "default")] Default, @@ -66,7 +42,34 @@ public enum Color Pink, [EnumMember(Value = "red")] - Red, + Red + } + + public override PropertyValueType Type => PropertyValueType.Status; + + [JsonProperty("status", NullValueHandling = NullValueHandling.Include)] + public Data Status { get; set; } + + public class Data + { + /// + /// ID of the option. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Name of the option as it appears in Notion. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Color of the option. + /// + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public StatusColor? Color { get; set; } } } } diff --git a/Src/Notion.Client/Models/PropertyValue/TitlePropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/TitlePropertyValue.cs index 58b7842d..e72a2a08 100644 --- a/Src/Notion.Client/Models/PropertyValue/TitlePropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/TitlePropertyValue.cs @@ -4,14 +4,14 @@ namespace Notion.Client { /// - /// Title property value object. + /// Title property value object. /// public class TitlePropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.Title; /// - /// An array of rich text objects + /// An array of rich text objects /// [JsonProperty("title")] public List Title { get; set; } diff --git a/Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs new file mode 100644 index 00000000..0ce1c704 --- /dev/null +++ b/Src/Notion.Client/Models/PropertyValue/UniqueIdPropertyValue.cs @@ -0,0 +1,28 @@ +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; } + } +} + diff --git a/Src/Notion.Client/Models/PropertyValue/UrlPropertyValue.cs b/Src/Notion.Client/Models/PropertyValue/UrlPropertyValue.cs index 08b800e6..91b5f71c 100644 --- a/Src/Notion.Client/Models/PropertyValue/UrlPropertyValue.cs +++ b/Src/Notion.Client/Models/PropertyValue/UrlPropertyValue.cs @@ -3,16 +3,16 @@ namespace Notion.Client { /// - /// URL property value object. + /// URL property value object. /// public class UrlPropertyValue : PropertyValue { public override PropertyValueType Type => PropertyValueType.Url; /// - /// Describes a web address + /// Describes a web address /// - [JsonProperty("url")] + [JsonProperty("url", NullValueHandling = NullValueHandling.Include)] public string Url { get; set; } } } 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; } + } + } +} diff --git a/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs b/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs index 61a7a887..062d75c0 100644 --- a/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs +++ b/Src/Notion.Client/Models/User/BotOwner/IBotOwner.cs @@ -4,8 +4,8 @@ namespace Notion.Client { [JsonConverter(typeof(JsonSubtypes), "type")] - [JsonSubtypes.KnownSubType(typeof(UserOwner), "user")] - [JsonSubtypes.KnownSubType(typeof(WorkspaceIntegrationOwner), "workspace")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(UserOwner), "user")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(WorkspaceIntegrationOwner), "workspace")] public interface IBotOwner { [JsonProperty("type")] diff --git a/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs b/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs index 40d69867..e60a4fab 100644 --- a/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs +++ b/Src/Notion.Client/Models/User/BotOwner/UserOwner.cs @@ -4,9 +4,9 @@ namespace Notion.Client { public class UserOwner : IBotOwner { - public string Type { get; set; } - [JsonProperty("user")] public User User { get; set; } + + public string Type { get; set; } } } diff --git a/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs b/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs index 78a84f6f..b5304157 100644 --- a/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs +++ b/Src/Notion.Client/Models/User/BotOwner/WorkspaceIntegrationOwner.cs @@ -4,9 +4,9 @@ namespace Notion.Client { public class WorkspaceIntegrationOwner : IBotOwner { - public string Type { get; set; } - [JsonProperty("workspace")] public bool Workspace { get; set; } + + public string Type { get; set; } } } diff --git a/Src/Notion.Client/Models/User/PartialUser.cs b/Src/Notion.Client/Models/User/PartialUser.cs index 5b335f0b..7e74c6d8 100644 --- a/Src/Notion.Client/Models/User/PartialUser.cs +++ b/Src/Notion.Client/Models/User/PartialUser.cs @@ -1,5 +1,8 @@ -namespace Notion.Client +using System.Diagnostics.CodeAnalysis; + +namespace Notion.Client { + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] public class PartialUser : IObject { public string Id { get; set; } diff --git a/Src/Notion.Client/Models/User/User.cs b/Src/Notion.Client/Models/User/User.cs index 7f336929..6ae9efef 100644 --- a/Src/Notion.Client/Models/User/User.cs +++ b/Src/Notion.Client/Models/User/User.cs @@ -4,9 +4,6 @@ namespace Notion.Client { public class User : IObject { - public ObjectType Object => ObjectType.User; - public string Id { get; set; } - [JsonProperty("type")] public string Type { get; set; } @@ -21,5 +18,9 @@ public class User : IObject [JsonProperty("bot")] public Bot Bot { get; set; } + + public ObjectType Object => ObjectType.User; + + public string Id { get; set; } } } diff --git a/Src/Notion.Client/Notion.Client.csproj b/Src/Notion.Client/Notion.Client.csproj index 274be515..2a6555c3 100644 --- a/Src/Notion.Client/Notion.Client.csproj +++ b/Src/Notion.Client/Notion.Client.csproj @@ -1,9 +1,9 @@ - + - 4.0.0-preview + 4.3.0-preview netstandard2.0 - 7.3 + 9.0 Notion.Net Vedant Koditkar @@ -16,11 +16,10 @@ - - all + runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/Src/Notion.Client/NotionAPIErrorCode.cs b/Src/Notion.Client/NotionAPIErrorCode.cs index f4cf699c..2ca2573f 100644 --- a/Src/Notion.Client/NotionAPIErrorCode.cs +++ b/Src/Notion.Client/NotionAPIErrorCode.cs @@ -1,7 +1,9 @@ -using System.Runtime.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum NotionAPIErrorCode { [EnumMember(Value = "invalid_json")] @@ -13,6 +15,9 @@ public enum NotionAPIErrorCode [EnumMember(Value = "invalid_request")] InvalidRequest, + [EnumMember(Value = "invalid_grant")] + InvalidGrant, + [EnumMember(Value = "validation_error")] ValidationError, @@ -37,7 +42,16 @@ public enum NotionAPIErrorCode [EnumMember(Value = "internal_server_error")] InternalServerError, + [EnumMember(Value = "bad_gateway")] + BadGateway, + [EnumMember(Value = "service_unavailable")] ServiceUnavailable, + + [EnumMember(Value = "database_connection_unavailable")] + DatabaseConnectionUnavailable, + + [EnumMember(Value = "gateway_timeout")] + GatewayTimeout } } diff --git a/Src/Notion.Client/NotionApiErrorResponse.cs b/Src/Notion.Client/NotionApiErrorResponse.cs index f21c6923..44a225b2 100644 --- a/Src/Notion.Client/NotionApiErrorResponse.cs +++ b/Src/Notion.Client/NotionApiErrorResponse.cs @@ -1,8 +1,13 @@ -namespace Notion.Client +using Newtonsoft.Json; + +namespace Notion.Client { - class NotionApiErrorResponse + internal class NotionApiErrorResponse { + [JsonProperty("code")] public NotionAPIErrorCode ErrorCode { get; set; } + + [JsonProperty("message")] public string Message { get; set; } } } diff --git a/Src/Notion.Client/NotionApiException.cs b/Src/Notion.Client/NotionApiException.cs index 358db384..cf62f1b6 100644 --- a/Src/Notion.Client/NotionApiException.cs +++ b/Src/Notion.Client/NotionApiException.cs @@ -1,8 +1,10 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Net; namespace Notion.Client { + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public class NotionApiException : Exception { public NotionApiException(HttpStatusCode statusCode, NotionAPIErrorCode? notionAPIErrorCode, string message) @@ -10,12 +12,7 @@ public NotionApiException(HttpStatusCode statusCode, NotionAPIErrorCode? notionA { } - public NotionApiException(HttpStatusCode statusCode, string message) - : this(statusCode, null, message, null) - { - } - - public NotionApiException( + private NotionApiException( HttpStatusCode statusCode, NotionAPIErrorCode? notionAPIErrorCode, string message, @@ -24,11 +21,17 @@ public NotionApiException( NotionAPIErrorCode = notionAPIErrorCode; StatusCode = statusCode; - Data.Add("StatusCode", statusCode); + InitializeData(); + } + + private void InitializeData() + { + Data.Add("StatusCode", StatusCode); Data.Add("NotionApiErrorCode", NotionAPIErrorCode); } public NotionAPIErrorCode? NotionAPIErrorCode { get; } + public HttpStatusCode StatusCode { get; } } } 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); + } + } +} diff --git a/Src/Notion.Client/NotionClient.cs b/Src/Notion.Client/NotionClient.cs index 5bbc6dad..2fc6f479 100644 --- a/Src/Notion.Client/NotionClient.cs +++ b/Src/Notion.Client/NotionClient.cs @@ -1,38 +1,63 @@ -namespace Notion.Client +using System.Diagnostics.CodeAnalysis; + +namespace Notion.Client { + [SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] public interface INotionClient { + IAuthenticationClient AuthenticationClient { get; } + IUsersClient Users { get; } + IDatabasesClient Databases { get; } + IPagesClient Pages { get; } + ISearchClient Search { get; } + IBlocksClient Blocks { get; } + + ICommentsClient Comments { get; } + IRestClient RestClient { get; } } public class NotionClient : INotionClient { public NotionClient( - RestClient restClient, - UsersClient users, - DatabasesClient databases, - PagesClient pages, - SearchClient search, - BlocksClient blocks) + IRestClient restClient, + IUsersClient users, + IDatabasesClient databases, + IPagesClient pages, + ISearchClient search, + ICommentsClient comments, + IBlocksClient blocks, + IAuthenticationClient authenticationClient) { RestClient = restClient; Users = users; Databases = databases; Pages = pages; Search = search; + Comments = comments; Blocks = blocks; + AuthenticationClient = authenticationClient; } + public IAuthenticationClient AuthenticationClient { get; } + public IUsersClient Users { get; } + public IDatabasesClient Databases { get; } + public IPagesClient Pages { get; } + public ISearchClient Search { get; } + public IBlocksClient Blocks { get; } + + public ICommentsClient Comments { get; } + public IRestClient RestClient { get; } } } diff --git a/Src/Notion.Client/NotionClientFactory.cs b/Src/Notion.Client/NotionClientFactory.cs index 4010eb8c..e66f0781 100644 --- a/Src/Notion.Client/NotionClientFactory.cs +++ b/Src/Notion.Client/NotionClientFactory.cs @@ -7,12 +7,14 @@ public static NotionClient Create(ClientOptions options) var restClient = new RestClient(options); return new NotionClient( - restClient: restClient - , users: new UsersClient(restClient) - , databases: new DatabasesClient(restClient) - , pages: new PagesClient(restClient) - , search: new SearchClient(restClient) - , blocks: new BlocksClient(restClient) + restClient + , new UsersClient(restClient) + , new DatabasesClient(restClient) + , new PagesClient(restClient) + , new SearchClient(restClient) + , new CommentsClient(restClient) + , new BlocksClient(restClient) + , new AuthenticationClient(restClient) ); } } diff --git a/Src/Notion.Client/RestClient/ClientOptions.cs b/Src/Notion.Client/RestClient/ClientOptions.cs index 3c6be1bc..d0015767 100644 --- a/Src/Notion.Client/RestClient/ClientOptions.cs +++ b/Src/Notion.Client/RestClient/ClientOptions.cs @@ -3,7 +3,9 @@ public class ClientOptions { public string BaseUrl { get; set; } + public string NotionVersion { get; set; } + public string AuthToken { get; set; } } } diff --git a/Src/Notion.Client/RestClient/IRestClient.cs b/Src/Notion.Client/RestClient/IRestClient.cs index 792840b6..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); @@ -34,7 +34,6 @@ Task DeleteAsync( string uri, IDictionary queryParams = null, IDictionary headers = null, - JsonSerializerSettings serializerSettings = null, CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/RestClient/LoggingHandler.cs b/Src/Notion.Client/RestClient/LoggingHandler.cs index 8655bb97..a6001d10 100644 --- a/Src/Notion.Client/RestClient/LoggingHandler.cs +++ b/Src/Notion.Client/RestClient/LoggingHandler.cs @@ -7,7 +7,9 @@ namespace Notion.Client { public class LoggingHandler : DelegatingHandler { - protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + protected override async Task SendAsync( + HttpRequestMessage request, + CancellationToken cancellationToken) { Log.Trace("Request: {request}", request); @@ -22,6 +24,7 @@ protected override async Task SendAsync(HttpRequestMessage catch (Exception ex) { Log.Error(ex, "Failed to get response: {exception}", ex); + throw; } } diff --git a/Src/Notion.Client/RestClient/RestClient.cs b/Src/Notion.Client/RestClient/RestClient.cs index b52b0ce3..59a848f7 100644 --- a/Src/Notion.Client/RestClient/RestClient.cs +++ b/Src/Notion.Client/RestClient/RestClient.cs @@ -14,68 +14,129 @@ namespace Notion.Client { public class RestClient : IRestClient { - private HttpClient _httpClient; private readonly ClientOptions _options; - protected readonly JsonSerializerSettings defaultSerializerSettings = new JsonSerializerSettings + protected readonly JsonSerializerSettings DefaultSerializerSettings = new() { NullValueHandling = NullValueHandling.Ignore, - ContractResolver = new DefaultContractResolver - { - NamingStrategy = new CamelCaseNamingStrategy() - } + ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() } }; + private HttpClient _httpClient; + public RestClient(ClientOptions options) { _options = MergeOptions(options); } - private static ClientOptions MergeOptions(ClientOptions options) + public async Task GetAsync( + string uri, + IDictionary queryParams = null, + IDictionary headers = null, + JsonSerializerSettings serializerSettings = null, + CancellationToken cancellationToken = default) { - return new ClientOptions + var response = await SendAsync(uri, HttpMethod.Get, queryParams, headers, + cancellationToken: cancellationToken); + + return await response.ParseStreamAsync(serializerSettings); + } + + public async Task PostAsync( + string uri, + object body, + IEnumerable> queryParams = null, + IDictionary headers = null, + JsonSerializerSettings serializerSettings = null, + CancellationToken cancellationToken = default) + { + void AttachContent(HttpRequestMessage httpRequest) { - AuthToken = options.AuthToken, - BaseUrl = options.BaseUrl ?? Constants.BASE_URL, - NotionVersion = options.NotionVersion ?? Constants.DEFAULT_NOTION_VERSION - }; + httpRequest.Content = new StringContent(JsonConvert.SerializeObject(body, DefaultSerializerSettings), + Encoding.UTF8, "application/json"); + } + + var response = await SendAsync(uri, HttpMethod.Post, queryParams, headers, AttachContent, + cancellationToken); + + return await response.ParseStreamAsync(serializerSettings); } - public async Task GetAsync( + public async Task PatchAsync( string uri, + object body, IDictionary queryParams = null, IDictionary headers = null, JsonSerializerSettings serializerSettings = null, CancellationToken cancellationToken = default) { - var response = await SendAsync(uri, HttpMethod.Get, queryParams, headers, cancellationToken: cancellationToken); + void AttachContent(HttpRequestMessage httpRequest) + { + var serializedBody = JsonConvert.SerializeObject(body, DefaultSerializerSettings); + httpRequest.Content = new StringContent(serializedBody, Encoding.UTF8, "application/json"); + } + + var response = await SendAsync(uri, new HttpMethod("PATCH"), queryParams, headers, AttachContent, + cancellationToken); return await response.ParseStreamAsync(serializerSettings); } + public async Task DeleteAsync( + string uri, + IDictionary queryParams = null, + IDictionary headers = null, + CancellationToken cancellationToken = default) + { + await SendAsync(uri, HttpMethod.Delete, queryParams, headers, null, cancellationToken); + } + + private static ClientOptions MergeOptions(ClientOptions options) + { + return new ClientOptions + { + AuthToken = options.AuthToken, + BaseUrl = options.BaseUrl ?? Constants.BaseUrl, + NotionVersion = options.NotionVersion ?? Constants.DefaultNotionVersion + }; + } + private static async Task BuildException(HttpResponseMessage response) { var errorBody = await response.Content.ReadAsStringAsync(); NotionApiErrorResponse errorResponse = null; + if (!string.IsNullOrWhiteSpace(errorBody)) { 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 + catch (Exception ex) { + Log.Error(ex, "Error when parsing the notion api response."); } } return new NotionApiException(response.StatusCode, errorResponse?.ErrorCode, errorResponse?.Message); } - public async Task SendAsync( + private async Task SendAsync( string requestUri, HttpMethod httpMethod, - IDictionary queryParams = null, + IEnumerable> queryParams = null, IDictionary headers = null, Action attachContent = null, CancellationToken cancellationToken = default) @@ -84,7 +145,7 @@ public async Task SendAsync( requestUri = AddQueryString(requestUri, queryParams); - HttpRequestMessage httpRequest = new HttpRequestMessage(httpMethod, requestUri); + using var httpRequest = new HttpRequestMessage(httpMethod, requestUri); httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _options.AuthToken); httpRequest.Headers.Add("Notion-Version", _options.NotionVersion); @@ -113,55 +174,20 @@ private static void AddHeaders(HttpRequestMessage request, IDictionary PostAsync( - string uri, - object body, - IDictionary queryParams = null, - IDictionary headers = null, - JsonSerializerSettings serializerSettings = null, - CancellationToken cancellationToken = default) + private void EnsureHttpClient() { - void AttachContent(HttpRequestMessage httpRequest) + if (_httpClient != null) { - httpRequest.Content = new StringContent(JsonConvert.SerializeObject(body, defaultSerializerSettings), Encoding.UTF8, "application/json"); + return; } - var response = await SendAsync(uri, HttpMethod.Post, queryParams, headers, AttachContent, cancellationToken: cancellationToken); - - return await response.ParseStreamAsync(serializerSettings); - } - - public async Task PatchAsync(string uri, object body, IDictionary queryParams = null, IDictionary headers = null, JsonSerializerSettings serializerSettings = null, CancellationToken cancellationToken = default) - { - void AttachContent(HttpRequestMessage httpRequest) - { - var serializedBody = JsonConvert.SerializeObject(body, defaultSerializerSettings); - httpRequest.Content = new StringContent(serializedBody, Encoding.UTF8, "application/json"); - } - - var response = await SendAsync(uri, new HttpMethod("PATCH"), queryParams, headers, AttachContent, cancellationToken: cancellationToken); - - return await response.ParseStreamAsync(serializerSettings); - } - - public async Task DeleteAsync(string uri, IDictionary queryParams = null, IDictionary headers = null, JsonSerializerSettings serializerSettings = null, CancellationToken cancellationToken = default) - { - await SendAsync(uri, HttpMethod.Delete, queryParams, headers, null, cancellationToken); - } - - private HttpClient EnsureHttpClient() - { - if (_httpClient == null) - { - var pipeline = new LoggingHandler() { InnerHandler = new HttpClientHandler() }; - _httpClient = new HttpClient(pipeline); - _httpClient.BaseAddress = new Uri(_options.BaseUrl); - } + var pipeline = new LoggingHandler { InnerHandler = new HttpClientHandler() }; - return _httpClient; + _httpClient = new HttpClient(pipeline); + _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 783ae20e..60de4e7b 100644 --- a/Src/Notion.Client/http/QueryHelpers.cs +++ b/Src/Notion.Client/http/QueryHelpers.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net; using System.Text; @@ -8,6 +9,7 @@ namespace Notion.Client.http { internal static class QueryHelpers { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public static string AddQueryString(string uri, string name, string value) { if (uri == null) @@ -43,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) { @@ -74,6 +76,7 @@ private static string AddQueryString( var sb = new StringBuilder(); sb.Append(uriToBeAppended); + foreach (var parameter in queryParams) { sb.Append(hasQuery ? '&' : '?'); @@ -84,13 +87,14 @@ private static string AddQueryString( } sb.Append(anchorText); + return sb.ToString(); } - private static IEnumerable> RemoveEmptyValueQueryParams(IEnumerable> queryParams) + private static IEnumerable> RemoveEmptyValueQueryParams( + IEnumerable> queryParams) { return queryParams.Where(x => !string.IsNullOrWhiteSpace(x.Value)); } - } } diff --git a/Test/Notion.IntegrationTests/BlocksClientTests.cs b/Test/Notion.IntegrationTests/BlocksClientTests.cs new file mode 100644 index 00000000..5f1ca25b --- /dev/null +++ b/Test/Notion.IntegrationTests/BlocksClientTests.cs @@ -0,0 +1,453 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using FluentAssertions; +using Notion.Client; +using Xunit; + +namespace Notion.IntegrationTests; + +public class IBlocksClientTests : IntegrationTestBase, IAsyncLifetime +{ + private Page _page = null!; + + public async Task InitializeAsync() + { + _page = await Client.Pages.CreateAsync( + PagesCreateParametersBuilder.Create( + new ParentPageInput { PageId = ParentPageId } + ).Build() + ); + } + + public async Task DisposeAsync() + { + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); + } + + [Fact] + public async Task AppendChildrenAsync_AppendsBlocksGivenBlocks() + { + var blocks = await Client.Blocks.AppendChildrenAsync( + new BlockAppendChildrenRequest + { + BlockId = _page.Id, + Children = new List + { + new BreadcrumbBlockRequest { Breadcrumb = new BreadcrumbBlockRequest.Data() }, + new DividerBlockRequest { Divider = new DividerBlockRequest.Data() }, + new TableOfContentsBlockRequest { TableOfContents = new TableOfContentsBlockRequest.Data() }, + new CalloutBlockRequest + { + Callout = new CalloutBlockRequest.Info + { + RichText = new List + { + new RichTextTextInput { Text = new Text { Content = "Test" } } + } + } + } + } + } + ); + + blocks.Results.Should().HaveCount(4); + } + + [Fact] + public async Task UpdateBlockAsync_UpdatesGivenBlock() + { + var blocks = await Client.Blocks.AppendChildrenAsync( + new BlockAppendChildrenRequest + { + BlockId = _page.Id, + Children = new List + { + new BreadcrumbBlockRequest { Breadcrumb = new BreadcrumbBlockRequest.Data() } + } + } + ); + + 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); + } + + [Fact] + public async Task DeleteAsync_DeleteBlockWithGivenId() + { + var blocks = await Client.Blocks.AppendChildrenAsync( + new BlockAppendChildrenRequest + { + BlockId = _page.Id, + Children = new List + { + new DividerBlockRequest { Divider = new DividerBlockRequest.Data() }, + new TableOfContentsBlockRequest { TableOfContents = new TableOfContentsBlockRequest.Data() } + } + } + ); + + blocks.Results.Should().HaveCount(2); + } + + [Theory] + [MemberData(nameof(BlockData))] + public async Task UpdateAsync_UpdatesGivenBlock( + IBlockObjectRequest block, IUpdateBlock updateBlock, Action assert) + { + var blocks = await Client.Blocks.AppendChildrenAsync( + new BlockAppendChildrenRequest + { + BlockId = _page.Id, + Children = new List { block } + } + ); + + var blockId = blocks.Results.First().Id; + await Client.Blocks.UpdateAsync(blockId, updateBlock); + + 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); + } + + private static IEnumerable BlockData() + { + return new List + { + new object[] + { + new BookmarkBlockRequest + { + Bookmark = new BookmarkBlockRequest.Info + { + Url = "https://developers.notion.com/reference/rich-text", + Caption = new List + { + new RichTextTextInput { Text = new Text { Content = "Notion API" } } + } + } + }, + new BookmarkUpdateBlock + { + Bookmark = new BookmarkUpdateBlock.Info + { + Url = "https://github.com/notion-dotnet/notion-sdk-net", + Caption = new List + { + new RichTextTextInput { Text = new Text { Content = "Github" } } + } + } + }, + new Action((block, _) => + { + var updatedBlock = (BookmarkBlock)block; + Assert.Equal("https://github.com/notion-dotnet/notion-sdk-net", updatedBlock.Bookmark.Url); + Assert.Equal("Github", updatedBlock.Bookmark.Caption.OfType().First().Text.Content); + }) + }, + new object[] + { + new EquationBlockRequest { Equation = new EquationBlockRequest.Info { Expression = "e=mc^3" } }, + new EquationUpdateBlock { Equation = new EquationUpdateBlock.Info { Expression = "e=mc^2" } }, + new Action((block, _) => + { + var updatedBlock = (EquationBlock)block; + Assert.Equal("e=mc^2", updatedBlock.Equation.Expression); + }) + }, + new object[] + { + new DividerBlockRequest { Divider = new DividerBlockRequest.Data() }, new DividerUpdateBlock(), + new Action((block, client) => + { + Assert.NotNull(block); + _ = Assert.IsType(block); + }) + }, + new object[] + { + new AudioBlockRequest + { + Audio = new ExternalFile + { + External = new ExternalFile.Info + { + Url = "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" + } + } + }, + new AudioUpdateBlock + { + Audio = new ExternalFileInput + { + External = new ExternalFileInput.Data + { + Url = "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-3.mp3" + } + } + }, + new Action((block, _) => + { + 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"); + }) + }, + new object[] + { + new TableOfContentsBlockRequest { TableOfContents = new TableOfContentsBlockRequest.Data() }, + new TableOfContentsUpdateBlock(), new Action((block, client) => + { + Assert.NotNull(block); + _ = Assert.IsType(block); + }) + }, + new object[] + { + new CalloutBlockRequest + { + Callout = new CalloutBlockRequest.Info + { + RichText = new List + { + new RichTextTextInput { Text = new Text { Content = "Test" } } + } + } + }, + new CalloutUpdateBlock + { + Callout = new CalloutUpdateBlock.Info + { + RichText = new List + { + new RichTextTextInput { Text = new Text { Content = "Test 2" } } + } + } + }, + new Action((block, _) => + { + Assert.NotNull(block); + var calloutBlock = Assert.IsType(block); + + Assert.Equal("Test 2", calloutBlock.Callout.RichText.OfType().First().Text.Content); + }) + }, + new object[] + { + new QuoteBlockRequest + { + Quote = new QuoteBlockRequest.Info + { + RichText = new List + { + new RichTextTextInput { Text = new Text { Content = "Test" } } + } + } + }, + new QuoteUpdateBlock + { + Quote = new QuoteUpdateBlock.Info + { + RichText = new List + { + new RichTextTextInput { Text = new Text { Content = "Test 2" } } + } + } + }, + new Action((block, _) => + { + Assert.NotNull(block); + var quoteBlock = Assert.IsType(block); + + Assert.Equal("Test 2", quoteBlock.Quote.RichText.OfType().First().Text.Content); + }) + }, + new object[] + { + new ImageBlockRequest + { + Image = new ExternalFile + { + External = new ExternalFile.Info + { + Url = "https://zephoria.com/wp-content/uploads/2014/08/online-community.jpg" + } + } + }, + new ImageUpdateBlock + { + Image = new ExternalFileInput + { + External = new ExternalFileInput.Data + { + Url + = "https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg" + } + } + }, + new Action((block, _) => + { + 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); + }) + }, + new object[] + { + new EmbedBlockRequest + { + Embed = new EmbedBlockRequest.Info + { + Url = "https://zephoria.com/wp-content/uploads/2014/08/online-community.jpg" + } + }, + new EmbedUpdateBlock + { + Embed = new EmbedUpdateBlock.Info + { + Url = "https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg" + } + }, + new Action((block, _) => + { + 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); + }) + }, + new object[] + { + new LinkToPageBlockRequest + { + LinkToPage = new PageParent + { + Type = ParentType.PageId, + PageId = "533578e3edf14c0a91a9da6b09bac3ee" + } + }, + new LinkToPageUpdateBlock + { + LinkToPage = new ParentPageInput { PageId = "3c357473a28149a488c010d2b245a589" } + }, + new Action((block, _) => + { + 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 + // This will change to updated ID once api start to support + Assert.Equal(Guid.Parse("533578e3edf14c0a91a9da6b09bac3ee"), Guid.Parse(pageParent.PageId)); + }) + }, + new object[] + { + new TableBlockRequest + { + Table = new TableBlockRequest.Info + { + TableWidth = 1, + Children = new[] + { + new TableRowBlockRequest + { + TableRow = new TableRowBlockRequest.Info + { + Cells = new[] + { + new[] { new RichTextText { Text = new Text { Content = "Data" } } } + } + } + } + } + } + }, + new TableUpdateBlock { Table = new TableUpdateBlock.Info { HasColumnHeader = false } }, + new Action((block, client) => + { + var tableBlock = block.Should().NotBeNull().And.BeOfType().Subject; + tableBlock.HasChildren.Should().BeTrue(); + + var children = client.Blocks + .RetrieveChildrenAsync(new BlockRetrieveChildrenRequest { BlockId = tableBlock.Id }) + .GetAwaiter().GetResult(); + + children.Results.Should().ContainSingle() + .Subject.Should().BeOfType() + .Subject.TableRow.Cells.Should().ContainSingle() + .Subject.Should().ContainSingle() + .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; + + // 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() + .Subject.Should().BeOfType().Subject + .Text.Content.Should().Be("Test file caption"); + }) + } + }; + } +} diff --git a/Test/Notion.IntegrationTests/CommentsClientTests.cs b/Test/Notion.IntegrationTests/CommentsClientTests.cs new file mode 100644 index 00000000..fac1fce1 --- /dev/null +++ b/Test/Notion.IntegrationTests/CommentsClientTests.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Notion.Client; +using Xunit; + +namespace Notion.IntegrationTests; + +public class CommentsClientTests : IntegrationTestBase, IAsyncLifetime +{ + private Page _page = null!; + + public async Task InitializeAsync() + { + _page = await Client.Pages.CreateAsync( + PagesCreateParametersBuilder.Create( + new ParentPageInput { PageId = ParentPageId } + ).Build() + ); + } + + public async Task DisposeAsync() + { + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); + } + + [Fact] + public async Task ShouldCreatePageComment() + { + // Arrange + var parameters = CreateCommentParameters.CreatePageComment( + new ParentPageInput { PageId = _page.Id }, + new List { new RichTextTextInput { Text = new Text { Content = "This is a comment" } } } + ); + + // Act + var response = await Client.Comments.CreateAsync(parameters); + + // Arrange + + Assert.NotNull(response.Parent); + Assert.NotNull(response.Id); + Assert.NotNull(response.DiscussionId); + + Assert.NotNull(response.RichText); + Assert.Single(response.RichText); + var richText = Assert.IsType(response.RichText.First()); + Assert.Equal("This is a comment", richText.Text.Content); + + var pageParent = Assert.IsType(response.Parent); + Assert.Equal(_page.Id, pageParent.PageId); + } + + [Fact] + public async Task ShouldCreateADiscussionComment() + { + // Arrange + var comment = await Client.Comments.CreateAsync( + CreateCommentParameters.CreatePageComment( + new ParentPageInput { PageId = _page.Id }, + new List + { + new RichTextTextInput { Text = new Text { Content = "This is a comment" } } + } + ) + ); + + // Act + var response = await Client.Comments.CreateAsync( + CreateCommentParameters.CreateDiscussionComment( + comment.DiscussionId, + new List + { + new RichTextTextInput { Text = new Text { Content = "This is a sub comment" } } + } + ) + ); + + // Arrange + Assert.NotNull(response.Parent); + Assert.NotNull(response.Id); + Assert.Equal(comment.DiscussionId, response.DiscussionId); + + Assert.NotNull(response.RichText); + Assert.Single(response.RichText); + var richText = Assert.IsType(response.RichText.First()); + Assert.Equal("This is a sub comment", richText.Text.Content); + + var pageParent = Assert.IsType(response.Parent); + Assert.Equal(_page.Id, pageParent.PageId); + } +} diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs new file mode 100644 index 00000000..7abd7b4e --- /dev/null +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -0,0 +1,188 @@ +using System; +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, IAsyncLifetime +{ + private Page _page = null!; + + public async Task InitializeAsync() + { + _page = await Client.Pages.CreateAsync( + PagesCreateParametersBuilder.Create( + new ParentPageInput { PageId = ParentPageId } + ).Build() + ); + } + + public async Task DisposeAsync() + { + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); + } + + [Fact] + public async Task QueryDatabase() + { + // Arrange + var createdDatabase = await CreateDatabaseWithAPageAsync("Test List"); + + // Act + var response = await Client.Databases.QueryAsync(createdDatabase.Id, new DatabasesQueryParameters()); + + // Assert + 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"); + } + + [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 + { + Title = new List + { + new RichTextTextInput + { + Text = new Text + { + Content = databaseName, + 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; + } + + [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/IBlocksClientTests.cs b/Test/Notion.IntegrationTests/IBlocksClientTests.cs deleted file mode 100644 index eabef5b4..00000000 --- a/Test/Notion.IntegrationTests/IBlocksClientTests.cs +++ /dev/null @@ -1,542 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using FluentAssertions; -using Notion.Client; -using Xunit; - -namespace Notion.IntegrationTests -{ - public class IBlocksClientTests - { - private readonly INotionClient _client; - - public IBlocksClientTests() - { - var options = new ClientOptions - { - AuthToken = Environment.GetEnvironmentVariable("NOTION_AUTH_TOKEN") - }; - - _client = NotionClientFactory.Create(options); - } - - [Fact] - public async Task AppendChildrenAsync_AppendsBlocksGivenBlocks() - { - var pageParentId = "3c357473a28149a488c010d2b245a589"; - - var page = await _client.Pages.CreateAsync( - PagesCreateParametersBuilder.Create( - new ParentPageInput() - { - PageId = pageParentId - } - ).Build() - ); - - var blocks = await _client.Blocks.AppendChildrenAsync( - page.Id, - new BlocksAppendChildrenParameters - { - Children = new List() - { - new BreadcrumbBlock - { - Breadcrumb = new BreadcrumbBlock.Data() - }, - new DividerBlock - { - Divider = new DividerBlock.Data() - }, - new TableOfContentsBlock - { - TableOfContents = new TableOfContentsBlock.Data() - }, - new CalloutBlock - { - Callout = new CalloutBlock.Info - { - RichText = new List { - new RichTextTextInput - { - Text = new Text - { - Content = "Test" - } - } - } - } - } - } - } - ); - - blocks.Results.Should().HaveCount(4); - - // cleanup - await _client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters - { - Archived = true - }); - } - - [Fact] - public async Task UpdateBlockAsync_UpdatesGivenBlock() - { - var pageParentId = "3c357473a28149a488c010d2b245a589"; - - var page = await _client.Pages.CreateAsync( - PagesCreateParametersBuilder.Create( - new ParentPageInput() - { - PageId = pageParentId - } - ).Build() - ); - - var blocks = await _client.Blocks.AppendChildrenAsync( - page.Id, - new BlocksAppendChildrenParameters - { - Children = new List() - { - new BreadcrumbBlock - { - Breadcrumb = new BreadcrumbBlock.Data() - } - } - } - ); - - var blockId = blocks.Results.First().Id; - await _client.Blocks.UpdateAsync(blockId, new BreadcrumbUpdateBlock()); - - blocks = await _client.Blocks.RetrieveChildrenAsync(page.Id); - blocks.Results.Should().HaveCount(1); - - // cleanup - await _client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters - { - Archived = true - }); - } - - [Fact] - public async Task DeleteAsync_DeleteBlockWithGivenId() - { - var pageParentId = "3c357473a28149a488c010d2b245a589"; - - var page = await _client.Pages.CreateAsync( - PagesCreateParametersBuilder.Create( - new ParentPageInput() - { - PageId = pageParentId - } - ).Build() - ); - - var blocks = await _client.Blocks.AppendChildrenAsync( - page.Id, - new BlocksAppendChildrenParameters - { - Children = new List() - { - new DividerBlock - { - Divider = new DividerBlock.Data() - }, - new TableOfContentsBlock - { - TableOfContents = new TableOfContentsBlock.Data() - }, - } - } - ); - - blocks.Results.Should().HaveCount(2); - - // cleanup - await _client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters - { - Archived = true - }); - } - - [Theory] - [MemberData(nameof(BlockData))] - public async Task UpdateAsync_UpdatesGivenBlock(IBlock block, IUpdateBlock updateBlock, Action assert) - { - var pageParentId = "3c357473a28149a488c010d2b245a589"; - - var page = await _client.Pages.CreateAsync( - PagesCreateParametersBuilder.Create( - new ParentPageInput - { - PageId = pageParentId - } - ).Build() - ); - - var blocks = await _client.Blocks.AppendChildrenAsync( - page.Id, - new BlocksAppendChildrenParameters - { - Children = new List() - { - block - } - } - ); - - var blockId = blocks.Results.First().Id; - await _client.Blocks.UpdateAsync(blockId, updateBlock); - - blocks = await _client.Blocks.RetrieveChildrenAsync(page.Id); - blocks.Results.Should().HaveCount(1); - - var updatedBlock = blocks.Results.First(); - - assert.Invoke(updatedBlock); - - // cleanup - await _client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters - { - Archived = true - }); - } - - private static IEnumerable BlockData() - { - return new List - { - new object[] { - new BookmarkBlock - { - Bookmark = new BookmarkBlock.Info - { - Url = "https://developers.notion.com/reference/rich-text", - Caption = new List - { - new RichTextTextInput - { - Text = new Text - { - Content = "Notion API" - } - } - } - } - }, - new BookmarkUpdateBlock { - Bookmark = new BookmarkUpdateBlock.Info - { - Url = "https://github.com/notion-dotnet/notion-sdk-net", - Caption = new List - { - new RichTextTextInput - { - Text = new Text - { - Content = "Github" - } - } - } - } - }, - new Action((block) => { - var updatedBlock = (BookmarkBlock)block; - Assert.Equal("https://github.com/notion-dotnet/notion-sdk-net", updatedBlock.Bookmark.Url); - Assert.Equal("Github", updatedBlock.Bookmark.Caption.OfType().First().Text.Content); - }) - }, - new object[] { - new EquationBlock - { - Equation = new EquationBlock.Info - { - Expression = "e=mc^3" - } - }, - new EquationUpdateBlock { - Equation = new EquationUpdateBlock.Info - { - Expression = "e=mc^2" - } - }, - new Action((block) => { - var updatedBlock = (EquationBlock)block; - Assert.Equal("e=mc^2", updatedBlock.Equation.Expression); - }) - }, - new object[] { - new DividerBlock { - Divider = new DividerBlock.Data() - }, - new DividerUpdateBlock(), - new Action((block) => { - Assert.NotNull(block); - Assert.IsType(block); - }) - }, - new object[] { - new AudioBlock { - Audio = new ExternalFile { - External = new ExternalFile.Info { - Url = "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" - } - } - }, - new AudioUpdateBlock { - Audio = new ExternalFileInput { - External = new ExternalFileInput.Data { - Url = "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-3.mp3" - } - } - }, - new Action((block) => { - 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"); - }) - }, - new object[] - { - new TableOfContentsBlock { - TableOfContents = new TableOfContentsBlock.Data() - }, - new TableOfContentsUpdateBlock(), - new Action((block) => - { - Assert.NotNull(block); - Assert.IsType(block); - }) - }, - new object[] - { - new CalloutBlock - { - Callout = new CalloutBlock.Info - { - RichText = new List - { - new RichTextTextInput - { - Text = new Text - { - Content = "Test" - } - } - } - } - }, - new CalloutUpdateBlock() - { - Callout = new CalloutUpdateBlock.Info - { - RichText = new List - { - new RichTextTextInput - { - Text = new Text - { - Content = "Test 2" - } - } - } - } - }, - new Action((block) => - { - Assert.NotNull(block); - var calloutBlock = Assert.IsType(block); - - Assert.Equal("Test 2", calloutBlock.Callout.RichText.OfType().First().Text.Content); - }) - }, - new object[] - { - new QuoteBlock - { - Quote = new QuoteBlock.Info - { - RichText = new List - { - new RichTextTextInput - { - Text = new Text - { - Content = "Test" - } - } - } - } - }, - new QuoteUpdateBlock() - { - Quote = new QuoteUpdateBlock.Info - { - RichText = new List - { - new RichTextTextInput - { - Text = new Text - { - Content = "Test 2" - } - } - } - } - }, - new Action((block) => - { - Assert.NotNull(block); - var quoteBlock = Assert.IsType(block); - - Assert.Equal("Test 2", quoteBlock.Quote.RichText.OfType().First().Text.Content); - }) - }, - new object[] - { - new ImageBlock() { - Image = new ExternalFile - { - External = new ExternalFile.Info - { - Url = "https://zephoria.com/wp-content/uploads/2014/08/online-community.jpg" - } - } - }, - new ImageUpdateBlock() - { - Image = new ExternalFileInput - { - External = new ExternalFileInput.Data - { - Url = "https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg" - } - } - }, - new Action (block => - { - 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); - }) - }, - new object[] - { - new EmbedBlock() - { - Embed = new EmbedBlock.Info - { - Url = "https://zephoria.com/wp-content/uploads/2014/08/online-community.jpg" - } - }, - new EmbedUpdateBlock() - { - Embed = new EmbedUpdateBlock.Info - { - Url = "https://www.iaspaper.net/wp-content/uploads/2017/09/TNEA-Online-Application.jpg" - } - }, - new Action (block => - { - 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); - }) - }, - 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 => - { - 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() - { - LinkToPage = new PageParent - { - Type = ParentType.PageId, - PageId = "533578e3edf14c0a91a9da6b09bac3ee" - } - }, - new LinkToPageUpdateBlock() - { - LinkToPage = new ParentPageInput - { - PageId = "3c357473a28149a488c010d2b245a589" - } - }, - new Action(block => - { - 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 - // This will change to updated ID once api start to support - Assert.Equal(Guid.Parse("533578e3edf14c0a91a9da6b09bac3ee"), Guid.Parse(pageParent.PageId)); - }) - } - }; - } - } -} diff --git a/Test/Notion.IntegrationTests/IPageClientTests.cs b/Test/Notion.IntegrationTests/IPageClientTests.cs deleted file mode 100644 index c1d78635..00000000 --- a/Test/Notion.IntegrationTests/IPageClientTests.cs +++ /dev/null @@ -1,234 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using FluentAssertions; -using Notion.Client; -using Xunit; - -namespace Notion.IntegrationTests -{ - public class IPageClientTests - { - private readonly INotionClient _client; - private readonly string _databaseId; - - public IPageClientTests() - { - var options = new ClientOptions - { - AuthToken = Environment.GetEnvironmentVariable("NOTION_AUTH_TOKEN") - }; - - _client = NotionClientFactory.Create(options); - _databaseId = Environment.GetEnvironmentVariable("DATABASE_ID") ?? "f86f2262-0751-40f2-8f63-e3f7a3c39fcb"; - } - - [Fact] - public async Task CreateAsync_CreatesANewPage() - { - PagesCreateParameters pagesCreateParameters = PagesCreateParametersBuilder.Create(new DatabaseParentInput - { - DatabaseId = _databaseId - }) - .AddProperty("Name", new TitlePropertyValue - { - Title = new List - { - new RichTextText - { - Text = new Text - { - Content = "Test Page Title" - } - } - } - }) - .Build(); - - var page = await _client.Pages.CreateAsync(pagesCreateParameters); - - page.Should().NotBeNull(); - page.Parent.Should().BeOfType().Which - .DatabaseId.Should().Be(_databaseId); - - page.Properties.Should().ContainKey("Name"); - page.Properties["Name"].Should().BeOfType().Which - .Title.First().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() - { - PagesCreateParameters pagesCreateParameters = PagesCreateParametersBuilder.Create(new DatabaseParentInput - { - DatabaseId = _databaseId - }) - .AddProperty("Name", new TitlePropertyValue - { - Title = new List - { - new RichTextText - { - Text = new Text - { - Content = "Test Page Title" - } - } - } - }) - .AddProperty("TestSelect", new SelectPropertyValue - { - Select = new SelectOption - { - Id = "dfbfbe65-6f67-4876-9f75-699124334d06" - } - }) - .Build(); - - var page = await _client.Pages.CreateAsync(pagesCreateParameters); - - page.Should().NotBeNull(); - page.Parent.Should().BeOfType().Which - .DatabaseId.Should().Be(_databaseId); - - page.Properties.Should().ContainKey("Name"); - page.Properties["Name"].Should().BeOfType().Which - .Title.First().PlainText.Should().Be("Test Page Title"); - - await _client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters - { - Archived = true - }); - } - - [Fact] - public async Task Test_RetrievePagePropertyItemAsync() - { - PagesCreateParameters pagesCreateParameters = PagesCreateParametersBuilder.Create(new DatabaseParentInput - { - DatabaseId = _databaseId - }) - .AddProperty("Name", new TitlePropertyValue - { - Title = new List - { - new RichTextText - { - Text = new Text - { - Content = "Test Page Title" - } - } - } - }) - .Build(); - - var page = await _client.Pages.CreateAsync(pagesCreateParameters); - - var property = await _client.Pages.RetrievePagePropertyItem(new RetrievePropertyItemParameters - { - PageId = page.Id, - PropertyId = "title" - }); - - property.Should().NotBeNull(); - property.Should().BeOfType(); - - var listProperty = (ListPropertyItem)property; - - listProperty.Type.Should().NotBeNull(); - listProperty.Results.Should().SatisfyRespectively(p => - { - p.Should().BeOfType(); - var titleProperty = (TitlePropertyItem)p; - - 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 - - string datePropertyName = "Test Date Property"; - var updateDatabaseParameters = new DatabasesUpdateParameters(); - updateDatabaseParameters.Properties = new Dictionary - { - { "Name", new TitleUpdatePropertySchema { Title = new Dictionary() } }, - { "Test Date Property", new DateUpdatePropertySchema{ Date = new Dictionary() } } - }; - - PagesCreateParameters pagesCreateParameters = PagesCreateParametersBuilder.Create(new DatabaseParentInput - { - DatabaseId = _databaseId - }) - .AddProperty("Name", new TitlePropertyValue - { - Title = new List - { - new RichTextText - { - Text = new Text - { - Content = "Test Page Title" - } - } - } - }) - .AddProperty(datePropertyName, new DatePropertyValue - { - Date = new Date() - { - Start = Convert.ToDateTime("2020-12-08T12:00:00Z"), - End = Convert.ToDateTime("2025-12-08T12:00:00Z") - } - }) - .Build(); - - var updatedDb = await _client.Databases.UpdateAsync(_databaseId, updateDatabaseParameters); - - var page = await _client.Pages.CreateAsync(pagesCreateParameters); - - var setDate = (DatePropertyItem)await _client.Pages.RetrievePagePropertyItem(new RetrievePropertyItemParameters - { - PageId = page.Id, - PropertyId = page.Properties[datePropertyName].Id - }); - - 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 updatedPage = await _client.Pages.UpdateAsync(page.Id, new PagesUpdateParameters - { - Properties = testProps - }); - - var verifyDate = (DatePropertyItem)await _client.Pages.RetrievePagePropertyItem(new RetrievePropertyItemParameters - { - PageId = page.Id, - PropertyId = updatedPage.Properties[datePropertyName].Id - }); - - verifyDate?.Date.Should().BeNull(); - - //cleanup - await _client.Blocks.DeleteAsync(page.Id); - } - } -} diff --git a/Test/Notion.IntegrationTests/IntegrationTestBase.cs b/Test/Notion.IntegrationTests/IntegrationTestBase.cs new file mode 100644 index 00000000..31836c32 --- /dev/null +++ b/Test/Notion.IntegrationTests/IntegrationTestBase.cs @@ -0,0 +1,24 @@ +using System; +using Notion.Client; + +namespace Notion.IntegrationTests; + +public abstract class IntegrationTestBase +{ + protected readonly INotionClient Client; + protected readonly string ParentPageId; + protected readonly string ParentDatabaseId; + + protected IntegrationTestBase() + { + var options = new ClientOptions { AuthToken = Environment.GetEnvironmentVariable("NOTION_AUTH_TOKEN") }; + + Client = NotionClientFactory.Create(options); + + ParentPageId = Environment.GetEnvironmentVariable("NOTION_PARENT_PAGE_ID") + ?? throw new InvalidOperationException("Parent page id is required."); + + ParentDatabaseId = Environment.GetEnvironmentVariable("NOTION_PARENT_DATABASE_ID") + ?? throw new InvalidOperationException("Parent database id is required."); + } +} 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.IntegrationTests/PageClientTests.cs b/Test/Notion.IntegrationTests/PageClientTests.cs new file mode 100644 index 00000000..4938bcfa --- /dev/null +++ b/Test/Notion.IntegrationTests/PageClientTests.cs @@ -0,0 +1,434 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using FluentAssertions; +using Notion.Client; +using Xunit; + +namespace Notion.IntegrationTests; + +public class PageClientTests : IntegrationTestBase, IAsyncLifetime +{ + private Page _page = null!; + private Database _database = null!; + + public async Task InitializeAsync() + { + // Create a page + _page = await Client.Pages.CreateAsync( + PagesCreateParametersBuilder.Create( + new ParentPageInput { PageId = ParentPageId } + ).Build() + ); + + // 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 = await Client.Databases.CreateAsync(createDbRequest); + } + + public async Task DisposeAsync() + { + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); + } + + [Fact] + public async Task CreateAsync_CreatesANewPage() + { + var pagesCreateParameters = PagesCreateParametersBuilder + .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .AddProperty("Name", + new TitlePropertyValue + { + Title = new List + { + new RichTextText { Text = new Text { Content = "Test Page Title" } } + } + }) + .Build(); + + var page = await Client.Pages.CreateAsync(pagesCreateParameters); + + 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.PlainText.Should().Be("Test Page Title"); + } + + [Fact] + public async Task Bug_unable_to_create_page_with_select_property() + { + // Arrange + var pagesCreateParameters = PagesCreateParametersBuilder + .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .AddProperty("Name", + new TitlePropertyValue + { + Title = new List + { + new RichTextText { Text = new Text { Content = "Test Page Title" } } + } + }) + .AddProperty("TestSelect", + 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(_database.Id); + + page.Properties.Should().ContainKey("Name"); + var titlePropertyValue = page.Properties["Name"].Should().BeOfType().Subject; + titlePropertyValue.Title.First().PlainText.Should().Be("Test Page Title"); + + 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 = _database.Id }) + .AddProperty("Name", + new TitlePropertyValue + { + Title = new List + { + new RichTextText { Text = new Text { Content = "Test Page Title" } } + } + }) + .Build(); + + 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(); + + var listProperty = (ListPropertyItem)property; + + listProperty.Type.Should().NotBeNull(); + + listProperty.Results.Should().SatisfyRespectively(p => + { + p.Should().BeOfType(); + var titleProperty = (TitlePropertyItem)p; + + titleProperty.Title.PlainText.Should().Be("Test Page Title"); + }); + } + + [Fact] + public async Task Test_UpdatePageProperty_with_date_as_null() + { + // Arrange + + // Add property Date property to database + const string DatePropertyName = "Test Date Property"; + + var updateDatabaseParameters = new DatabasesUpdateParameters + { + Properties = new Dictionary + { + { "Name", new TitleUpdatePropertySchema { Title = new Dictionary() } }, + { + "Test Date Property", + new DateUpdatePropertySchema { Date = new Dictionary() } + } + } + }; + + // Create a page with the property having a date + var pagesCreateParameters = PagesCreateParametersBuilder + .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .AddProperty("Name", + new TitlePropertyValue + { + Title = new List + { + new RichTextText { Text = new Text { Content = "Test Page Title" } } + } + }) + .AddProperty(DatePropertyName, + new DatePropertyValue + { + Date = new Date + { + Start = DateTimeOffset.Parse("2024-06-26T00:00:00.000+01:00"), + End = DateTimeOffset.Parse("2025-12-08").Date + } + }) + .Build(); + + await Client.Databases.UpdateAsync(_database.Id, updateDatabaseParameters); + + var page = await Client.Pages.CreateAsync(pagesCreateParameters); + + // Act + var setDate = (DatePropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( + new RetrievePropertyItemParameters + { + PageId = page.Id, + PropertyId = page.Properties[DatePropertyName].Id + } + ); + + // Assert + 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 + { + Properties = new Dictionary + { + { DatePropertyName, new DatePropertyValue { Date = null } } + } + }; + + 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(); + } + + [Fact] + public async Task Bug_Unable_To_Parse_NumberPropertyItem() + { + // Arrange + var pagesCreateParameters = PagesCreateParametersBuilder + .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(); + + // Act + var page = await Client.Pages.CreateAsync(pagesCreateParameters); + + // Assert + Assert.NotNull(page); + var pageParent = Assert.IsType(page.Parent); + Assert.Equal(_database.Id, pageParent.DatabaseId); + + var titleProperty = (ListPropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( + new RetrievePropertyItemParameters + { + PageId = page.Id, + PropertyId = page.Properties["Name"].Id + }); + + Assert.Equal("Test Page Title", titleProperty.Results.First().As().Title.PlainText); + + var numberProperty = (NumberPropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( + new RetrievePropertyItemParameters + { + PageId = page.Id, + PropertyId = page.Properties["Number"].Id + }); + + Assert.Equal(200.00, numberProperty.Number); + } + + [Fact] + public async Task Bug_exception_when_attempting_to_set_select_property_to_nothing() + { + // Arrange + var databaseCreateRequest = new DatabasesCreateParameters + { + Title = + 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() } }, + { + "Colors1", + new SelectPropertySchema + { + Select = new OptionWrapper + { + Options = new List + { + new() { Name = "Red" }, + new() { Name = "Green" }, + new() { Name = "Blue" } + } + } + } + }, + { + "Colors2", + new SelectPropertySchema + { + Select = new OptionWrapper + { + Options = new List + { + new() { Name = "Red" }, + new() { Name = "Green" }, + new() { Name = "Blue" } + } + } + } + }, + } + }; + + var database = await Client.Databases.CreateAsync(databaseCreateRequest); + + var pagesCreateParameters = PagesCreateParametersBuilder + .Create(new DatabaseParentInput { DatabaseId = database.Id }) + .AddProperty("title", + new TitlePropertyValue + { + Title = new List + { + new RichTextTextInput { Text = new Text { Content = "Test" } } + } + }) + .AddProperty("Colors1", new SelectPropertyValue { Select = new SelectOption { Name = "Red" } }) + .AddProperty("Colors2", new SelectPropertyValue { Select = new SelectOption { Name = "Green" } }) + .Build(); + + // Act + var page = await Client.Pages.CreateAsync(pagesCreateParameters); + + var updatePageRequest = new PagesUpdateParameters + { + Properties = new Dictionary + { + { "Colors1", new SelectPropertyValue { Select = new SelectOption { Name = "Blue" } } }, + { "Colors2", new SelectPropertyValue { Select = null } } + } + }; + + 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(); + } + + [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() + { + 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 + }); + + var mention = titleProperty.Results.First().As().Title.As().Mention; + mention.Date.Start.Should().NotBeNull(); + mention.Date.End.Should().BeNull(); + } +} diff --git a/Test/Notion.IntegrationTests/PageWithPageParentTests.cs b/Test/Notion.IntegrationTests/PageWithPageParentTests.cs new file mode 100644 index 00000000..3c6d3c6c --- /dev/null +++ b/Test/Notion.IntegrationTests/PageWithPageParentTests.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using FluentAssertions; +using Notion.Client; +using Xunit; + +namespace Notion.IntegrationTests; + +public class PageWithPageParentTests : IntegrationTestBase, IAsyncLifetime +{ + private Page _page = null!; + + public async Task InitializeAsync() + { + var pagesCreateParameters = PagesCreateParametersBuilder + .Create(new ParentPageInput() { PageId = ParentPageId }) + .AddProperty("title", + new TitlePropertyValue + { + Title = new List + { + new RichTextTextInput { Text = new Text { Content = "Test Page Title" } } + } + }).Build(); + + _page = await Client.Pages.CreateAsync(pagesCreateParameters); + } + + public async Task DisposeAsync() + { + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); + } + + [Fact] + public async Task Update_Title_Of_Page() + { + // Arrange + var updatePage = new PagesUpdateParameters() + { + Properties = new Dictionary + { + { + "title", + new TitlePropertyValue() + { + Title = new List + { + new RichTextText { Text = new Text() { Content = "Page Title Updated" } } + } + } + } + } + }; + + // Act + var updatedPage = await Client.Pages.UpdateAsync(_page.Id, updatePage); + + // Assert + var titleProperty = (ListPropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( + new RetrievePropertyItemParameters + { + PageId = updatedPage.Id, + PropertyId = updatedPage.Properties["title"].Id + } + ); + + titleProperty.Results.First().As().Title.PlainText.Should().Be("Page Title Updated"); + } +} diff --git a/Test/Notion.UnitTests/ApiTestBase.cs b/Test/Notion.UnitTests/ApiTestBase.cs index e593a47c..51dfd7fc 100644 --- a/Test/Notion.UnitTests/ApiTestBase.cs +++ b/Test/Notion.UnitTests/ApiTestBase.cs @@ -1,70 +1,58 @@ using System; using System.Linq; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; using Notion.Client; using WireMock.Matchers; using WireMock.RequestBuilders; using WireMock.Server; -namespace Notion.UnitTests +namespace Notion.UnitTests; + +public class ApiTestBase : IDisposable { - public class ApiTestBase : IDisposable + protected readonly ClientOptions ClientOptions; + protected readonly WireMockServer Server; + + protected ApiTestBase() { - protected readonly WireMockServer Server; + Server = WireMockServer.Start(); - protected static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings() + ClientOptions = new ClientOptions { - Formatting = Newtonsoft.Json.Formatting.Indented, - ContractResolver = new DefaultContractResolver - { - NamingStrategy = new CamelCaseNamingStrategy() - } + BaseUrl = Server.Urls.First(), + AuthToken = "" }; + } - protected readonly ClientOptions ClientOptions; - - protected ApiTestBase() - { - Server = WireMockServer.Start(); - ClientOptions = new ClientOptions() - { - BaseUrl = Server.Urls.First(), - AuthToken = "" - }; - } - - public void Dispose() - { - Server.Stop(); - Server.Dispose(); - } + public void Dispose() + { + Server.Stop(); + Server.Dispose(); + } - protected IRequestBuilder CreateGetRequestBuilder(string path) - { - return Request.Create() - .WithPath(path) - .UsingGet() - .WithHeader("Authorization", $"Bearer {ClientOptions.AuthToken}", MatchBehaviour.AcceptOnMatch) - .WithHeader("Notion-Version", Constants.DEFAULT_NOTION_VERSION, MatchBehaviour.AcceptOnMatch); - } + protected IRequestBuilder CreateGetRequestBuilder(string path) + { + return Request.Create() + .WithPath(path) + .UsingGet() + .WithHeader("Authorization", $"Bearer {ClientOptions.AuthToken}", MatchBehaviour.AcceptOnMatch) + .WithHeader("Notion-Version", Constants.DefaultNotionVersion, MatchBehaviour.AcceptOnMatch); + } - protected IRequestBuilder CreatePostRequestBuilder(string path) - { - return Request.Create() - .WithPath(path) - .UsingPost() - .WithHeader("Authorization", $"Bearer {ClientOptions.AuthToken}", MatchBehaviour.AcceptOnMatch) - .WithHeader("Notion-Version", Constants.DEFAULT_NOTION_VERSION, MatchBehaviour.AcceptOnMatch); - } + protected IRequestBuilder CreatePostRequestBuilder(string path) + { + return Request.Create() + .WithPath(path) + .UsingPost() + .WithHeader("Authorization", $"Bearer {ClientOptions.AuthToken}", MatchBehaviour.AcceptOnMatch) + .WithHeader("Notion-Version", Constants.DefaultNotionVersion, MatchBehaviour.AcceptOnMatch); + } - protected IRequestBuilder CreatePatchRequestBuilder(string path) - { - return Request.Create() - .WithPath(path) - .UsingPatch() - .WithHeader("Authorization", $"Bearer {ClientOptions.AuthToken}", MatchBehaviour.AcceptOnMatch) - .WithHeader("Notion-Version", Constants.DEFAULT_NOTION_VERSION, MatchBehaviour.AcceptOnMatch); - } + protected IRequestBuilder CreatePatchRequestBuilder(string path) + { + return Request.Create() + .WithPath(path) + .UsingPatch() + .WithHeader("Authorization", $"Bearer {ClientOptions.AuthToken}", MatchBehaviour.AcceptOnMatch) + .WithHeader("Notion-Version", Constants.DefaultNotionVersion, MatchBehaviour.AcceptOnMatch); } } diff --git a/Test/Notion.UnitTests/BlocksClientTests.cs b/Test/Notion.UnitTests/BlocksClientTests.cs index 753e5464..e2cc8603 100644 --- a/Test/Notion.UnitTests/BlocksClientTests.cs +++ b/Test/Notion.UnitTests/BlocksClientTests.cs @@ -7,191 +7,189 @@ using WireMock.ResponseBuilders; using Xunit; -namespace Notion.UnitTests +namespace Notion.UnitTests; + +public class BlocksClientTests : ApiTestBase { - public class BlocksClientTests : ApiTestBase - { - private readonly IBlocksClient _client; + private readonly IBlocksClient _client; - public BlocksClientTests() - { - _client = new BlocksClient(new RestClient(ClientOptions)); - } + public BlocksClientTests() + { + _client = new BlocksClient(new RestClient(ClientOptions)); + } - [Fact] - public async Task RetrieveBlockChildren() - { - // Arrange - string blockId = "3c357473-a281-49a4-88c0-10d2b245a589"; - var path = ApiEndpoints.BlocksApiUrls.RetrieveChildren(blockId); - var jsonData = await File.ReadAllTextAsync("data/blocks/RetrieveBlockChildrenResponse.json"); + [Fact] + public async Task RetrieveBlockChildren() + { + // Arrange + var blockId = "3c357473-a281-49a4-88c0-10d2b245a589"; + var path = ApiEndpoints.BlocksApiUrls.RetrieveChildren(blockId); + var jsonData = await File.ReadAllTextAsync("data/blocks/RetrieveBlockChildrenResponse.json"); - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - // Act - var childrenResult = await _client.RetrieveChildrenAsync(blockId, new BlocksRetrieveChildrenParameters()); + // Act + var childrenResult = await _client.RetrieveChildrenAsync(new BlockRetrieveChildrenRequest + { + BlockId = blockId + }); - // Assert - var children = childrenResult.Results; - children.Should().HaveCount(8); - } + // Assert + var children = childrenResult.Results; + children.Should().HaveCount(9); + } - [Fact] - public async Task AppendBlockChildren() - { - // Arrange - string blockId = "7face6fd-3ef4-4b38-b1dc-c5044988eec0"; - var path = ApiEndpoints.BlocksApiUrls.AppendChildren(blockId); + [Fact] + public async Task AppendBlockChildren() + { + // Arrange + var blockId = "7face6fd-3ef4-4b38-b1dc-c5044988eec0"; + var path = ApiEndpoints.BlocksApiUrls.AppendChildren(blockId); - var jsonData = await File.ReadAllTextAsync("data/blocks/AppendBlockChildrenResponse.json"); + var jsonData = await File.ReadAllTextAsync("data/blocks/AppendBlockChildrenResponse.json"); - Server.Given(CreatePatchRequestBuilder(path)) - .RespondWith( + Server.Given(CreatePatchRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var parameters = new BlocksAppendChildrenParameters() + var request = new BlockAppendChildrenRequest + { + BlockId = blockId, + Children = new List { - Children = new List + new HeadingTwoBlockRequest { - new HeadingTwoBlock() + Heading_2 = new HeadingTwoBlockRequest.Info { - Heading_2 = new HeadingTwoBlock.Info + RichText = new List { - RichText = new List - { - new RichTextText - { - Text = new Text - { - Content = "Lacinato kale" - } - } - } + new RichTextText { Text = new Text { Content = "Lacinato kale" } } } - }, - new ParagraphBlock() + } + }, + new ParagraphBlockRequest + { + Paragraph = new ParagraphBlockRequest.Info { - Paragraph = new ParagraphBlock.Info + RichText = new List { - RichText = new List + new RichTextText { - new RichTextText + Text = new Text { - Text = new Text + Content + = "Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", + Link = new Link { - Content = "Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm.", - Link = new Link - { - Url = "https://en.wikipedia.org/wiki/Lacinato_kale" - } + Url + = "https://en.wikipedia.org/wiki/Lacinato_kale" } } } } } } - }; + } + }; - // Act - var blocksResult = await _client.AppendChildrenAsync(blockId, parameters); + // Act + var blocksResult = await _client.AppendChildrenAsync(request); - // Assert - var blocks = blocksResult.Results; - blocks.Should().SatisfyRespectively( - block => - { - block.Type.Should().Be(BlockType.Heading_2); - var headingBlock = (HeadingTwoBlock)block; - var text = headingBlock.Heading_2.RichText.OfType().FirstOrDefault(); - text.Text.Content.Should().Be("Lacinato kale"); - }, - block => - { - block.Type.Should().Be(BlockType.Paragraph); - var paragraphBlock = (ParagraphBlock)block; - var text = paragraphBlock.Paragraph.RichText.OfType().LastOrDefault(); - text.Text.Content.Should().Be("Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm."); - text.Text.Link.Url.Should().Be("https://en.wikipedia.org/wiki/Lacinato_kale"); - } - ); - } + // Assert + var blocks = blocksResult.Results; - [Fact] - public async Task RetrieveAsync() - { - string blockId = "9bc30ad4-9373-46a5-84ab-0a7845ee52e6"; - var path = ApiEndpoints.BlocksApiUrls.Retrieve(blockId); - var jsonData = await File.ReadAllTextAsync("data/blocks/RetrieveBlockResponse.json"); + blocks.Should().SatisfyRespectively( + block => + { + block.Type.Should().Be(BlockType.Heading_2); + var headingBlock = (HeadingTwoBlock)block; + var text = headingBlock.Heading_2.RichText.OfType().First(); + text.Text.Content.Should().Be("Lacinato kale"); + }, + block => + { + block.Type.Should().Be(BlockType.Paragraph); + var paragraphBlock = (ParagraphBlock)block; + var text = paragraphBlock.Paragraph.RichText.OfType().Last(); + + text.Text.Content.Should().Be( + "Lacinato kale is a variety of kale with a long tradition in Italian cuisine, especially that of Tuscany. It is also known as Tuscan kale, Italian kale, dinosaur kale, kale, flat back kale, palm tree kale, or black Tuscan palm."); + + text.Text.Link.Url.Should().Be("https://en.wikipedia.org/wiki/Lacinato_kale"); + } + ); + } + + [Fact] + public async Task RetrieveAsync() + { + var blockId = "9bc30ad4-9373-46a5-84ab-0a7845ee52e6"; + var path = ApiEndpoints.BlocksApiUrls.Retrieve(blockId); + var jsonData = await File.ReadAllTextAsync("data/blocks/RetrieveBlockResponse.json"); - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var block = await _client.RetrieveAsync(blockId); + var block = await _client.RetrieveAsync(blockId); - block.Id.Should().Be(blockId); - block.HasChildren.Should().BeFalse(); - block.Type.Should().Be(BlockType.ToDo); + block.Id.Should().Be(blockId); + block.HasChildren.Should().BeFalse(); + block.Type.Should().Be(BlockType.ToDo); - var todoBlock = ((ToDoBlock)block); - todoBlock.ToDo.RichText.Should().ContainSingle(); - todoBlock.ToDo.RichText.First().Should().BeAssignableTo(); - ((RichTextText)todoBlock.ToDo.RichText.First()).Text.Content.Should().Be("Lacinato kale"); - } + var todoBlock = (ToDoBlock)block; + todoBlock.ToDo.RichText.Should().ContainSingle(); + todoBlock.ToDo.RichText.First().Should().BeAssignableTo(); + ((RichTextText)todoBlock.ToDo.RichText.First()).Text.Content.Should().Be("Lacinato kale"); + } - [Fact] - public async Task UpdateAsync() - { - string blockId = "9bc30ad4-9373-46a5-84ab-0a7845ee52e6"; - var path = ApiEndpoints.BlocksApiUrls.Update(blockId); - var jsonData = await File.ReadAllTextAsync("data/blocks/UpdateBlockResponse.json"); + [Fact] + public async Task UpdateAsync() + { + var blockId = "9bc30ad4-9373-46a5-84ab-0a7845ee52e6"; + var path = ApiEndpoints.BlocksApiUrls.Update(blockId); + var jsonData = await File.ReadAllTextAsync("data/blocks/UpdateBlockResponse.json"); - Server.Given(CreatePatchRequestBuilder(path)) - .RespondWith( + Server.Given(CreatePatchRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var updateBlock = new ToDoUpdateBlock + var updateBlock = new ToDoUpdateBlock + { + ToDo = new ToDoUpdateBlock.Info { - ToDo = new ToDoUpdateBlock.Info + RichText = new List { - RichText = new List() - { - new RichTextTextInput - { - Text = new Text - { - Content = "Lacinato kale" - }, - } - }, - IsChecked = true - } - }; + new RichTextTextInput { Text = new Text { Content = "Lacinato kale" } } + }, + IsChecked = true + } + }; - var block = await _client.UpdateAsync(blockId, updateBlock); + var block = await _client.UpdateAsync(blockId, updateBlock); - block.Id.Should().Be(blockId); - block.HasChildren.Should().BeFalse(); - block.Type.Should().Be(BlockType.ToDo); + block.Id.Should().Be(blockId); + block.HasChildren.Should().BeFalse(); + block.InTrash.Should().BeFalse(); + block.Type.Should().Be(BlockType.ToDo); - var todoBlock = ((ToDoBlock)block); - todoBlock.ToDo.RichText.Should().ContainSingle(); - todoBlock.ToDo.RichText.First().Should().BeAssignableTo(); - ((RichTextText)todoBlock.ToDo.RichText.First()).Text.Content.Should().Be("Lacinato kale"); - } + var todoBlock = (ToDoBlock)block; + todoBlock.ToDo.RichText.Should().ContainSingle(); + todoBlock.ToDo.RichText.First().Should().BeAssignableTo(); + ((RichTextText)todoBlock.ToDo.RichText.First()).Text.Content.Should().Be("Lacinato kale"); } } diff --git a/Test/Notion.UnitTests/DatabasesClientTests.cs b/Test/Notion.UnitTests/DatabasesClientTests.cs index 8e3689e8..30deae75 100644 --- a/Test/Notion.UnitTests/DatabasesClientTests.cs +++ b/Test/Notion.UnitTests/DatabasesClientTests.cs @@ -7,191 +7,194 @@ using WireMock.ResponseBuilders; using Xunit; -namespace Notion.UnitTests +namespace Notion.UnitTests; + +public class DatabasesClientTests : ApiTestBase { - public class DatabasesClientTests : ApiTestBase + private readonly IDatabasesClient _client; + private readonly IPagesClient _pagesClient; + + public DatabasesClientTests() { - private readonly IDatabasesClient _client; - private readonly IPagesClient _pagesClient; - public DatabasesClientTests() - { - _client = new DatabasesClient(new RestClient(ClientOptions)); - _pagesClient = new PagesClient(new RestClient(ClientOptions)); - } + _client = new DatabasesClient(new RestClient(ClientOptions)); + _pagesClient = new PagesClient(new RestClient(ClientOptions)); + } - [Fact] - public async Task QueryAsync() - { - var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; - var path = ApiEndpoints.DatabasesApiUrls.Query(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/DatabasesQueryResponse.json"); + [Fact] + public async Task QueryAsync() + { + var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; + var path = ApiEndpoints.DatabasesApiUrls.Query(databaseId); + var jsonData = await File.ReadAllTextAsync("data/databases/DatabasesQueryResponse.json"); - Server.Given(CreatePostRequestBuilder(path)) - .RespondWith( + Server.Given(CreatePostRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var databasesQueryParams = new DatabasesQueryParameters + var databasesQueryParams = new DatabasesQueryParameters + { + Filter = new CompoundFilter { - Filter = new CompoundFilter + Or = new List { - Or = new List { - new CheckboxFilter( - "In stock", - true - ), - new NumberFilter( - "Cost of next trip", - greaterThanOrEqualTo: 2 - ) - }, - }, - Sorts = new List + new CheckboxFilter( + "In stock", + true + ), + new NumberFilter( + "Cost of next trip", + greaterThanOrEqualTo: 2 + ) + } + }, + Sorts = new List + { + new() { - new Sort - { - Property = "Last ordered", - Direction = Direction.Ascending - } + Property = "Last ordered", + Direction = Direction.Ascending } - }; + } + }; - var pagesPaginatedList = await _client.QueryAsync(databaseId, databasesQueryParams); + var pagesPaginatedList = await _client.QueryAsync(databaseId, databasesQueryParams); - pagesPaginatedList.Results.Should().ContainSingle(); + pagesPaginatedList.Results.Should().ContainSingle(); - foreach (var page in pagesPaginatedList.Results) - { - page.Parent.Should().BeAssignableTo(); - page.Object.Should().Be(ObjectType.Page); - } + foreach (var iWikiDatabase in pagesPaginatedList.Results) + { + var page = (Page)iWikiDatabase; + page.Parent.Should().BeAssignableTo(); + page.Object.Should().Be(ObjectType.Page); } + } - [Fact] - public async Task RetrieveDatabaseAsync() - { - var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; - var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/DatabaseRetrieveResponse.json"); + [Fact] + public async Task RetrieveDatabaseAsync() + { + var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; + var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); + var jsonData = await File.ReadAllTextAsync("data/databases/DatabaseRetrieveResponse.json"); - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var database = await _client.RetrieveAsync(databaseId); + var database = await _client.RetrieveAsync(databaseId); - database.Parent.Type.Should().Be(ParentType.PageId); - database.Parent.Should().BeOfType(); - ((PageParent)database.Parent).PageId.Should().Be("649089db-8984-4051-98fb-a03593b852d8"); - foreach (var property in database.Properties) - { - property.Key.Should().Be(property.Value.Name); - } + database.Parent.Type.Should().Be(ParentType.PageId); + database.Parent.Should().BeOfType(); + ((PageParent)database.Parent).PageId.Should().Be("649089db-8984-4051-98fb-a03593b852d8"); - HelperAsserts.IPageIconAsserts(database.Icon); - HelperAsserts.FileObjectAsserts(database.Cover); + foreach (var property in database.Properties) + { + property.Key.Should().Be(property.Value.Name); } - [Fact] - public async Task DatabasePropertyObjectContainNameProperty() - { - var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; - var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/DatabasePropertyObjectContainNameProperty.json"); + HelperAsserts.IPageIconAsserts(database.Icon); + HelperAsserts.FileObjectAsserts(database.Cover); + } - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( + [Fact] + public async Task DatabasePropertyObjectContainNameProperty() + { + var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; + var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); + var jsonData = await File.ReadAllTextAsync("data/databases/DatabasePropertyObjectContainNameProperty.json"); + + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var database = await _client.RetrieveAsync(databaseId); + var database = await _client.RetrieveAsync(databaseId); - foreach (var property in database.Properties) - { - property.Key.Should().Be(property.Value.Name); - } + foreach (var property in database.Properties) + { + property.Key.Should().Be(property.Value.Name); } + } - [Fact] - public async Task DatabasePropertyObjectContainRelationProperty() - { - var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; - var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/DatabasePropertyObjectContainRelation.json"); + [Fact] + public async Task DatabasePropertyObjectContainRelationProperty() + { + var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; + var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); + var jsonData = await File.ReadAllTextAsync("data/databases/DatabasePropertyObjectContainRelation.json"); - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var database = await _client.RetrieveAsync(databaseId); + var database = await _client.RetrieveAsync(databaseId); - database.Properties.Should().ContainKey("Property").WhichValue.Should().BeEquivalentTo( - new RelationProperty() + database.Properties.Should().ContainKey("Property").WhichValue.Should().BeEquivalentTo( + new RelationProperty + { + Id = "zDGa", + Name = "Property", + Relation = new DualPropertyRelation + { + DatabaseId = "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", + DualProperty = new DualPropertyRelation.Data { - Id = "zDGa", - Name = "Property", - Relation = new Relation() - { - DatabaseId = "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - SyncedPropertyName = "Related to sample table (Property)", - SyncedPropertyId = "VQ}{" - } - }); - } + SyncedPropertyName = "Related to sample table (Property)", + SyncedPropertyId = "VQ}{" + } + } + }); + } - [Fact] - public async Task DatabasePropertyObjectContainParentProperty() - { - var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; - var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/DatabasePropertyObjectContainParentProperty.json"); + [Fact] + public async Task DatabasePropertyObjectContainParentProperty() + { + var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; + var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); + var jsonData = await File.ReadAllTextAsync("data/databases/DatabasePropertyObjectContainParentProperty.json"); - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var database = await _client.RetrieveAsync(databaseId); + var database = await _client.RetrieveAsync(databaseId); - database.Parent.Type.Should().Be(ParentType.PageId); - database.Parent.Should().BeOfType(); - ((PageParent)database.Parent).PageId.Should().Be("649089db-8984-4051-98fb-a03593b852d8"); - } + database.Parent.Type.Should().Be(ParentType.PageId); + database.Parent.Should().BeOfType(); + ((PageParent)database.Parent).PageId.Should().Be("649089db-8984-4051-98fb-a03593b852d8"); + } - [Fact] - public async Task CreateDatabaseAsync() - { - var pageId = "533578e3-edf1-4c0a-91a9-da6b09bac3ee"; - var path = ApiEndpoints.DatabasesApiUrls.Create; - var jsonData = await File.ReadAllTextAsync("data/databases/CreateDatabaseResponse.json"); + [Fact] + public async Task CreateDatabaseAsync() + { + var pageId = "533578e3-edf1-4c0a-91a9-da6b09bac3ee"; + var path = ApiEndpoints.DatabasesApiUrls.Create; + var jsonData = await File.ReadAllTextAsync("data/databases/CreateDatabaseResponse.json"); - Server.Given(CreatePostRequestBuilder(path)) - .RespondWith( + Server.Given(CreatePostRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var createDatabaseParameters = new DatabasesCreateParameters(); - - createDatabaseParameters.Parent = new ParentPageInput - { - PageId = pageId - }; - - createDatabaseParameters.Title = new List + var createDatabaseParameters = new DatabasesCreateParameters + { + Parent = new ParentPageInput { PageId = pageId }, + Title = new List { new RichTextTextInput { @@ -201,29 +204,30 @@ public async Task CreateDatabaseAsync() Link = null } } - }; - - createDatabaseParameters.Properties = new Dictionary + }, + Properties = new Dictionary { { "Name", new TitlePropertySchema { Title = new Dictionary() } }, { "Price", new NumberPropertySchema { Number = new Number { Format = "dollar" } } }, - { "Food group", new SelectPropertySchema + { + "Food group", + new SelectPropertySchema { Select = new OptionWrapper { Options = new List { - new SelectOptionSchema + new() { Color = Color.Green, Name = "🥦Vegetable" }, - new SelectOptionSchema + new() { Color = Color.Red, Name = "🍎Fruit" }, - new SelectOptionSchema + new() { Color = Color.Yellow, Name = "💪Protein" @@ -232,87 +236,91 @@ public async Task CreateDatabaseAsync() } } }, - { "Last ordered", new DatePropertySchema{ Date = new Dictionary() } } - }; + { "Last ordered", new DatePropertySchema { Date = new Dictionary() } } + } + }; - var database = await _client.CreateAsync(createDatabaseParameters); + var database = await _client.CreateAsync(createDatabaseParameters); - database.Parent.Type.Should().Be(ParentType.PageId); - database.Parent.Should().BeOfType(); - ((PageParent)database.Parent).PageId.Should().Be(pageId); + database.Parent.Type.Should().Be(ParentType.PageId); + database.Parent.Should().BeOfType(); + ((PageParent)database.Parent).PageId.Should().Be(pageId); - database.Properties.Should().HaveCount(4); + database.Properties.Should().HaveCount(4); - var selectOptions = (SelectProperty)database.Properties["Food group"]; - selectOptions.Name.Should().Be("Food group"); - selectOptions.Select.Options.Should().SatisfyRespectively( - option => - { - option.Name.Should().Be("🥦Vegetable"); - option.Color.Should().Be(Color.Green); - }, - option => - { - option.Name.Should().Be("🍎Fruit"); - option.Color.Should().Be(Color.Red); - }, - option => - { - option.Name.Should().Be("💪Protein"); - option.Color.Should().Be(Color.Yellow); - } - ); - } + var selectOptions = (SelectProperty)database.Properties["Food group"]; + selectOptions.Name.Should().Be("Food group"); - [Fact] - public async Task UpdateDatabaseAsync() - { - var databaseId = "1e9eee34-9c5c-4fe6-a4e1-8244eb141ed8"; - var path = ApiEndpoints.DatabasesApiUrls.Update(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/UpdateDatabaseResponse.json"); + selectOptions.Select.Options.Should().SatisfyRespectively( + option => + { + option.Name.Should().Be("🥦Vegetable"); + option.Color.Should().Be(Color.Green); + }, + option => + { + option.Name.Should().Be("🍎Fruit"); + option.Color.Should().Be(Color.Red); + }, + option => + { + option.Name.Should().Be("💪Protein"); + option.Color.Should().Be(Color.Yellow); + } + ); + } - Server.Given(CreatePatchRequestBuilder(path)) - .RespondWith( + [Fact] + public async Task UpdateDatabaseAsync() + { + var databaseId = "1e9eee34-9c5c-4fe6-a4e1-8244eb141ed8"; + var path = ApiEndpoints.DatabasesApiUrls.Update(databaseId); + var jsonData = await File.ReadAllTextAsync("data/databases/UpdateDatabaseResponse.json"); + + Server.Given(CreatePatchRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var updateDatabaseParameters = new DatabasesUpdateParameters(); - - updateDatabaseParameters.Title = new List - { - new RichTextTextInput + var updateDatabaseParameters = new DatabasesUpdateParameters + { + Title = + new List { - Text = new Text + new RichTextTextInput { - Content = "Grocery List New", - Link = null + Text = new Text + { + Content = "Grocery List New", + Link = null + } } - } - }; - - updateDatabaseParameters.Properties = new Dictionary + }, + Properties = new Dictionary { { "Name", new TitleUpdatePropertySchema { Title = new Dictionary() } }, { "Price", new NumberUpdatePropertySchema { Number = new Number { Format = "yen" } } }, - { "Food group", new SelectUpdatePropertySchema + { + "Food group", + new SelectUpdatePropertySchema { Select = new OptionWrapper { Options = new List { - new SelectOption + new() { Color = Color.Green, Name = "🥦Vegetables" }, - new SelectOption + new() { Color = Color.Red, Name = "🍎Fruit" }, - new SelectOption + new() { Color = Color.Yellow, Name = "💪Protein" @@ -321,72 +329,73 @@ public async Task UpdateDatabaseAsync() } } }, - { "Last ordered", new DateUpdatePropertySchema{ Date = new Dictionary() } } - }; + { "Last ordered", new DateUpdatePropertySchema { Date = new Dictionary() } } + } + }; - var database = await _client.UpdateAsync(databaseId, updateDatabaseParameters); + var database = await _client.UpdateAsync(databaseId, updateDatabaseParameters); - database.Parent.Type.Should().Be(ParentType.PageId); - database.Parent.Should().BeOfType(); - ((PageParent)database.Parent).PageId.Should().Be("533578e3-edf1-4c0a-91a9-da6b09bac3ee"); + database.Parent.Type.Should().Be(ParentType.PageId); + database.Parent.Should().BeOfType(); + ((PageParent)database.Parent).PageId.Should().Be("533578e3-edf1-4c0a-91a9-da6b09bac3ee"); - database.Properties.Should().HaveCount(4); + database.Properties.Should().HaveCount(4); - database.Title.Should().ContainSingle(); - database.Title.Should().SatisfyRespectively( - title => - { - title.Should().BeAssignableTo(); - ((RichTextText)title).Text.Content.Should().Be("Grocery List New"); - } - ); + database.Title.Should().ContainSingle(); - var selectOptions = (SelectProperty)database.Properties["Food group"]; - selectOptions.Name.Should().Be("Food group"); - selectOptions.Select.Options.Should().SatisfyRespectively( - option => - { - option.Name.Should().Be("🥦Vegetables"); - option.Color.Should().Be(Color.Green); - }, - option => - { - option.Name.Should().Be("🍎Fruit"); - option.Color.Should().Be(Color.Red); - }, - option => - { - option.Name.Should().Be("💪Protein"); - option.Color.Should().Be(Color.Yellow); - } - ); + database.Title.Should().SatisfyRespectively( + title => + { + title.Should().BeAssignableTo(); + ((RichTextText)title).Text.Content.Should().Be("Grocery List New"); + } + ); - var price = (NumberProperty)database.Properties["Price"]; - price.Number.Format.Should().Be("yen"); - } + var selectOptions = (SelectProperty)database.Properties["Food group"]; + selectOptions.Name.Should().Be("Food group"); - [Fact] - public async Task FormulaPropertyCanBeSetWhenCreatingDatabase() - { - var pageId = "98ad959b-2b6a-4774-80ee-00246fb0ea9b"; - var path = ApiEndpoints.DatabasesApiUrls.Create; - var jsonData = await File.ReadAllTextAsync("data/databases/FormulaPropertyCanBeSetWhenCreatingDatabaseResponse.json"); + selectOptions.Select.Options.Should().SatisfyRespectively( + option => + { + option.Name.Should().Be("🥦Vegetables"); + option.Color.Should().Be(Color.Green); + }, + option => + { + option.Name.Should().Be("🍎Fruit"); + option.Color.Should().Be(Color.Red); + }, + option => + { + option.Name.Should().Be("💪Protein"); + option.Color.Should().Be(Color.Yellow); + } + ); - Server.Given(CreatePostRequestBuilder(path)) - .RespondWith( + var price = (NumberProperty)database.Properties["Price"]; + price.Number.Format.Should().Be("yen"); + } + + [Fact] + public async Task FormulaPropertyCanBeSetWhenCreatingDatabase() + { + var pageId = "98ad959b-2b6a-4774-80ee-00246fb0ea9b"; + var path = ApiEndpoints.DatabasesApiUrls.Create; + + var jsonData + = await File.ReadAllTextAsync("data/databases/FormulaPropertyCanBeSetWhenCreatingDatabaseResponse.json"); + + Server.Given(CreatePostRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var createDatabaseParameters = new DatabasesCreateParameters(); - - createDatabaseParameters.Parent = new ParentPageInput - { - PageId = pageId - }; - - createDatabaseParameters.Title = new List + var createDatabaseParameters = new DatabasesCreateParameters + { + Parent = new ParentPageInput { PageId = pageId }, + Title = new List { new RichTextTextInput { @@ -396,91 +405,117 @@ public async Task FormulaPropertyCanBeSetWhenCreatingDatabase() Link = null } } - }; - - createDatabaseParameters.Properties = new Dictionary + }, + Properties = new Dictionary { - { "Cost of next trip", new FormulaPropertySchema { Formula = new Formula { Expression = "if(prop(\"In stock\"), 0, prop(\"Price\"))" } } }, + { + "Cost of next trip", + new FormulaPropertySchema + { + Formula = new Formula { Expression = "if(prop(\"In stock\"), 0, prop(\"Price\"))" } + } + }, { "Price", new NumberPropertySchema { Number = new Number { Format = "dollar" } } } - }; + } + }; - var database = await _client.CreateAsync(createDatabaseParameters); + var database = await _client.CreateAsync(createDatabaseParameters); - database.Parent.Type.Should().Be(ParentType.PageId); - database.Parent.Should().BeOfType(); - ((PageParent)database.Parent).PageId.Should().Be(pageId); + database.Parent.Type.Should().Be(ParentType.PageId); + database.Parent.Should().BeOfType(); + ((PageParent)database.Parent).PageId.Should().Be(pageId); - database.Properties.Should().HaveCount(2); + database.Properties.Should().HaveCount(2); - var formulaProperty = (FormulaProperty)database.Properties["Cost of next trip"]; - formulaProperty.Formula.Expression.Should().Be("if(prop(\"In stock\"), 0, prop(\"Price\"))"); - } + var formulaProperty = (FormulaProperty)database.Properties["Cost of next trip"]; + formulaProperty.Formula.Expression.Should().Be("if(prop(\"In stock\"), 0, prop(\"Price\"))"); + } - [Fact] - public async Task Fix123_QueryAsync_DateFormulaValue_Returns_Null() - { - var databaseId = "f86f2262-0751-40f2-8f63-e3f7a3c39fcb"; - var path = ApiEndpoints.DatabasesApiUrls.Query(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json"); + [Fact] + public async Task Fix123_QueryAsync_DateFormulaValue_Returns_Null() + { + var databaseId = "f86f2262-0751-40f2-8f63-e3f7a3c39fcb"; + var path = ApiEndpoints.DatabasesApiUrls.Query(databaseId); - Server.Given(CreatePostRequestBuilder(path)) - .RespondWith( + var jsonData + = await File.ReadAllTextAsync("data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json"); + + Server.Given(CreatePostRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var databasesQueryParams = new DatabasesQueryParameters + var databasesQueryParams = new DatabasesQueryParameters + { + Filter = new CompoundFilter { - Filter = new CompoundFilter + Or = new List { - Or = new List { - new CheckboxFilter( - "In stock", - true - ), - new NumberFilter( - "Cost of next trip", - greaterThanOrEqualTo: 2 - ) - }, - }, - Sorts = new List + new CheckboxFilter( + "In stock", + true + ), + new NumberFilter( + "Cost of next trip", + greaterThanOrEqualTo: 2 + ) + } + }, + Sorts = new List + { + new() { - new Sort - { - Property = "Last ordered", - Direction = Direction.Ascending - } + Property = "Last ordered", + Direction = Direction.Ascending } - }; + } + }; - var pagesPaginatedList = await _client.QueryAsync(databaseId, databasesQueryParams); + var pagesPaginatedList = await _client.QueryAsync(databaseId, databasesQueryParams); - pagesPaginatedList.Results.Should().ContainSingle(); + pagesPaginatedList.Results.Should().ContainSingle(); - foreach (var page in pagesPaginatedList.Results) - { - page.Parent.Should().BeAssignableTo(); - page.Object.Should().Be(ObjectType.Page); + foreach (var iWikiDatabase in pagesPaginatedList.Results) + { + var page = (Page)iWikiDatabase; + page.Parent.Should().BeAssignableTo(); + page.Object.Should().Be(ObjectType.Page); - Server.Given(CreateGetRequestBuilder(ApiEndpoints.PagesApiUrls.RetrievePropertyItem(page.Id, page.Properties["FormulaProp"].Id))) + Server.Given(CreateGetRequestBuilder( + ApiEndpoints.PagesApiUrls.RetrievePropertyItem(page.Id, page.Properties["FormulaProp"].Id))) .RespondWith( Response.Create() - .WithStatusCode(200) - .WithBody("{\"object\":\"property_item\",\"id\":\"JwY^\",\"type\":\"formula\",\"formula\":{\"type\":\"date\",\"date\":{\"start\":\"2021-06-28\",\"end\":null}}}") + .WithStatusCode(200) + .WithBody( + "{\"object\":\"property_item\",\"id\":\"JwY^\",\"type\":\"formula\",\"formula\":{\"type\":\"date\",\"date\":{\"start\":\"2021-06-28\",\"end\":null}}}") ); - var formulaPropertyValue = (FormulaPropertyItem)await _pagesClient.RetrievePagePropertyItem(new RetrievePropertyItemParameters + var formulaPropertyValue = (FormulaPropertyItem)await _pagesClient.RetrievePagePropertyItemAsync( + new RetrievePropertyItemParameters { PageId = page.Id, PropertyId = page.Properties["FormulaProp"].Id }); - //var formulaPropertyValue = (FormulaPropertyValue)page.Properties["FormulaProp"]; - formulaPropertyValue.Formula.Date.Start.Should().Be(DateTime.Parse("2021-06-28")); - formulaPropertyValue.Formula.Date.End.Should().BeNull(); - } + //var formulaPropertyValue = (FormulaPropertyValue)page.Properties["FormulaProp"]; + formulaPropertyValue.Formula.Date.Start.Should().Be(DateTimeOffset.Parse("2021-06-28", null, System.Globalization.DateTimeStyles.AssumeUniversal).UtcDateTime); + 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); + } } 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); + } +} diff --git a/Test/Notion.UnitTests/FilterTests.cs b/Test/Notion.UnitTests/FilterTests.cs index 5b4650a5..39b90229 100644 --- a/Test/Notion.UnitTests/FilterTests.cs +++ b/Test/Notion.UnitTests/FilterTests.cs @@ -4,131 +4,146 @@ using Notion.Client; using Xunit; -namespace Notion.UnitTests +namespace Notion.UnitTests; + +public class FilterTests { - public class SerializerSettingsSource : RestClient + private readonly SerializerSettingsSource _settingsSource = new(new ClientOptions()); + + private string SerializeFilter(Filter filter) { - public SerializerSettingsSource(ClientOptions options) : base(options) - { + return JsonConvert.SerializeObject(filter, _settingsSource.GetSerializerSettings()); + } - } + [Fact] + public void CompoundFilterTest() + { + var selectFilter = new SelectFilter("A select", "Option"); + var relationFilter = new RelationFilter("Link", "subtask#1"); + var dateFilter = new DateFilter("Due", pastMonth: new Dictionary()); - public JsonSerializerSettings GetSerializerSettings() + var filterGroup = new List { - return defaultSerializerSettings; - } + relationFilter, + selectFilter + }; + + var complexFiler = new CompoundFilter( + and: new List + { + dateFilter, + new CompoundFilter(filterGroup) + } + ); + + Assert.Equal( + "{\"and\":[{\"date\":{\"past_month\":{}},\"property\":\"Due\"}," + + "{\"or\":[{\"relation\":{\"contains\":\"subtask#1\"},\"property\":\"Link\"}," + + "{\"select\":{\"equals\":\"Option\"},\"property\":\"A select\"}]}]}", + SerializeFilter(complexFiler) + ); + } + [Fact] + public void CheckboxFilterTest() + { + var filter = new CheckboxFilter("Property name", false); + + Assert.Equal( + "{\"checkbox\":{\"equals\":false},\"property\":\"Property name\"}", + SerializeFilter(filter) + ); } - public class FilterTests + + [Fact] + public void DateFilterTest() { - private readonly SerializerSettingsSource _settingsSource = new SerializerSettingsSource(new ClientOptions()); + var filter = new DateFilter("When", onOrAfter: new DateTime(2042, 11, 29)); - private string SerializeFilter(Filter filter) - { - return JsonConvert.SerializeObject(filter, _settingsSource.GetSerializerSettings()); - } + Assert.Equal( + "{\"date\":{\"on_or_after\":\"2042-11-29T00:00:00\"},\"property\":\"When\"}", + SerializeFilter(filter) + ); + } - [Fact] - public void CompoundFilterTest() - { - var selectFilter = new SelectFilter("A select", equal: "Option"); - var relationFilter = new RelationFilter("Link", contains: "subtask#1"); - var dateFilter = new DateFilter("Due", pastMonth: new Dictionary()); - - var filterGroup = new List { relationFilter, selectFilter }; - var complexFiler = new CompoundFilter( - and: new List { dateFilter, new CompoundFilter(or: filterGroup) } - ); - - Assert.Equal( - "{\"and\":[{\"date\":{\"past_month\":{}},\"property\":\"Due\"}," - + "{\"or\":[{\"relation\":{\"contains\":\"subtask#1\"},\"property\":\"Link\"}," + - "{\"select\":{\"equals\":\"Option\"},\"property\":\"A select\"}]}]}", - SerializeFilter(complexFiler) - ); - } + [Fact] + public void FilesFilterTest() + { + var filter = new FilesFilter("Attachments", isNotEmpty: false); - [Fact] - public void CheckboxFilterTest() - { - var filter = new CheckboxFilter("Property name", equal: false); - Assert.Equal( - "{\"checkbox\":{\"equals\":false},\"property\":\"Property name\"}", - SerializeFilter(filter) - ); - } + Assert.Equal( + "{\"files\":{\"is_not_empty\":false},\"property\":\"Attachments\"}", + SerializeFilter(filter) + ); + } - [Fact] - public void DateFilterTest() - { - var filter = new DateFilter("When", onOrAfter: new DateTime(2042, 11, 29)); - Assert.Equal( - "{\"date\":{\"on_or_after\":\"2042-11-29T00:00:00\"},\"property\":\"When\"}", - SerializeFilter(filter) - ); - } + [Fact] + public void FormulaFilterTest() + { + var filter = new FormulaFilter( + "Some", + number: new NumberFilter.Condition(isEmpty: true) + ); + + Assert.Equal( + "{\"formula\":{\"number\":{\"is_empty\":true}},\"property\":\"Some\"}", + SerializeFilter(filter) + ); + } - [Fact] - public void FilesFilterTest() - { - var filter = new FilesFilter("Attachments", isNotEmpty: false); - Assert.Equal( - "{\"files\":{\"is_not_empty\":false},\"property\":\"Attachments\"}", - SerializeFilter(filter) - ); - } + [Fact] + public void MultiSelectFilterTest() + { + var filter = new MultiSelectFilter("category 1", doesNotContain: "tag"); - [Fact] - public void FormulaFilterTest() - { - var filter = new FormulaFilter( - "Some", - number: new NumberFilter.Condition(isEmpty: true) - ); - Assert.Equal( - "{\"formula\":{\"number\":{\"is_empty\":true}},\"property\":\"Some\"}", - SerializeFilter(filter) - ); - } + Assert.Equal( + "{\"multi_select\":{\"does_not_contain\":\"tag\"},\"property\":\"category 1\"}", + SerializeFilter(filter) + ); + } - [Fact] - public void MultiSelectFilterTest() - { - var filter = new MultiSelectFilter("category 1", doesNotContain: "tag"); - Assert.Equal( - "{\"multi_select\":{\"does_not_contain\":\"tag\"},\"property\":\"category 1\"}", - SerializeFilter(filter) - ); - } + [Fact(Skip = "Not sure if integer should be serialized as a number with decimals")] + public void NumberFilterTest() + { + var filter = new NumberFilter("sum", greaterThanOrEqualTo: -54); - [Fact(Skip = "Not sure if integer should be serialized as a number with decimals")] - public void NumberFilterTest() - { - var filter = new NumberFilter("sum", greaterThanOrEqualTo: -54); - Assert.Equal( - "{\"number\":{\"greater_than_or_equal_to\":-54.0},\"property\":\"sum\"}", - SerializeFilter(filter) - ); - } + Assert.Equal( + "{\"number\":{\"greater_than_or_equal_to\":-54.0},\"property\":\"sum\"}", + SerializeFilter(filter) + ); + } + + [Fact] + public void PeopleFilter() + { + var filter = new PeopleFilter("assignee PM", doesNotContain: "some-uuid"); + + Assert.Equal( + "{\"people\":{\"does_not_contain\":\"some-uuid\"},\"property\":\"assignee PM\"}", + SerializeFilter(filter) + ); + } + + [Fact] + public void RichTextFilterTest() + { + var filter = new RichTextFilter("Some property", doesNotEqual: "Example text"); + + Assert.Equal( + "{\"rich_text\":{\"does_not_equal\":\"Example text\"},\"property\":\"Some property\"}", + SerializeFilter(filter) + ); + } - [Fact] - public void PeopleFilter() + private class SerializerSettingsSource : RestClient + { + public SerializerSettingsSource(ClientOptions options) : base(options) { - var filter = new PeopleFilter("assignee PM", doesNotContain: "some-uuid"); - Assert.Equal( - "{\"people\":{\"does_not_contain\":\"some-uuid\"},\"property\":\"assignee PM\"}", - SerializeFilter(filter) - ); } - [Fact] - public void RichTextFilterTest() + public JsonSerializerSettings GetSerializerSettings() { - var filter = new RichTextFilter("Some property", doesNotEqual: "Example text"); - Assert.Equal( - "{\"rich_text\":{\"does_not_equal\":\"Example text\"},\"property\":\"Some property\"}", - SerializeFilter(filter) - ); + return DefaultSerializerSettings; } } -} +} diff --git a/Test/Notion.UnitTests/HelperAsserts.cs b/Test/Notion.UnitTests/HelperAsserts.cs index 1b07fbf5..3b1a29ec 100644 --- a/Test/Notion.UnitTests/HelperAsserts.cs +++ b/Test/Notion.UnitTests/HelperAsserts.cs @@ -1,41 +1,44 @@ using FluentAssertions; using Notion.Client; -namespace Notion.UnitTests +namespace Notion.UnitTests; + +public static class HelperAsserts { - public static class HelperAsserts + public static void IPageIconAsserts(IPageIcon icon) { - public static void IPageIconAsserts(IPageIcon icon) + icon.Should().NotBeNull(); + + switch (icon) { - icon.Should().NotBeNull(); - - switch (icon) - { - case EmojiObject emoji: - emoji.Emoji.Should().NotBeNull(); - break; - case FileObject fileObject: - FileObjectAsserts(fileObject); - break; - } + case EmojiObject emoji: + emoji.Emoji.Should().NotBeNull(); + + break; + case FileObject fileObject: + FileObjectAsserts(fileObject); + + break; } + } - public static void FileObjectAsserts(FileObject fileObject) + public static void FileObjectAsserts(FileObject fileObject) + { + fileObject.Should().NotBeNull(); + + switch (fileObject) { - fileObject.Should().NotBeNull(); - - switch (fileObject) - { - case UploadedFile uploadedFile: - uploadedFile.File.Should().NotBeNull(); - uploadedFile.File.Url.Should().NotBeNull(); - uploadedFile.File.ExpiryTime.Should().NotBeSameDateAs(default); - break; - case ExternalFile externalFile: - externalFile.External.Should().NotBeNull(); - externalFile.External.Url.Should().NotBeNull(); - break; - } + case UploadedFile uploadedFile: + uploadedFile.File.Should().NotBeNull(); + uploadedFile.File.Url.Should().NotBeNull(); + uploadedFile.File.ExpiryTime.Should().NotBeSameDateAs(default); + + break; + case ExternalFile externalFile: + externalFile.External.Should().NotBeNull(); + externalFile.External.Url.Should().NotBeNull(); + + break; } } } diff --git a/Test/Notion.UnitTests/Notion.UnitTests.csproj b/Test/Notion.UnitTests/Notion.UnitTests.csproj index 30ff0791..6a33f5c0 100644 --- a/Test/Notion.UnitTests/Notion.UnitTests.csproj +++ b/Test/Notion.UnitTests/Notion.UnitTests.csproj @@ -8,15 +8,15 @@ - - + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -51,7 +51,7 @@ Always - + Always diff --git a/Test/Notion.UnitTests/PagesClientTests.cs b/Test/Notion.UnitTests/PagesClientTests.cs index 13598b0f..4dc75380 100644 --- a/Test/Notion.UnitTests/PagesClientTests.cs +++ b/Test/Notion.UnitTests/PagesClientTests.cs @@ -8,264 +8,262 @@ using WireMock.ResponseBuilders; using Xunit; -namespace Notion.UnitTests +namespace Notion.UnitTests; + +public class PagesClientTests : ApiTestBase { - public class PagesClientTests : ApiTestBase - { - private readonly IPagesClient _client; + private readonly IPagesClient _client; - public PagesClientTests() - { - _client = new PagesClient(new RestClient(ClientOptions)); - } + public PagesClientTests() + { + _client = new PagesClient(new RestClient(ClientOptions)); + } - [Fact] - public async Task RetrieveAsync() - { - var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; - var path = ApiEndpoints.PagesApiUrls.Retrieve(pageId); - var jsonData = await File.ReadAllTextAsync("data/pages/PageObjectShouldHaveUrlPropertyResponse.json"); + [Fact] + public async Task RetrieveAsync() + { + var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; + var path = ApiEndpoints.PagesApiUrls.Retrieve(pageId); + var jsonData = await File.ReadAllTextAsync("data/pages/PageObjectShouldHaveUrlPropertyResponse.json"); - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var page = await _client.RetrieveAsync(pageId); + var page = await _client.RetrieveAsync(pageId); - page.Url.Should().Be("https://www.notion.so/Avocado-251d2b5f268c4de2afe9c71ff92ca95c"); - 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.Url.Should().Be("https://www.notion.so/Avocado-251d2b5f268c4de2afe9c71ff92ca95c"); + page.Id.Should().Be(pageId); + page.Parent.Type.Should().Be(ParentType.DatabaseId); + ((DatabaseParent)page.Parent).DatabaseId.Should().Be("48f8fee9-cd79-4180-bc2f-ec0398253067"); + page.InTrash.Should().BeFalse(); + } - [Fact] - public async Task CreateAsync() - { - var path = ApiEndpoints.PagesApiUrls.Create(); + [Fact] + public async Task CreateAsync() + { + var path = ApiEndpoints.PagesApiUrls.Create(); - var jsonData = await File.ReadAllTextAsync("data/pages/CreatePageResponse.json"); + var jsonData = await File.ReadAllTextAsync("data/pages/CreatePageResponse.json"); - Server.Given(CreatePostRequestBuilder(path)) - .RespondWith( - Response.Create() + Server.Given(CreatePostRequestBuilder(path)) + .RespondWith( + Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var pagesCreateParameters = PagesCreateParametersBuilder.Create(new DatabaseParentInput - { - DatabaseId = "3c357473-a281-49a4-88c0-10d2b245a589" - }).AddProperty("Name", new TitlePropertyValue() - { - Title = new List() + var pagesCreateParameters = PagesCreateParametersBuilder + .Create(new DatabaseParentInput { DatabaseId = "3c357473-a281-49a4-88c0-10d2b245a589" }) + .AddProperty( + "Name", + new TitlePropertyValue { - new RichTextText() - { - Text = new Text - { - Content = "Test" - } - } + Title = new List { new RichTextText { Text = new Text { Content = "Test" } } } } - }).Build(); + ).Build(); - var page = await _client.CreateAsync(pagesCreateParameters); + var page = await _client.CreateAsync(pagesCreateParameters); - page.Id.Should().NotBeNullOrEmpty(); - page.Url.Should().NotBeNullOrEmpty(); - page.Properties.Should().HaveCount(1); - page.Properties.First().Key.Should().Be("Name"); - page.IsArchived.Should().BeFalse(); - page.Parent.Should().NotBeNull(); - ((DatabaseParent)page.Parent).DatabaseId.Should().Be("3c357473-a281-49a4-88c0-10d2b245a589"); - } + page.Id.Should().NotBeNullOrEmpty(); + page.Url.Should().NotBeNullOrEmpty(); + page.Properties.Should().HaveCount(1); + page.Properties.First().Key.Should().Be("Name"); + page.InTrash.Should().BeFalse(); + page.Parent.Should().NotBeNull(); + ((DatabaseParent)page.Parent).DatabaseId.Should().Be("3c357473-a281-49a4-88c0-10d2b245a589"); + } - [Fact] - public async Task UpdatePropertiesAsync() - { - var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; - var propertyId = "{>U;"; - var path = ApiEndpoints.PagesApiUrls.UpdateProperties(pageId); + [Fact] + public async Task UpdatePropertiesAsync() + { + var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; + var propertyId = "{>U;"; + var path = ApiEndpoints.PagesApiUrls.UpdateProperties(pageId); - var jsonData = await File.ReadAllTextAsync("data/pages/UpdatePagePropertiesResponse.json"); + var jsonData = await File.ReadAllTextAsync("data/pages/UpdatePagePropertiesResponse.json"); - Server.Given(CreatePatchRequestBuilder(path)) - .RespondWith( - Response.Create() + Server.Given(CreatePatchRequestBuilder(path)) + .RespondWith( + Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - Server.Given(CreateGetRequestBuilder(ApiEndpoints.PagesApiUrls.RetrievePropertyItem(pageId, propertyId))) - .RespondWith( - Response.Create().WithStatusCode(200).WithBody("{\"object\":\"property_item\",\"id\":\"{>U;\",\"type\":\"checkbox\",\"checkbox\":true}")); + Server.Given(CreateGetRequestBuilder(ApiEndpoints.PagesApiUrls.RetrievePropertyItem(pageId, propertyId))) + .RespondWith( + Response.Create().WithStatusCode(200) + .WithBody( + "{\"object\":\"property_item\",\"id\":\"{>U;\",\"type\":\"checkbox\",\"checkbox\":true}")); - var updatedProperties = new Dictionary() - { - { "In stock", new CheckboxPropertyValue() { Checkbox = true } } - }; + var updatedProperties = new Dictionary + { + { "In stock", new CheckboxPropertyValue { Checkbox = true } } + }; - var page = await _client.UpdatePropertiesAsync(pageId, updatedProperties); + var page = await _client.UpdatePropertiesAsync(pageId, updatedProperties); - page.Id.Should().Be(pageId); - page.Properties.Should().HaveCount(2); - var updatedProperty = page.Properties.First(x => x.Key == "In stock"); + page.Id.Should().Be(pageId); + page.Properties.Should().HaveCount(2); + var updatedProperty = page.Properties.First(x => x.Key == "In stock"); - var checkboxPropertyValue = (CheckboxPropertyItem)await _client.RetrievePagePropertyItem(new RetrievePropertyItemParameters + var checkboxPropertyValue = (CheckboxPropertyItem)await _client.RetrievePagePropertyItemAsync( + new RetrievePropertyItemParameters { PageId = page.Id, PropertyId = updatedProperty.Value.Id }); - checkboxPropertyValue.Checkbox.Should().BeTrue(); - } + checkboxPropertyValue.Checkbox.Should().BeTrue(); + } - [Fact] - public async Task PageObjectShouldHaveUrlProperty() - { - var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; - var path = ApiEndpoints.PagesApiUrls.Retrieve(pageId); - var jsonData = await File.ReadAllTextAsync("data/pages/PageObjectShouldHaveUrlPropertyResponse.json"); + [Fact] + public async Task PageObjectShouldHaveUrlProperty() + { + var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; + var path = ApiEndpoints.PagesApiUrls.Retrieve(pageId); + var jsonData = await File.ReadAllTextAsync("data/pages/PageObjectShouldHaveUrlPropertyResponse.json"); - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - var page = await _client.RetrieveAsync(pageId); + var page = await _client.RetrieveAsync(pageId); - page.Url.Should().Be("https://www.notion.so/Avocado-251d2b5f268c4de2afe9c71ff92ca95c"); - } + page.Url.Should().Be("https://www.notion.so/Avocado-251d2b5f268c4de2afe9c71ff92ca95c"); + } - [Fact] - public async Task UpdatePageAsync() - { - var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; - var propertyId = "{>U;"; - var path = ApiEndpoints.PagesApiUrls.UpdateProperties(pageId); + [Fact] + public async Task UpdatePageAsync() + { + var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; + var propertyId = "{>U;"; + var path = ApiEndpoints.PagesApiUrls.UpdateProperties(pageId); - var jsonData = await File.ReadAllTextAsync("data/pages/UpdatePagePropertiesResponse.json"); + var jsonData = await File.ReadAllTextAsync("data/pages/UpdatePagePropertiesResponse.json"); - Server.Given(CreatePatchRequestBuilder(path)) - .RespondWith( - Response.Create() + Server.Given(CreatePatchRequestBuilder(path)) + .RespondWith( + Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - Server.Given(CreateGetRequestBuilder(ApiEndpoints.PagesApiUrls.RetrievePropertyItem(pageId, propertyId))) - .RespondWith( - Response.Create().WithStatusCode(200).WithBody("{\"object\":\"property_item\",\"id\":\"{>U;\",\"type\":\"checkbox\",\"checkbox\":true}")); + Server.Given(CreateGetRequestBuilder(ApiEndpoints.PagesApiUrls.RetrievePropertyItem(pageId, propertyId))) + .RespondWith( + Response.Create().WithStatusCode(200) + .WithBody( + "{\"object\":\"property_item\",\"id\":\"{>U;\",\"type\":\"checkbox\",\"checkbox\":true}")); - var pagesUpdateParameters = new PagesUpdateParameters + var pagesUpdateParameters = new PagesUpdateParameters + { + Properties = new Dictionary { - Properties = new Dictionary() - { - { "In stock", new CheckboxPropertyValue() { Checkbox = true } } - } - }; + { "In stock", new CheckboxPropertyValue { Checkbox = true } } + } + }; - var page = await _client.UpdateAsync(pageId, pagesUpdateParameters); + var page = await _client.UpdateAsync(pageId, pagesUpdateParameters); - page.Id.Should().Be(pageId); - page.IsArchived.Should().BeFalse(); - page.Properties.Should().HaveCount(2); - var updatedProperty = page.Properties.First(x => x.Key == "In stock"); + page.Id.Should().Be(pageId); + page.InTrash.Should().BeFalse(); + page.Properties.Should().HaveCount(2); + var updatedProperty = page.Properties.First(x => x.Key == "In stock"); - var checkboxPropertyValue = (CheckboxPropertyItem)await _client.RetrievePagePropertyItem(new RetrievePropertyItemParameters + var checkboxPropertyValue = (CheckboxPropertyItem)await _client.RetrievePagePropertyItemAsync( + new RetrievePropertyItemParameters { PageId = page.Id, PropertyId = updatedProperty.Value.Id }); - checkboxPropertyValue.Checkbox.Should().BeTrue(); - } + checkboxPropertyValue.Checkbox.Should().BeTrue(); + } - [Fact] - public async Task ArchivePageAsync() - { - var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; - var propertyId = "{>U;"; + [Fact] + public async Task TrashPageAsync() + { + var pageId = "251d2b5f-268c-4de2-afe9-c71ff92ca95c"; + var propertyId = "{>U;"; - var path = ApiEndpoints.PagesApiUrls.UpdateProperties(pageId); + 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( - Response.Create() + Server.Given(CreatePatchRequestBuilder(path)) + .RespondWith( + Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - Server.Given(CreateGetRequestBuilder(ApiEndpoints.PagesApiUrls.RetrievePropertyItem(pageId, propertyId))) - .RespondWith( - Response.Create().WithStatusCode(200).WithBody("{\"object\":\"property_item\",\"id\":\"{>U;\",\"type\":\"checkbox\",\"checkbox\":true}")); + Server.Given(CreateGetRequestBuilder(ApiEndpoints.PagesApiUrls.RetrievePropertyItem(pageId, propertyId))) + .RespondWith( + Response.Create().WithStatusCode(200) + .WithBody( + "{\"object\":\"property_item\",\"id\":\"{>U;\",\"type\":\"checkbox\",\"checkbox\":true}")); - var pagesUpdateParameters = new PagesUpdateParameters + var pagesUpdateParameters = new PagesUpdateParameters + { + InTrash = true, + Properties = new Dictionary { - Archived = true, - Properties = new Dictionary() - { - { "In stock", new CheckboxPropertyValue() { Checkbox = true } } - } - }; + { "In stock", new CheckboxPropertyValue { Checkbox = true } } + } + }; - var page = await _client.UpdateAsync(pageId, pagesUpdateParameters); + var page = await _client.UpdateAsync(pageId, pagesUpdateParameters); - page.Id.Should().Be(pageId); - page.IsArchived.Should().BeTrue(); - page.Properties.Should().HaveCount(2); - var updatedProperty = page.Properties.First(x => x.Key == "In stock"); + page.Id.Should().Be(pageId); + page.InTrash.Should().BeTrue(); + page.Properties.Should().HaveCount(3); + var updatedProperty = page.Properties.First(x => x.Key == "In stock"); - var checkboxPropertyValue = (CheckboxPropertyItem)await _client.RetrievePagePropertyItem(new RetrievePropertyItemParameters + var checkboxPropertyValue = (CheckboxPropertyItem)await _client.RetrievePagePropertyItemAsync( + new RetrievePropertyItemParameters { PageId = page.Id, PropertyId = updatedProperty.Value.Id }); - checkboxPropertyValue.Checkbox.Should().BeTrue(); - } + checkboxPropertyValue.Checkbox.Should().BeTrue(); + } - [Fact] - public async Task CreateAsync_Throws_ArgumentNullException_When_Parameter_Is_Null() - { - Func act = async () => await _client.CreateAsync(null); + [Fact] + public async Task CreateAsync_Throws_ArgumentNullException_When_Parameter_Is_Null() + { + Func act = async () => await _client.CreateAsync(null); - (await act.Should().ThrowAsync()).And.ParamName.Should().Be("pagesCreateParameters"); - } + (await act.Should().ThrowAsync()).And.ParamName.Should().Be("pagesCreateParameters"); + } - [Fact] - public async Task CreateAsync_Throws_ArgumentNullException_When_Parent_Is_Missing() - { - var pagesCreateParameters = PagesCreateParametersBuilder.Create(null).Build(); + [Fact] + public async Task CreateAsync_Throws_ArgumentNullException_When_Parent_Is_Missing() + { + var pagesCreateParameters = PagesCreateParametersBuilder.Create(null).Build(); - Func act = async () => await _client.CreateAsync(pagesCreateParameters); + Func act = async () => await _client.CreateAsync(pagesCreateParameters); - (await act.Should().ThrowAsync()).And.ParamName.Should().Be("Parent"); - } + (await act.Should().ThrowAsync()).And.ParamName.Should().Be("Parent"); + } - [Fact] - public async Task CreateAsync_Throws_ArgumentNullException_When_Properties_Is_Missing() + [Fact] + public async Task CreateAsync_Throws_ArgumentNullException_When_Properties_Is_Missing() + { + var pagesCreateParameters = new PagesCreateParameters { - var pagesCreateParameters = new PagesCreateParameters - { - Parent = new ParentPageInput() - { - PageId = "3c357473-a281-49a4-88c0-10d2b245a589", - }, - Properties = null - }; + Parent = new ParentPageInput { PageId = "3c357473-a281-49a4-88c0-10d2b245a589" }, + Properties = null + }; - Func act = async () => await _client.CreateAsync(pagesCreateParameters); + Func act = async () => await _client.CreateAsync(pagesCreateParameters); - (await act.Should().ThrowAsync()).And.ParamName.Should().Be("Properties"); - } + (await act.Should().ThrowAsync()).And.ParamName.Should().Be("Properties"); } } diff --git a/Test/Notion.UnitTests/PropertyTests.cs b/Test/Notion.UnitTests/PropertyTests.cs index d09e4a87..55f6d1c1 100644 --- a/Test/Notion.UnitTests/PropertyTests.cs +++ b/Test/Notion.UnitTests/PropertyTests.cs @@ -1,67 +1,69 @@ using System; -using FluentAssertions; using Notion.Client; using Notion.Client.Extensions; using Xunit; -namespace Notion.UnitTests +namespace Notion.UnitTests; + +public class PropertyTests { - public class PropertyTests + [Theory] + [InlineData(typeof(CheckboxProperty), PropertyType.Checkbox)] + [InlineData(typeof(CreatedByProperty), PropertyType.CreatedBy)] + [InlineData(typeof(CreatedTimeProperty), PropertyType.CreatedTime)] + [InlineData(typeof(DateProperty), PropertyType.Date)] + [InlineData(typeof(EmailProperty), PropertyType.Email)] + [InlineData(typeof(FilesProperty), PropertyType.Files)] + [InlineData(typeof(FormulaProperty), PropertyType.Formula)] + [InlineData(typeof(LastEditedByProperty), PropertyType.LastEditedBy)] + [InlineData(typeof(LastEditedTimeProperty), PropertyType.LastEditedTime)] + [InlineData(typeof(NumberProperty), PropertyType.Number)] + [InlineData(typeof(PeopleProperty), PropertyType.People)] + [InlineData(typeof(PhoneNumberProperty), PropertyType.PhoneNumber)] + [InlineData(typeof(RelationProperty), PropertyType.Relation)] + [InlineData(typeof(RichTextProperty), PropertyType.RichText)] + [InlineData(typeof(RollupProperty), PropertyType.Rollup)] + [InlineData(typeof(SelectProperty), PropertyType.Select)] + [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) { - [Theory] - [InlineData(typeof(CheckboxProperty), PropertyType.Checkbox)] - [InlineData(typeof(CreatedByProperty), PropertyType.CreatedBy)] - [InlineData(typeof(CreatedTimeProperty), PropertyType.CreatedTime)] - [InlineData(typeof(DateProperty), PropertyType.Date)] - [InlineData(typeof(EmailProperty), PropertyType.Email)] - [InlineData(typeof(FilesProperty), PropertyType.Files)] - [InlineData(typeof(FormulaProperty), PropertyType.Formula)] - [InlineData(typeof(LastEditedByProperty), PropertyType.LastEditedBy)] - [InlineData(typeof(LastEditedTimeProperty), PropertyType.LastEditedTime)] - [InlineData(typeof(NumberProperty), PropertyType.Number)] - [InlineData(typeof(PeopleProperty), PropertyType.People)] - [InlineData(typeof(PhoneNumberProperty), PropertyType.PhoneNumber)] - [InlineData(typeof(RelationProperty), PropertyType.Relation)] - [InlineData(typeof(RichTextProperty), PropertyType.RichText)] - [InlineData(typeof(RollupProperty), PropertyType.Rollup)] - [InlineData(typeof(SelectProperty), PropertyType.Select)] - [InlineData(typeof(TitleProperty), PropertyType.Title)] - [InlineData(typeof(UrlProperty), PropertyType.Url)] - public void TestPropertyType(Type type, PropertyType expectedPropertyType) - { - var typeInstance = (Property)Activator.CreateInstance(type); + var typeInstance = (Property)Activator.CreateInstance(type); - var actualPropertyType = typeInstance.Type; + var actualPropertyType = typeInstance!.Type; - Assert.Equal(expectedPropertyType, actualPropertyType); - } + Assert.Equal(expectedPropertyType, actualPropertyType); + } - [Theory] - [InlineData(typeof(CheckboxProperty), "checkbox")] - [InlineData(typeof(CreatedByProperty), "created_by")] - [InlineData(typeof(CreatedTimeProperty), "created_time")] - [InlineData(typeof(DateProperty), "date")] - [InlineData(typeof(EmailProperty), "email")] - [InlineData(typeof(FilesProperty), "files")] - [InlineData(typeof(FormulaProperty), "formula")] - [InlineData(typeof(LastEditedByProperty), "last_edited_by")] - [InlineData(typeof(LastEditedTimeProperty), "last_edited_time")] - [InlineData(typeof(NumberProperty), "number")] - [InlineData(typeof(PeopleProperty), "people")] - [InlineData(typeof(PhoneNumberProperty), "phone_number")] - [InlineData(typeof(RelationProperty), "relation")] - [InlineData(typeof(RichTextProperty), "rich_text")] - [InlineData(typeof(RollupProperty), "rollup")] - [InlineData(typeof(SelectProperty), "select")] - [InlineData(typeof(TitleProperty), "title")] - [InlineData(typeof(UrlProperty), "url")] - public void TestPropertyTypeText(Type type, string expectedPropertyType) - { - var typeInstance = (Property)Activator.CreateInstance(type); + [Theory] + [InlineData(typeof(CheckboxProperty), "checkbox")] + [InlineData(typeof(CreatedByProperty), "created_by")] + [InlineData(typeof(CreatedTimeProperty), "created_time")] + [InlineData(typeof(DateProperty), "date")] + [InlineData(typeof(EmailProperty), "email")] + [InlineData(typeof(FilesProperty), "files")] + [InlineData(typeof(FormulaProperty), "formula")] + [InlineData(typeof(LastEditedByProperty), "last_edited_by")] + [InlineData(typeof(LastEditedTimeProperty), "last_edited_time")] + [InlineData(typeof(NumberProperty), "number")] + [InlineData(typeof(PeopleProperty), "people")] + [InlineData(typeof(PhoneNumberProperty), "phone_number")] + [InlineData(typeof(RelationProperty), "relation")] + [InlineData(typeof(RichTextProperty), "rich_text")] + [InlineData(typeof(RollupProperty), "rollup")] + [InlineData(typeof(SelectProperty), "select")] + [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); - var actualPropertyType = typeInstance.Type.GetEnumMemberValue(); + var actualPropertyType = typeInstance!.Type.GetEnumMemberValue(); - Assert.Equal(expectedPropertyType, actualPropertyType); - } + Assert.Equal(expectedPropertyType, actualPropertyType); } } diff --git a/Test/Notion.UnitTests/SearchClientTest.cs b/Test/Notion.UnitTests/SearchClientTest.cs index aa506572..a5a477cb 100644 --- a/Test/Notion.UnitTests/SearchClientTest.cs +++ b/Test/Notion.UnitTests/SearchClientTest.cs @@ -1,71 +1,69 @@ -using System; -using System.IO; +using System.IO; using System.Threading.Tasks; using FluentAssertions; using Notion.Client; using WireMock.ResponseBuilders; using Xunit; -namespace Notion.UnitTests +namespace Notion.UnitTests; + +public class SearchClientTest : ApiTestBase { - public class SearchClientTest : ApiTestBase - { - private readonly SearchClient _client; + private readonly SearchClient _client; - public SearchClientTest() - { - _client = new SearchClient(new RestClient(ClientOptions)); - } + public SearchClientTest() + { + _client = new SearchClient(new RestClient(ClientOptions)); + } - [Fact] - public async Task Search() - { - // Arrange - var path = ApiEndpoints.SearchApiUrls.Search(); - var jsonData = await File.ReadAllTextAsync("data/search/SearchResponse.json"); + [Fact] + public async Task Search() + { + // Arrange + var path = ApiEndpoints.SearchApiUrls.Search(); + var jsonData = await File.ReadAllTextAsync("data/search/SearchResponse.json"); - Server.Given(CreatePostRequestBuilder(path)) - .RespondWith( + Server.Given(CreatePostRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - SearchParameters searchParameters = new SearchParameters() + var searchParameters = new SearchRequest + { + Query = "External tasks", + Sort = new SearchSort { - Query = "External tasks", - Sort = new SearchSort - { - Direction = SearchDirection.Ascending, - Timestamp = "last_edited_time" - } - }; + Direction = SearchDirection.Ascending, + Timestamp = "last_edited_time" + } + }; - // Act - var searchResult = await _client.SearchAsync(searchParameters); + // Act + var searchResult = await _client.SearchAsync(searchParameters); - // Assert - var results = searchResult.Results; + // Assert + var results = searchResult.Results; - results.Should().SatisfyRespectively( - obj => - { - obj.Object.Should().Be(ObjectType.Database); + results.Should().SatisfyRespectively( + obj => + { + obj.Object.Should().Be(ObjectType.Database); - var database = (Database)obj; - database.Properties.Should().HaveCount(2); - }, - obj => - { - obj.Object.Should().Be(ObjectType.Page); + var database = (Database)obj; + database.Properties.Should().HaveCount(2); + }, + obj => + { + obj.Object.Should().Be(ObjectType.Page); - var page = (Page)obj; - page.IsArchived.Should().BeFalse(); - page.Properties.Should().HaveCount(1); - page.Parent.Should().BeAssignableTo(); - ((DatabaseParent)page.Parent).DatabaseId.Should().Be("e6c6f8ff-c70e-4970-91ba-98f03e0d7fc6"); - } - ); - } + var page = (Page)obj; + 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/UserClientTest.cs b/Test/Notion.UnitTests/UserClientTest.cs index d9b27984..6e93decc 100644 --- a/Test/Notion.UnitTests/UserClientTest.cs +++ b/Test/Notion.UnitTests/UserClientTest.cs @@ -5,145 +5,144 @@ using WireMock.ResponseBuilders; using Xunit; -namespace Notion.UnitTests +namespace Notion.UnitTests; + +public class UserClientTest : ApiTestBase { - public class UserClientTest : ApiTestBase + private readonly IUsersClient _client; + + public UserClientTest() + { + _client = new UsersClient(new RestClient(ClientOptions)); + } + + [Fact] + public async Task ListUsers() + { + // Arrange + var jsonData = await File.ReadAllTextAsync("data/users/ListUsersResponse.json"); + var path = ApiEndpoints.UsersApiUrls.List(); + + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( + Response.Create() + .WithStatusCode(200) + .WithBody(jsonData) + ); + + // Act + var users = await _client.ListAsync(); + + // Assert + users.Results.Should().SatisfyRespectively( + user => + { + user.Id.Should().Be("5e37c1b4-630f-4e81-bd6b-296af31e345f"); + user.Name.Should().Be("Vedant Koditkar"); + user.Type.Should().Be("person"); + user.Person.Email.Should().Be("vedkoditkar@gmail.com"); + user.Bot.Should().BeNull(); + }, + user => + { + user.Id.Should().Be("590693f3-797f-4970-98ff-7284106393e5"); + user.Name.Should().Be("Test"); + user.Type.Should().Be("bot"); + user.Person.Should().BeNull(); + } + ); + } + + [Fact] + public async Task RetrieveUser() { - private readonly IUsersClient _client; - - public UserClientTest() - { - _client = new UsersClient(new RestClient(ClientOptions)); - } - - [Fact] - public async Task ListUsers() - { - // Arrange - var jsonData = await File.ReadAllTextAsync("data/users/ListUsersResponse.json"); - var path = ApiEndpoints.UsersApiUrls.List(); - - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( + // Arrange + var jsonData = await File.ReadAllTextAsync("data/users/RetrieveUserResponse.json"); + var userId = "5e37c1b4-630f-4e81-bd6b-296af31e345f"; + var path = ApiEndpoints.UsersApiUrls.Retrieve(userId); + + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - // Act - var users = await _client.ListAsync(); - - // Assert - users.Results.Should().SatisfyRespectively( - user => - { - user.Id.Should().Be("5e37c1b4-630f-4e81-bd6b-296af31e345f"); - user.Name.Should().Be("Vedant Koditkar"); - user.Type.Should().Be("person"); - user.Person.Email.Should().Be("vedkoditkar@gmail.com"); - user.Bot.Should().BeNull(); - }, - user => - { - user.Id.Should().Be("590693f3-797f-4970-98ff-7284106393e5"); - user.Name.Should().Be("Test"); - user.Type.Should().Be("bot"); - user.Person.Should().BeNull(); - } + // Act + var user = await _client.RetrieveAsync(userId); + + // Assert + user.Id.Should().Be("5e37c1b4-630f-4e81-bd6b-296af31e345f"); + user.Name.Should().Be("Vedant Koditkar"); + user.Type.Should().Be("person"); + user.Person.Email.Should().Be("vedkoditkar@gmail.com"); + user.Bot.Should().BeNull(); + } + + [Fact] + public async Task RetrieveTokenUser_WorkspaceInternalToken() + { + // Arrange + var jsonData = await File.ReadAllTextAsync("data/users/MeResponse.json"); + + var path = ApiEndpoints.UsersApiUrls.Me(); + + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( + Response.Create() + .WithStatusCode(200) + .WithBody(jsonData) ); - } - - [Fact] - public async Task RetrieveUser() - { - // Arrange - var jsonData = await File.ReadAllTextAsync("data/users/RetrieveUserResponse.json"); - var userId = "5e37c1b4-630f-4e81-bd6b-296af31e345f"; - var path = ApiEndpoints.UsersApiUrls.Retrieve(userId); - - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( + + // Act + var user = await _client.MeAsync(); + + // Assert + user.Id.Should().Be("590693f3-797f-4970-98ff-7284106393e5"); + user.Name.Should().Be("Test"); + user.AvatarUrl.Should().BeNull(); + user.Type.Should().Be("bot"); + user.Person.Should().BeNull(); + user.Bot.Should().NotBeNull(); + user.Bot.Owner.Should().BeOfType(); + + var owner = (WorkspaceIntegrationOwner)user.Bot.Owner; + owner.Workspace.Should().BeTrue(); + } + + [Fact] + public async Task RetrieveTokenUser_UserLevelToken() + { + // Arrange + var jsonData = await File.ReadAllTextAsync("data/users/MeUserLevelResponse.json"); + + var path = ApiEndpoints.UsersApiUrls.Me(); + + Server.Given(CreateGetRequestBuilder(path)) + .RespondWith( Response.Create() .WithStatusCode(200) .WithBody(jsonData) ); - // Act - var user = await _client.RetrieveAsync(userId); - - // Assert - user.Id.Should().Be("5e37c1b4-630f-4e81-bd6b-296af31e345f"); - user.Name.Should().Be("Vedant Koditkar"); - user.Type.Should().Be("person"); - user.Person.Email.Should().Be("vedkoditkar@gmail.com"); - user.Bot.Should().BeNull(); - } - - [Fact] - public async Task RetrieveTokenUser_WorkspaceInternalToken() - { - // Arrange - var jsonData = await File.ReadAllTextAsync("data/users/MeResponse.json"); - - var path = ApiEndpoints.UsersApiUrls.Me(); - - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - // Act - var user = await _client.MeAsync(); - - // Assert - user.Id.Should().Be("590693f3-797f-4970-98ff-7284106393e5"); - user.Name.Should().Be("Test"); - user.AvatarUrl.Should().BeNull(); - user.Type.Should().Be("bot"); - user.Person.Should().BeNull(); - user.Bot.Should().NotBeNull(); - user.Bot.Owner.Should().BeOfType(); - - var owner = (WorkspaceIntegrationOwner)user.Bot.Owner; - owner.Workspace.Should().BeTrue(); - } - - [Fact] - public async Task RetrieveTokenUser_UserLevelToken() - { - // Arrange - var jsonData = await File.ReadAllTextAsync("data/users/MeUserLevelResponse.json"); - - var path = ApiEndpoints.UsersApiUrls.Me(); - - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - // Act - var user = await _client.MeAsync(); - - // Assert - user.Id.Should().Be("16d84278-ab0e-484c-9bdd-b35da3bd8905"); - user.Name.Should().Be("pied piper"); - user.AvatarUrl.Should().BeNull(); - user.Type.Should().Be("bot"); - user.Person.Should().BeNull(); - user.Bot.Should().NotBeNull(); - user.Bot.Owner.Should().BeOfType(); - - var owner = (UserOwner)user.Bot.Owner; - owner.User.Id.Should().Be("5389a034-eb5c-47b5-8a9e-f79c99ef166c"); - owner.User.Name.Should().Be("christine makenotion"); - owner.User.AvatarUrl.Should().BeNull(); - owner.User.Type.Should().Be("person"); - owner.User.Person.Email.Should().Be("christine@makenotion.com"); - owner.User.Bot.Should().BeNull(); - } + // Act + var user = await _client.MeAsync(); + + // Assert + user.Id.Should().Be("16d84278-ab0e-484c-9bdd-b35da3bd8905"); + user.Name.Should().Be("pied piper"); + user.AvatarUrl.Should().BeNull(); + user.Type.Should().Be("bot"); + user.Person.Should().BeNull(); + user.Bot.Should().NotBeNull(); + user.Bot.Owner.Should().BeOfType(); + + var owner = (UserOwner)user.Bot.Owner; + owner.User.Id.Should().Be("5389a034-eb5c-47b5-8a9e-f79c99ef166c"); + owner.User.Name.Should().Be("christine makenotion"); + owner.User.AvatarUrl.Should().BeNull(); + owner.User.Type.Should().Be("person"); + owner.User.Person.Email.Should().Be("christine@makenotion.com"); + owner.User.Bot.Should().BeNull(); } } 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 649185e7..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": [ @@ -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, + "in_trash": false, + "type": "synced_block", + "synced_block": { + "synced_from": { + "type": "block_id", + "block_id": "d2f7e3f3-c553-410d-a5f9-dfc0c335b169" + } + } } ], "next_cursor": null, 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/DatabasePropertyObjectContainNameProperty.json b/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainNameProperty.json index 5ed09bb1..2951f5f3 100644 --- a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainNameProperty.json +++ b/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainNameProperty.json @@ -71,8 +71,11 @@ "type": "relation", "relation": { "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "synced_property_name": "Related to sample table (Property)", - "synced_property_id": "VQ}{" + "type": "dual_property", + "dual_property": { + "synced_property_name": "Related to sample table (Property)", + "synced_property_id": "VQ}{" + } } }, "Name": { diff --git a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainParentProperty.json b/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainParentProperty.json index 5ed09bb1..2951f5f3 100644 --- a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainParentProperty.json +++ b/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainParentProperty.json @@ -71,8 +71,11 @@ "type": "relation", "relation": { "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "synced_property_name": "Related to sample table (Property)", - "synced_property_id": "VQ}{" + "type": "dual_property", + "dual_property": { + "synced_property_name": "Related to sample table (Property)", + "synced_property_id": "VQ}{" + } } }, "Name": { diff --git a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainRelation.json b/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainRelation.json index 5ed09bb1..2951f5f3 100644 --- a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainRelation.json +++ b/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainRelation.json @@ -71,8 +71,11 @@ "type": "relation", "relation": { "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "synced_property_name": "Related to sample table (Property)", - "synced_property_id": "VQ}{" + "type": "dual_property", + "dual_property": { + "synced_property_name": "Related to sample table (Property)", + "synced_property_id": "VQ}{" + } } }, "Name": { diff --git a/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json b/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json index ef374f2d..9e1acfb0 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", @@ -82,10 +83,19 @@ "type": "relation", "relation": { "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "synced_property_name": "Related to sample table (Property)", - "synced_property_id": "VQ}{" + "type": "dual_property", + "dual_property": { + "synced_property_name": "Related to sample table (Property)", + "synced_property_id": "VQ}{" + } } }, + "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 ea380375..ad0e5497 100644 --- a/Test/Notion.UnitTests/data/databases/DatabasesListResponse.json +++ b/Test/Notion.UnitTests/data/databases/DatabasesListResponse.json @@ -74,10 +74,19 @@ "type": "relation", "relation": { "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "synced_property_name": "Related to sample table (Property)", - "synced_property_id": "VQ}{" + "type": "dual_property", + "dual_property": { + "synced_property_name": "Related to sample table (Property)", + "synced_property_id": "VQ}{" + } } }, + "SimpleButton": { + "id":"_ri%7C", + "name":"SimpleButton", + "type":"button", + "button": {} + }, "Name": { "id": "title", "name": "Name", @@ -188,8 +197,11 @@ "type": "relation", "relation": { "database_id": "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1", - "synced_property_name": "Property", - "synced_property_id": "zDGa" + "type": "dual_property", + "dual_property": { + "synced_property_name": "Property", + "synced_property_id": "zDGa" + } } }, "Column 1": { diff --git a/Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json b/Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json index 27e70234..d291a5b2 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": { @@ -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/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 87% rename from Test/Notion.UnitTests/data/pages/ArchivePageResponse.json rename to Test/Notion.UnitTests/data/pages/TrashPageResponse.json index 2f9af7c6..add1f546 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": { @@ -11,6 +11,11 @@ "type": "checkbox", "checkbox": true }, + "Add Page Button": { + "id":"_ri%7C", + "type":"button", + "button": {} + }, "Name": { "id": "title", "type": "title", 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", diff --git a/docs/README.md b/docs/README.md index d8d29422..54a041d2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,13 +10,6 @@ A simple and easy to use client for the [Notion API](https://developers.notion.c dotnet add package Notion.Net ``` -**Note:** default Notion-Version used by NuGet package versions -| Package version | Notion-Version | -| --- | --- | -| 3.0.0+ | 2022-02-22 | -| 2.0.0+ | 2021-08-16 | -| 1.0.0+ | 2021-05-13 | - ## Usage > Before getting started, you need to [create an integration](https://www.notion.com/my-integrations) and find the token. You can learn more about authorization [here](https://developers.notion.com/docs/authorization). @@ -96,6 +89,9 @@ var complexFiler = new CompoundFilter( - [x] Retrieve block children - [x] Append block children - [x] Delete a block +- [x] Comments + - [x] Retrieve comments + - [x] Create comment - [x] Users - [x] Retrieve a User - [x] List all users 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 diff --git a/package.json b/package.json new file mode 100644 index 00000000..a32bb1db --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "notion-sdk-net", + "version": "1.0.0", + "main": "index.js", + "repository": "git@github.com:notion-dotnet/notion-sdk-net.git", + "author": "Vedant Koditkar", + "license": "MIT", + "scripts": { + "lint": "dotnet jb cleanupcode --include=\"**/**.cs\" .\\Notion.sln" + } +}