├── slf4j2 ├── src │ ├── test │ │ ├── resources │ │ │ └── simplelogger.properties │ │ └── kotlin │ │ │ └── integration_tests │ │ │ └── SimpleJavaTest.java │ └── main │ │ └── kotlin │ │ └── notion │ │ └── api │ │ └── v1 │ │ └── logging │ │ └── Slf4jLogger.kt └── pom.xml ├── core ├── src │ ├── main │ │ └── kotlin │ │ │ └── notion │ │ │ └── api │ │ │ ├── v1 │ │ │ ├── model │ │ │ │ ├── common │ │ │ │ │ ├── Icon.kt │ │ │ │ │ ├── Cover.kt │ │ │ │ │ ├── WithObjectType.kt │ │ │ │ │ ├── Pagination.kt │ │ │ │ │ ├── Equation.kt │ │ │ │ │ ├── ExternalFileDetails.kt │ │ │ │ │ ├── FileDetails.kt │ │ │ │ │ ├── SyncedFrom.kt │ │ │ │ │ ├── LinkToPage.kt │ │ │ │ │ ├── Emoji.kt │ │ │ │ │ ├── RichTextLinkType.kt │ │ │ │ │ ├── FileType.kt │ │ │ │ │ ├── RichTextType.kt │ │ │ │ │ ├── FormulaType.kt │ │ │ │ │ ├── RichTextMentionType.kt │ │ │ │ │ ├── ObjectType.kt │ │ │ │ │ ├── OptionColor.kt │ │ │ │ │ ├── File.kt │ │ │ │ │ ├── BlockColor.kt │ │ │ │ │ ├── RichTextColor.kt │ │ │ │ │ └── PropertyType.kt │ │ │ │ ├── users │ │ │ │ │ ├── Person.kt │ │ │ │ │ ├── Bot.kt │ │ │ │ │ ├── BotOwner.kt │ │ │ │ │ ├── UserType.kt │ │ │ │ │ ├── User.kt │ │ │ │ │ └── Users.kt │ │ │ │ ├── databases │ │ │ │ │ ├── query │ │ │ │ │ │ ├── filter │ │ │ │ │ │ │ ├── QueryTopLevelFilter.kt │ │ │ │ │ │ │ ├── CompoundFilterElement.kt │ │ │ │ │ │ │ ├── condition │ │ │ │ │ │ │ │ ├── FilesFilter.kt │ │ │ │ │ │ │ │ ├── CheckboxFilter.kt │ │ │ │ │ │ │ │ ├── SelectFilter.kt │ │ │ │ │ │ │ │ ├── StatusFilter.kt │ │ │ │ │ │ │ │ ├── PeopleFilter.kt │ │ │ │ │ │ │ │ ├── RelationFilter.kt │ │ │ │ │ │ │ │ ├── MultiSelectFilter.kt │ │ │ │ │ │ │ │ ├── FormulaFilter.kt │ │ │ │ │ │ │ │ ├── NumberFilter.kt │ │ │ │ │ │ │ │ ├── TextFilter.kt │ │ │ │ │ │ │ │ ├── DateFilter.kt │ │ │ │ │ │ │ │ ├── TimestampFilter.kt │ │ │ │ │ │ │ │ └── RollupFilter.kt │ │ │ │ │ │ │ ├── CompoundFilter.kt │ │ │ │ │ │ │ └── PropertyFilter.kt │ │ │ │ │ │ └── sort │ │ │ │ │ │ │ ├── QuerySort.kt │ │ │ │ │ │ │ ├── QuerySortDirection.kt │ │ │ │ │ │ │ └── QuerySortTimestamp.kt │ │ │ │ │ ├── DatabaseParentType.kt │ │ │ │ │ ├── DatabaseParent.kt │ │ │ │ │ ├── Databases.kt │ │ │ │ │ ├── QueryResults.kt │ │ │ │ │ ├── Database.kt │ │ │ │ │ └── DatabasePropertySchema.kt │ │ │ │ ├── error │ │ │ │ │ ├── OAuthError.kt │ │ │ │ │ └── Error.kt │ │ │ │ ├── pages │ │ │ │ │ ├── PageParentType.kt │ │ │ │ │ ├── Page.kt │ │ │ │ │ ├── PageParent.kt │ │ │ │ │ └── PagePropertyItem.kt │ │ │ │ ├── blocks │ │ │ │ │ ├── BlockParentType.kt │ │ │ │ │ ├── Blocks.kt │ │ │ │ │ ├── BlockElementUpdate.kt │ │ │ │ │ ├── BlockParent.kt │ │ │ │ │ ├── UnsupportedBlock.kt │ │ │ │ │ ├── DividerBlock.kt │ │ │ │ │ ├── ColumnBlock.kt │ │ │ │ │ ├── EquationBlock.kt │ │ │ │ │ ├── LinkToPageBlock.kt │ │ │ │ │ ├── BreadcrumbBlock.kt │ │ │ │ │ ├── ColumnListBlock.kt │ │ │ │ │ ├── ChildPageBlock.kt │ │ │ │ │ ├── LinkPreviewBlock.kt │ │ │ │ │ ├── ChildDatabaseBlock.kt │ │ │ │ │ ├── TableBlock.kt │ │ │ │ │ ├── TableOfContentsBlock.kt │ │ │ │ │ ├── EmbedBlock.kt │ │ │ │ │ ├── BookmarkBlock.kt │ │ │ │ │ ├── TableRowBlock.kt │ │ │ │ │ ├── QuoteBlock.kt │ │ │ │ │ ├── SyncedBlock.kt │ │ │ │ │ ├── TemplateBlock.kt │ │ │ │ │ ├── CodeBlock.kt │ │ │ │ │ ├── VideoBlock.kt │ │ │ │ │ ├── AudioBlock.kt │ │ │ │ │ ├── CalloutBlock.kt │ │ │ │ │ ├── ToggleBlock.kt │ │ │ │ │ ├── ParagraphBlock.kt │ │ │ │ │ ├── ToDoBlock.kt │ │ │ │ │ ├── PDFBlock.kt │ │ │ │ │ ├── HeadingTwoBlock.kt │ │ │ │ │ ├── ImageBlock.kt │ │ │ │ │ ├── BulletedListItemBlock.kt │ │ │ │ │ ├── NumberedListItemBlock.kt │ │ │ │ │ ├── BlockType.kt │ │ │ │ │ ├── HeadingOneBlock.kt │ │ │ │ │ ├── HeadingThreeBlock.kt │ │ │ │ │ └── FileBlock.kt │ │ │ │ ├── oauth │ │ │ │ │ └── OAuthTokenResult.kt │ │ │ │ ├── search │ │ │ │ │ ├── PageSearchResultParentType.kt │ │ │ │ │ ├── SearchResults.kt │ │ │ │ │ ├── PageSearchResult.kt │ │ │ │ │ ├── SearchResult.kt │ │ │ │ │ ├── DatabaseSearchResult.kt │ │ │ │ │ └── PageSearchResultParent.kt │ │ │ │ └── comments │ │ │ │ │ ├── Comments.kt │ │ │ │ │ └── Comment.kt │ │ │ ├── request │ │ │ │ ├── users │ │ │ │ │ ├── RetrieveUserRequest.kt │ │ │ │ │ └── ListUsersRequest.kt │ │ │ │ ├── databases │ │ │ │ │ ├── RetrieveDatabaseRequest.kt │ │ │ │ │ ├── ListDatabasesRequest.kt │ │ │ │ │ ├── UpdateDatabaseRequest.kt │ │ │ │ │ ├── QueryDatabaseRequest.kt │ │ │ │ │ └── CreateDatabaseRequest.kt │ │ │ │ ├── blocks │ │ │ │ │ ├── DeleteBlockRequest.kt │ │ │ │ │ ├── RetrieveBlockRequest.kt │ │ │ │ │ ├── AppendBlockChildrenRequest.kt │ │ │ │ │ ├── UpdateBlockRequest.kt │ │ │ │ │ └── RetrieveBlockChildrenRequest.kt │ │ │ │ ├── oauth │ │ │ │ │ └── ExchangeAuthCodeRequest.kt │ │ │ │ ├── comments │ │ │ │ │ ├── CreateCommentRequest.kt │ │ │ │ │ └── RetrieveCommentsRequest.kt │ │ │ │ ├── pages │ │ │ │ │ ├── RetrievePageRequest.kt │ │ │ │ │ ├── UpdatePageRequest.kt │ │ │ │ │ ├── CreatePageRequest.kt │ │ │ │ │ └── RetrievePagePropertyItemRequest.kt │ │ │ │ ├── common │ │ │ │ │ └── Pagination.kt │ │ │ │ └── search │ │ │ │ │ └── SearchRequest.kt │ │ │ ├── http │ │ │ │ ├── NotionHttpResponse.kt │ │ │ │ ├── UserAgent.kt │ │ │ │ ├── NotionHttpClient.kt │ │ │ │ └── HttpUrlConnPatchMethodWorkaround.kt │ │ │ ├── logging │ │ │ │ ├── NotionLogger.kt │ │ │ │ ├── JavaUtilLogger.kt │ │ │ │ └── StdoutLogger.kt │ │ │ ├── exception │ │ │ │ ├── NotionAPIError.kt │ │ │ │ └── NotionOAuthAPIError.kt │ │ │ ├── endpoint │ │ │ │ ├── EndpointsSupport.kt │ │ │ │ ├── SearchSupport.kt │ │ │ │ ├── OAuthSupport.kt │ │ │ │ ├── CommentsSupport.kt │ │ │ │ └── UsersSupport.kt │ │ │ ├── json │ │ │ │ ├── gson │ │ │ │ │ ├── CoverParser.kt │ │ │ │ │ ├── IconParser.kt │ │ │ │ │ ├── SearchResultParser.kt │ │ │ │ │ ├── CompoundFilterElementParser.kt │ │ │ │ │ └── GsonUnknownFieldDetection.kt │ │ │ │ └── NotionJsonSerializer.kt │ │ │ └── NotionClient.kt │ │ │ └── Metadata.kt │ └── test │ │ └── kotlin │ │ ├── tests │ │ ├── java_compatibility │ │ │ ├── DatabasePropertiesTest.java │ │ │ ├── PageParentTest.java │ │ │ ├── NotionClientTest.java │ │ │ ├── BlocksTest.java │ │ │ ├── PagePropertiesTest.java │ │ │ └── RequestsTest.java │ │ ├── logging │ │ │ └── JavaUtilLoggerTest.kt │ │ ├── json │ │ │ └── OAuthTokenResultParserTest.kt │ │ └── model │ │ │ ├── UsersTest.kt │ │ │ └── SearchResultTest.kt │ │ └── integration_tests │ │ ├── SimpleJavaTest.java │ │ ├── SearchTest.kt │ │ └── UsersTest.kt └── pom.xml ├── scripts ├── check_dependency_updates.sh ├── format.sh ├── release.sh └── set_version.sh ├── .github ├── dependabot.yml └── workflows │ └── ci-build.yml ├── slf4j ├── src │ ├── test │ │ ├── resources │ │ │ └── logback.xml │ │ └── kotlin │ │ │ └── integration_tests │ │ │ └── SimpleJavaTest.java │ └── main │ │ └── kotlin │ │ └── notion │ │ └── api │ │ └── v1 │ │ └── logging │ │ └── Slf4jLogger.kt └── pom.xml ├── .gitignore ├── LICENSE ├── okhttp3 ├── pom.xml └── src │ └── test │ └── kotlin │ └── integration_tests │ └── SimpleTest.kt ├── okhttp4 ├── pom.xml └── src │ └── test │ └── kotlin │ └── integration_tests │ └── SimpleTest.kt ├── okhttp5 ├── pom.xml └── src │ └── test │ └── kotlin │ └── integration_tests │ └── SimpleTest.kt └── httpclient └── pom.xml /slf4j2/src/test/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simpleLogger.defaultLogLevel=debug -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/Icon.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | interface Icon 4 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/Cover.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | interface Cover 4 | -------------------------------------------------------------------------------- /scripts/check_dependency_updates.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mvn versions:display-dependency-updates | \ 3 | grep -v checking | \ 4 | grep -v org.jetbrains.kotlin 5 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/users/Person.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.users 2 | 3 | data class Person @JvmOverloads constructor(val email: String) 4 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/WithObjectType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | interface WithObjectType { 4 | val objectType: ObjectType 5 | } 6 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/QueryTopLevelFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter 2 | 3 | interface QueryTopLevelFilter 4 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/CompoundFilterElement.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter 2 | 3 | interface CompoundFilterElement 4 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/users/Bot.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.users 2 | 3 | class Bot @JvmOverloads constructor(val owner: BotOwner, var workspaceName: String) 4 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/Pagination.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | interface Pagination { 4 | val nextCursor: String? 5 | val hasMore: Boolean? 6 | } 7 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/users/RetrieveUserRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.users 2 | 3 | data class RetrieveUserRequest @JvmOverloads constructor(val userId: String) 4 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/Equation.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | data class Equation 4 | @JvmOverloads 5 | constructor( 6 | val expression: String, 7 | ) 8 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/ExternalFileDetails.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | data class ExternalFileDetails @JvmOverloads constructor(var url: String? = null) 4 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/databases/RetrieveDatabaseRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.databases 2 | 3 | data class RetrieveDatabaseRequest @JvmOverloads constructor(val databaseId: String) 4 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/users/BotOwner.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.users 2 | 3 | class BotOwner 4 | @JvmOverloads 5 | constructor( 6 | val type: String, 7 | val workspace: Boolean, 8 | ) 9 | -------------------------------------------------------------------------------- /scripts/format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | project=$1 4 | # ------------------------------------------ 5 | if [[ "project" == "" ]]; then 6 | mvn spotless:apply 7 | else 8 | mvn spotless:apply -pl "$project" 9 | fi 10 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/FileDetails.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | data class FileDetails 4 | @JvmOverloads 5 | constructor( 6 | var url: String? = null, 7 | var expiryTime: String? = null, 8 | ) 9 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/SyncedFrom.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | data class SyncedFrom 4 | @JvmOverloads 5 | constructor( 6 | val type: String? = null, 7 | val blockId: String? = null, 8 | ) : Icon 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/http/NotionHttpResponse.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.http 2 | 3 | open class NotionHttpResponse 4 | @JvmOverloads 5 | constructor( 6 | val status: Int, 7 | val body: String, 8 | val headers: Map>, 9 | ) 10 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/error/OAuthError.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.error 2 | 3 | // This data class does not have setters as developers never manually modify this 4 | data class OAuthError 5 | @JvmOverloads 6 | constructor( 7 | val error: String, 8 | ) 9 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/blocks/DeleteBlockRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.blocks 2 | 3 | // var is intentional here (for the easiness in other JVM languages) 4 | data class DeleteBlockRequest 5 | @JvmOverloads 6 | constructor( 7 | val blockId: String, 8 | ) 9 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/blocks/RetrieveBlockRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.blocks 2 | 3 | // var is intentional here (for the easiness in other JVM languages) 4 | data class RetrieveBlockRequest 5 | @JvmOverloads 6 | constructor( 7 | val blockId: String, 8 | ) 9 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/LinkToPage.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | data class LinkToPage 4 | @JvmOverloads 5 | constructor( 6 | val type: String? = null, 7 | val pageId: String? = null, 8 | val databaseId: String? = null, 9 | ) : Icon 10 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/FilesFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class FilesFilter 4 | @JvmOverloads 5 | constructor( 6 | var isEmpty: Boolean? = null, 7 | var isNotEmpty: Boolean? = null, 8 | ) 9 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/Emoji.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | // https://developers.notion.com/reference/emoji-object 4 | data class Emoji 5 | @JvmOverloads 6 | constructor( 7 | val type: String = "emoji", 8 | var emoji: String? = null, 9 | ) : Icon 10 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/CheckboxFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class CheckboxFilter 4 | @JvmOverloads 5 | constructor( 6 | var equals: Boolean? = null, 7 | var doesNotEqual: Boolean? = null, 8 | ) 9 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/users/ListUsersRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.users 2 | 3 | import notion.api.v1.request.common.Pagination 4 | 5 | data class ListUsersRequest 6 | @JvmOverloads 7 | constructor(override var startCursor: String?, override var pageSize: Int?) : Pagination 8 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/blocks/AppendBlockChildrenRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.blocks 2 | 3 | import notion.api.v1.model.blocks.Block 4 | 5 | data class AppendBlockChildrenRequest 6 | @JvmOverloads 7 | constructor( 8 | @Transient val blockId: String, 9 | val children: List, 10 | ) 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/oauth/ExchangeAuthCodeRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.oauth 2 | 3 | data class ExchangeAuthCodeRequest 4 | @JvmOverloads 5 | constructor( 6 | val grantType: String = "authorization_code", 7 | val code: String, 8 | val state: String, 9 | val redirectUri: String, 10 | ) 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/RichTextLinkType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class RichTextLinkType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("url") Url("url"); 7 | 8 | override fun toString(): String = value 9 | } 10 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/Metadata.kt: -------------------------------------------------------------------------------- 1 | package notion.api 2 | 3 | object Metadata { 4 | const val VERSION: String = "1.11.2-SNAPSHOT" 5 | 6 | fun isLibraryMaintainerMode(): Boolean { 7 | val value = System.getenv("NOTION_SDK_JVM_LIBRARY_MAINTAINER_MODE") 8 | return value != null && ((value == "1") or (value == "true")) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/CompoundFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter 2 | 3 | open class CompoundFilter 4 | @JvmOverloads 5 | constructor( 6 | var or: List? = null, 7 | var and: List? = null, 8 | ) : QueryTopLevelFilter, CompoundFilterElement 9 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/sort/QuerySort.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.sort 2 | 3 | open class QuerySort 4 | @JvmOverloads 5 | constructor( 6 | var property: String? = null, 7 | var timestamp: QuerySortTimestamp? = null, 8 | var direction: QuerySortDirection? = QuerySortDirection.Ascending, 9 | ) 10 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/users/UserType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.users 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class UserType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("person") Person("person"), 7 | @SerializedName("bot") Bot("bot"); 8 | 9 | override fun toString(): String = value 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/SelectFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class SelectFilter 4 | @JvmOverloads 5 | constructor( 6 | var equals: String? = null, 7 | var doesNotEqual: String? = null, 8 | var isEmpty: Boolean? = null, 9 | var isNotEmpty: Boolean? = null, 10 | ) 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/StatusFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class StatusFilter 4 | @JvmOverloads 5 | constructor( 6 | var equals: String? = null, 7 | var doesNotEqual: String? = null, 8 | var isEmpty: Boolean? = null, 9 | var isNotEmpty: Boolean? = null, 10 | ) 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/FileType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class FileType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("external") External("external"), 7 | @SerializedName("file") File("file"); 8 | 9 | override fun toString(): String = value 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/PeopleFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class PeopleFilter 4 | @JvmOverloads 5 | constructor( 6 | var contains: String? = null, 7 | var doesNotContain: String? = null, 8 | var isEmpty: Boolean? = null, 9 | var isNotEmpty: Boolean? = null, 10 | ) 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/RelationFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class RelationFilter 4 | @JvmOverloads 5 | constructor( 6 | var contains: String? = null, 7 | var doesNotContain: String? = null, 8 | var isEmpty: Boolean? = null, 9 | var isNotEmpty: Boolean? = null, 10 | ) 11 | -------------------------------------------------------------------------------- /slf4j/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/MultiSelectFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class MultiSelectFilter 4 | @JvmOverloads 5 | constructor( 6 | var contains: String? = null, 7 | var doesNotContain: String? = null, 8 | var isEmpty: Boolean? = null, 9 | var isNotEmpty: Boolean? = null, 10 | ) 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/DatabaseParentType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class DatabaseParentType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("workspace") Workspace("workspace"), 7 | @SerializedName("page_id") PageId("page_id"); 8 | 9 | override fun toString(): String = value 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/FormulaFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class FormulaFilter 4 | @JvmOverloads 5 | constructor( 6 | var property: String? = null, 7 | var text: TextFilter? = null, 8 | var checkbox: CheckboxFilter? = null, 9 | var number: NumberFilter? = null, 10 | var date: DateFilter? = null, 11 | ) 12 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/comments/CreateCommentRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.comments 2 | 3 | import notion.api.v1.model.pages.PageParent 4 | import notion.api.v1.model.pages.PageProperty 5 | 6 | data class CreateCommentRequest 7 | @JvmOverloads 8 | constructor( 9 | val parent: PageParent? = null, 10 | val discussionId: String? = null, 11 | var richText: List, 12 | ) 13 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/databases/ListDatabasesRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.databases 2 | 3 | import notion.api.v1.request.common.Pagination 4 | 5 | // var is intentional here (for the easiness in other JVM languages) 6 | data class ListDatabasesRequest 7 | @JvmOverloads 8 | constructor( 9 | override var startCursor: String? = null, 10 | override var pageSize: Int? = null, 11 | ) : Pagination 12 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/RichTextType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class RichTextType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("text") Text("text"), 7 | @SerializedName("equation") Equation("equation"), 8 | @SerializedName("mention") Mention("mention"); 9 | 10 | override fun toString(): String = value 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/sort/QuerySortDirection.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.sort 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class QuerySortDirection @JvmOverloads constructor(val value: String) { 6 | @SerializedName("ascending") Ascending("ascending"), 7 | @SerializedName("descending") Descending("descending"); 8 | 9 | override fun toString(): String = value 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/pages/PageParentType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.pages 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class PageParentType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("database_id") DatabaseId("database_id"), 7 | @SerializedName("page_id") PageId("page_id"), 8 | @SerializedName("workspace") Workspace("workspace"); 9 | 10 | override fun toString(): String = value 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/sort/QuerySortTimestamp.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.sort 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class QuerySortTimestamp @JvmOverloads constructor(val value: String) { 6 | @SerializedName("created_time") CreatedTime("created_time"), 7 | @SerializedName("last_edited_time") LastEditedTime("last_edited_time"); 8 | 9 | override fun toString(): String = value 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/databases/UpdateDatabaseRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.databases 2 | 3 | import notion.api.v1.model.databases.DatabaseProperty 4 | import notion.api.v1.model.databases.DatabasePropertySchema 5 | 6 | data class UpdateDatabaseRequest 7 | @JvmOverloads 8 | constructor( 9 | @Transient val id: String, 10 | val title: List? = null, 11 | val properties: Map? = null, 12 | ) 13 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/FormulaType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class FormulaType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("string") StringType("string"), 7 | @SerializedName("number") Number("string"), 8 | @SerializedName("boolean") Boolean("boolean"), 9 | @SerializedName("date") Date("date"); 10 | 11 | override fun toString(): String = value 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/RichTextMentionType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class RichTextMentionType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("user") User("user"), 7 | @SerializedName("page") Page("page"), 8 | @SerializedName("database") Database("database"), 9 | @SerializedName("date") Date("date"); 10 | 11 | override fun toString(): String = value 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/blocks/UpdateBlockRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.blocks 2 | 3 | import notion.api.v1.model.blocks.BlockElementUpdate 4 | import notion.api.v1.model.blocks.BlockType 5 | 6 | data class UpdateBlockRequest 7 | @JvmOverloads 8 | constructor( 9 | val blockId: String, // path param 10 | val elements: Map, // in body 11 | val type: String? = null, // in body 12 | val archived: Boolean? = null, // in body 13 | ) 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .checkstyle 2 | .classpath 3 | .externalToolBuilders/ 4 | .project 5 | .gradle 6 | .settings/ 7 | .idea/ 8 | artifacts/ 9 | src/main/webapp/WEB-INF/classes/ 10 | src/main/webapp/WEB-INF/lib/ 11 | target/ 12 | *.iml 13 | *.ipr 14 | *.iws 15 | build/ 16 | downloaded_files/ 17 | node_modules/ 18 | typescript-types/dist/ 19 | 20 | logs/ 21 | json-logs/raw* 22 | 23 | .DS_Store 24 | 25 | appConfig.json 26 | appConfig_*.json 27 | verificationToken.txt 28 | 29 | *.hprof 30 | .env 31 | .sdkmanrc 32 | .vscode -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/pages/RetrievePageRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.pages 2 | 3 | data class RetrievePageRequest 4 | @JvmOverloads 5 | constructor( 6 | val pageId: String, 7 | val filterProperties: List? = null, 8 | ) { 9 | 10 | fun toQuery(): Map> { 11 | val body = mutableMapOf>() 12 | if (filterProperties != null) { 13 | body["filter_properties"] = filterProperties 14 | } 15 | return body 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/pages/UpdatePageRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.pages 2 | 3 | import notion.api.v1.model.common.Cover 4 | import notion.api.v1.model.common.Icon 5 | import notion.api.v1.model.pages.PageProperty 6 | 7 | data class UpdatePageRequest 8 | @JvmOverloads 9 | constructor( 10 | @Transient val pageId: String, 11 | val properties: Map, 12 | val archived: Boolean? = null, 13 | val icon: Icon? = null, 14 | val cover: Cover? = null, 15 | ) 16 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/BlockParentType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class BlockParentType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("database_id") DatabaseId("database_id"), 7 | @SerializedName("page_id") PageId("page_id"), 8 | @SerializedName("block_id") BlockId("block_id"), 9 | @SerializedName("workspace") Workspace("workspace"); 10 | 11 | override fun toString(): String = value 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/NumberFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class NumberFilter 4 | @JvmOverloads 5 | constructor( 6 | var equals: Int? = null, 7 | var doesNotEqual: Int? = null, 8 | var greaterThan: Int? = null, 9 | var lessThan: Int? = null, 10 | var greaterThanOrEqualTo: Int? = null, 11 | var lessThanOrEqualTo: Int? = null, 12 | var isEmpty: Boolean? = null, 13 | var isNotEmpty: Boolean? = null, 14 | ) 15 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/TextFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class TextFilter 4 | @JvmOverloads 5 | constructor( 6 | var equals: String? = null, 7 | var doesNotEqual: String? = null, 8 | var contains: String? = null, 9 | var doesNotContain: String? = null, 10 | var startsWith: String? = null, 11 | var endsWith: String? = null, 12 | var isEmpty: Boolean? = null, 13 | var isNotEmpty: Boolean? = null, 14 | ) 15 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/oauth/OAuthTokenResult.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.oauth 2 | 3 | import notion.api.v1.model.users.User 4 | 5 | data class OAuthTokenResult 6 | @JvmOverloads 7 | constructor( 8 | val accessToken: String, 9 | val tokenType: String, 10 | val workspaceId: String, 11 | val workspaceName: String?, 12 | val workspaceIcon: String?, 13 | val botId: String, 14 | val owner: Owner, 15 | ) 16 | 17 | data class Owner @JvmOverloads constructor(val type: String, val user: User?) 18 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/common/Pagination.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.common 2 | 3 | interface Pagination { 4 | var startCursor: String? 5 | var pageSize: Int? 6 | 7 | fun buildPaginationParams(): Map> { 8 | val q = mutableMapOf>() 9 | if (startCursor != null) { 10 | q["start_cursor"] = listOf(startCursor!!) 11 | } 12 | if (pageSize != null) { 13 | q["page_size"] = listOf(pageSize.toString()) 14 | } 15 | return q 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/search/PageSearchResultParentType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.search 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class PageSearchResultParentType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("database_id") DatabaseId("database_id"), 7 | @SerializedName("page_id") PageId("page_id"), 8 | @SerializedName("block_id") BlockId("block_id"), 9 | @SerializedName("workspace") Workspace("workspace"); 10 | 11 | override fun toString(): String = value 12 | } 13 | -------------------------------------------------------------------------------- /core/src/test/kotlin/tests/java_compatibility/DatabasePropertiesTest.java: -------------------------------------------------------------------------------- 1 | package tests.java_compatibility; 2 | 3 | import notion.api.v1.model.common.PropertyType; 4 | import notion.api.v1.model.databases.DatabaseProperty; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertNotNull; 8 | 9 | public class DatabasePropertiesTest { 10 | 11 | @Test 12 | public void minimumConstructor() { 13 | DatabaseProperty property = new DatabaseProperty(PropertyType.RichText, "id-value"); 14 | assertNotNull(property); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/error/Error.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.error 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.ObjectType 5 | import notion.api.v1.model.common.WithObjectType 6 | 7 | // This data class does not have setters as developers never manually modify this 8 | data class Error 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Error, 12 | val status: Int, 13 | val code: String, 14 | val message: String, 15 | ) : WithObjectType 16 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/pages/CreatePageRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.pages 2 | 3 | import notion.api.v1.model.blocks.Block 4 | import notion.api.v1.model.common.Cover 5 | import notion.api.v1.model.common.Icon 6 | import notion.api.v1.model.pages.PageParent 7 | import notion.api.v1.model.pages.PageProperty 8 | 9 | data class CreatePageRequest 10 | @JvmOverloads 11 | constructor( 12 | val parent: PageParent, 13 | val properties: Map, 14 | var children: List? = null, 15 | val icon: Icon? = null, 16 | val cover: Cover? = null, 17 | ) 18 | -------------------------------------------------------------------------------- /core/src/test/kotlin/integration_tests/SimpleJavaTest.java: -------------------------------------------------------------------------------- 1 | package integration_tests; 2 | 3 | import notion.api.v1.NotionClient; 4 | import notion.api.v1.model.search.SearchResults; 5 | import org.junit.Assert; 6 | 7 | public class SimpleJavaTest { 8 | 9 | public static void main(String[] args) { 10 | NotionClient client = new NotionClient(System.getenv("NOTION_TOKEN")); 11 | try { 12 | SearchResults results = client.search("Test Database"); 13 | Assert.assertNotNull(results); 14 | } finally { 15 | client.close(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/logging/NotionLogger.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.logging 2 | 3 | interface NotionLogger { 4 | 5 | fun isDebugEnabled(): Boolean 6 | 7 | fun debug(message: String, e: Throwable?) 8 | fun info(message: String, e: Throwable?) 9 | fun warn(message: String, e: Throwable?) 10 | fun error(message: String, e: Throwable?) 11 | 12 | // for other JVM languages 13 | fun debug(message: String) = debug(message, null) 14 | fun info(message: String) = info(message, null) 15 | fun warn(message: String) = warn(message, null) 16 | fun error(message: String) = error(message, null) 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/http/UserAgent.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.http 2 | 3 | import notion.api.Metadata 4 | 5 | object UserAgent { 6 | 7 | @JvmStatic 8 | fun buildUserAgent(): String { 9 | val libraryVersion = Metadata.VERSION 10 | val library = "notion-sdk-jvm/$libraryVersion" 11 | val repo = "https://github.com/seratch/notion-sdk-jvm" 12 | val jvm = 13 | "" + System.getProperty("java.vm.name") + "/" + System.getProperty("java.version") + "" 14 | val os = "" + System.getProperty("os.name") + "/" + System.getProperty("os.version") + "" 15 | return "$library; $repo; $jvm; $os" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/users/User.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.users 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.ObjectType 5 | import notion.api.v1.model.common.WithObjectType 6 | 7 | data class User 8 | @JvmOverloads 9 | constructor( 10 | @SerializedName("object") override val objectType: ObjectType = ObjectType.User, 11 | val id: String, 12 | val type: UserType? = null, 13 | val person: Person? = null, 14 | val name: String? = null, 15 | val avatarUrl: String? = null, 16 | val bot: Bot? = null, 17 | val requestId: String? = null, 18 | ) : WithObjectType 19 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/exception/NotionAPIError.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.exception 2 | 3 | import notion.api.v1.http.NotionHttpResponse 4 | import notion.api.v1.model.error.Error 5 | 6 | class NotionAPIError 7 | @JvmOverloads 8 | constructor( 9 | val error: Error, 10 | val httpResponse: NotionHttpResponse, 11 | override val message: String = buildMessage(error), 12 | override val cause: Throwable? = null 13 | ) : RuntimeException(message, cause) { 14 | 15 | companion object { 16 | private fun buildMessage(error: Error) = 17 | "Got an error from Notion (status: ${error.status}, code: ${error.code}, message: ${error.message})" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/ObjectType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class ObjectType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("block") Block("block"), 7 | @SerializedName("database") Database("database"), 8 | @SerializedName("error") Error("error"), 9 | @SerializedName("page") Page("page"), 10 | @SerializedName("comment") Comment("comment"), 11 | @SerializedName("property_item") PropertyItem("property_item"), 12 | @SerializedName("list") List("list"), 13 | @SerializedName("user") User("user"); 14 | 15 | override fun toString(): String = value 16 | } 17 | -------------------------------------------------------------------------------- /core/src/test/kotlin/tests/logging/JavaUtilLoggerTest.kt: -------------------------------------------------------------------------------- 1 | package tests.logging 2 | 3 | import kotlin.test.assertTrue 4 | import notion.api.v1.logging.JavaUtilLogger 5 | import org.junit.Test 6 | 7 | class JavaUtilLoggerTest { 8 | 9 | @Test 10 | fun test() { 11 | val logger = JavaUtilLogger() 12 | assertTrue(logger.isDebugEnabled()) 13 | 14 | logger.debug("foo") 15 | logger.info("foo") 16 | logger.warn("foo") 17 | logger.error("foo") 18 | 19 | logger.debug("foo", RuntimeException("hi")) 20 | logger.info("foo", RuntimeException("hi")) 21 | logger.warn("foo", RuntimeException("hi")) 22 | logger.error("foo", RuntimeException("hi")) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/test/kotlin/integration_tests/SearchTest.kt: -------------------------------------------------------------------------------- 1 | package integration_tests 2 | 3 | import kotlin.test.assertNotNull 4 | import notion.api.v1.NotionClient 5 | import org.junit.Test 6 | 7 | class SearchTest { 8 | 9 | @Test 10 | fun search() { 11 | NotionClient(token = System.getenv("NOTION_TOKEN")).use { client -> 12 | val searchResult = client.search("Great example data") 13 | assertNotNull(searchResult.results) 14 | } 15 | } 16 | 17 | @Test 18 | fun database() { 19 | NotionClient(token = System.getenv("NOTION_TOKEN")).use { client -> 20 | val searchResult = client.search("Test Database") 21 | assertNotNull(searchResult.results) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/DatabaseParent.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases 2 | 3 | data class DatabaseParent 4 | @JvmOverloads 5 | constructor( 6 | val type: DatabaseParentType? = null, 7 | var pageId: String? = null, // type: page 8 | var workspace: Boolean? = null // type: workspace 9 | ) { 10 | 11 | companion object { 12 | @JvmStatic 13 | fun page(pageId: String): DatabaseParent { 14 | return DatabaseParent(type = DatabaseParentType.PageId, pageId = pageId) 15 | } 16 | 17 | @JvmStatic 18 | fun workspace(): DatabaseParent { 19 | return DatabaseParent(type = DatabaseParentType.Workspace, workspace = true) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/users/Users.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.users 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.ObjectType 5 | import notion.api.v1.model.common.Pagination 6 | import notion.api.v1.model.common.WithObjectType 7 | 8 | data class Users 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.List, 12 | val results: List, 13 | override val nextCursor: String? = null, 14 | override val hasMore: Boolean = false, 15 | val type: String, 16 | var user: Object? = null, 17 | val requestId: String? = null, 18 | ) : WithObjectType, Pagination 19 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/Databases.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.ObjectType 5 | import notion.api.v1.model.common.Pagination 6 | import notion.api.v1.model.common.WithObjectType 7 | 8 | // This data class does not have setters as developers never manually modify this 9 | data class Databases 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.List, 13 | val results: List, 14 | override val nextCursor: String? = null, 15 | override val hasMore: Boolean = false, 16 | ) : WithObjectType, Pagination 17 | -------------------------------------------------------------------------------- /core/src/test/kotlin/tests/java_compatibility/PageParentTest.java: -------------------------------------------------------------------------------- 1 | package tests.java_compatibility; 2 | 3 | import notion.api.v1.model.pages.PageParent; 4 | import notion.api.v1.model.pages.PageParentType; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertNotNull; 8 | 9 | public class PageParentTest { 10 | 11 | @Test 12 | public void creation_noArgConstructor() { 13 | PageParent parent = new PageParent(); 14 | assertNotNull(parent); 15 | } 16 | 17 | @Test 18 | public void creation() { 19 | PageParent parent = new PageParent(PageParentType.DatabaseId); 20 | parent.setDatabaseId("database-id"); 21 | assertNotNull(parent); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/exception/NotionOAuthAPIError.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.exception 2 | 3 | import notion.api.v1.http.NotionHttpResponse 4 | import notion.api.v1.model.error.OAuthError 5 | 6 | class NotionOAuthAPIError 7 | @JvmOverloads 8 | constructor( 9 | val error: OAuthError, 10 | val httpResponse: NotionHttpResponse, 11 | override val message: String = buildMessage(httpResponse, error), 12 | override val cause: Throwable? = null 13 | ) : RuntimeException(message, cause) { 14 | 15 | companion object { 16 | private fun buildMessage(response: NotionHttpResponse, error: OAuthError) = 17 | "Got an error from Notion (status: ${response.status}, error: ${error.error})" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/test/kotlin/integration_tests/UsersTest.kt: -------------------------------------------------------------------------------- 1 | package integration_tests 2 | 3 | import kotlin.test.assertNotNull 4 | import notion.api.v1.NotionClient 5 | import org.junit.Test 6 | 7 | class UsersTest { 8 | 9 | @Test 10 | fun fetchUsers() { 11 | NotionClient(token = System.getenv("NOTION_TOKEN")).use { client -> 12 | val botUser = client.retrieveBotUser() 13 | assertNotNull(botUser) 14 | 15 | val users = client.listUsers() 16 | assertNotNull(users.results) 17 | 18 | val users2 = client.listUsers(pageSize = 1, startCursor = null) 19 | assertNotNull(users2.results) 20 | 21 | val user = client.retrieveUser(users2.results[0].id) 22 | assertNotNull(user) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/databases/QueryDatabaseRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.databases 2 | 3 | import notion.api.v1.model.databases.query.filter.QueryTopLevelFilter 4 | import notion.api.v1.model.databases.query.sort.QuerySort 5 | import notion.api.v1.request.common.Pagination 6 | 7 | // TODO: The document says filter_properties works in this request body, but it didn't work for us 8 | // as of Jan 2023. 9 | data class QueryDatabaseRequest 10 | @JvmOverloads 11 | constructor( 12 | @Transient val databaseId: String, 13 | var filter: QueryTopLevelFilter? = null, 14 | var sorts: List? = null, 15 | override var startCursor: String? = null, 16 | override var pageSize: Int? = null, 17 | ) : Pagination 18 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/OptionColor.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class OptionColor @JvmOverloads constructor(val value: String) { 6 | @SerializedName("default") Default("default"), 7 | @SerializedName("gray") Gray("gray"), 8 | @SerializedName("brown") Brown("brown"), 9 | @SerializedName("orange") Orange("orange"), 10 | @SerializedName("yellow") Yellow("yellow"), 11 | @SerializedName("green") Green("green"), 12 | @SerializedName("blue") Blue("blue"), 13 | @SerializedName("purple") Purple("purple"), 14 | @SerializedName("pink") Pink("pink"), 15 | @SerializedName("red") Red("red"); 16 | 17 | override fun toString(): String = value 18 | } 19 | -------------------------------------------------------------------------------- /slf4j/src/test/kotlin/integration_tests/SimpleJavaTest.java: -------------------------------------------------------------------------------- 1 | package integration_tests; 2 | 3 | import notion.api.v1.NotionClient; 4 | import notion.api.v1.logging.Slf4jLogger; 5 | import notion.api.v1.model.databases.Databases; 6 | import notion.api.v1.model.search.SearchResults; 7 | import org.junit.Assert; 8 | 9 | public class SimpleJavaTest { 10 | 11 | public static void main(String[] args) { 12 | NotionClient client = new NotionClient(System.getenv("NOTION_TOKEN")); 13 | client.setLogger(new Slf4jLogger()); 14 | try { 15 | SearchResults results = client.search("Test Database"); 16 | Assert.assertNotNull(results); 17 | } finally { 18 | client.close(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /slf4j2/src/test/kotlin/integration_tests/SimpleJavaTest.java: -------------------------------------------------------------------------------- 1 | package integration_tests; 2 | 3 | import notion.api.v1.NotionClient; 4 | import notion.api.v1.logging.Slf4jLogger; 5 | import notion.api.v1.model.databases.Databases; 6 | import notion.api.v1.model.search.SearchResults; 7 | import org.junit.Assert; 8 | 9 | public class SimpleJavaTest { 10 | 11 | public static void main(String[] args) { 12 | NotionClient client = new NotionClient(System.getenv("NOTION_TOKEN")); 13 | client.setLogger(new Slf4jLogger()); 14 | try { 15 | SearchResults results = client.search("Test Database"); 16 | Assert.assertNotNull(results); 17 | } finally { 18 | client.close(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/search/SearchResults.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.search 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.ObjectType 5 | import notion.api.v1.model.common.Pagination 6 | import notion.api.v1.model.common.WithObjectType 7 | 8 | data class SearchResults 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.List, 12 | val results: List, 13 | override val nextCursor: String? = null, 14 | override val hasMore: Boolean = false, 15 | val type: String, 16 | val block: Object? = null, 17 | var pageOrDatabase: Object? = null, 18 | val requestId: String? = null, 19 | ) : WithObjectType, Pagination 20 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/pages/RetrievePagePropertyItemRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.pages 2 | 3 | import notion.api.v1.request.common.Pagination 4 | 5 | data class RetrievePagePropertyItemRequest 6 | @JvmOverloads 7 | constructor( 8 | val pageId: String, 9 | val propertyId: String, 10 | override var startCursor: String? = null, 11 | override var pageSize: Int? = null, 12 | ) : Pagination { 13 | 14 | fun toQuery(): Map> { 15 | val body = mutableMapOf>() 16 | if (startCursor != null) { 17 | body["start_cursor"] = listOf(startCursor!!) 18 | } 19 | if (pageSize != null) { 20 | body["page_size"] = listOf(pageSize.toString()) 21 | } 22 | return body 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/search/SearchRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.search 2 | 3 | import notion.api.v1.request.common.Pagination 4 | 5 | open class SearchRequest 6 | @JvmOverloads 7 | constructor( 8 | val query: String, 9 | val filter: SearchFilter? = null, 10 | val sort: SearchSort? = null, 11 | override var startCursor: String? = null, 12 | override var pageSize: Int? = null, 13 | ) : Pagination { 14 | 15 | open class SearchFilter 16 | @JvmOverloads 17 | constructor( 18 | var value: String? = null, 19 | var property: String? = null, 20 | ) 21 | 22 | open class SearchSort 23 | @JvmOverloads 24 | constructor( 25 | var direction: String? = null, 26 | var timestamp: String? = null, 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/databases/CreateDatabaseRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.databases 2 | 3 | import notion.api.v1.model.common.Cover 4 | import notion.api.v1.model.common.Icon 5 | import notion.api.v1.model.databases.DatabaseParent 6 | import notion.api.v1.model.databases.DatabaseProperty 7 | import notion.api.v1.model.databases.DatabasePropertySchema 8 | 9 | data class CreateDatabaseRequest 10 | @JvmOverloads 11 | constructor( 12 | val parent: DatabaseParent, 13 | val title: List, 14 | val properties: Map, 15 | val description: List? = null, 16 | val isInline: Boolean? = null, 17 | val icon: Icon? = null, 18 | val cover: Cover? = null, 19 | ) 20 | -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dir=`dirname $0`/.. 4 | release_version=`sed -n 's/\([^\$]\..*\)<\/version>$/\1/p' < ${dir}/pom.xml` 5 | 6 | export MAVEN_OPTS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/java.awt.font=ALL-UNNAMED" 7 | 8 | if [[ "${release_version}" =~ ^.+-SNAPSHOT$ ]]; then 9 | profile=snapshot-releases 10 | mvn clean \ 11 | deploy \ 12 | -P snapshot-releases \ 13 | -D maven.test.skip=true \ 14 | ${exclusion} 15 | else 16 | profile=production-releases 17 | mvn clean \ 18 | deploy \ 19 | -P production-releases \ 20 | -D maven.test.skip=true \ 21 | ${exclusion} \ 22 | nexus-staging:release 23 | fi 24 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/Blocks.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.ObjectType 5 | import notion.api.v1.model.common.Pagination 6 | import notion.api.v1.model.common.WithObjectType 7 | 8 | // This data class does not have setters as developers never manually modify this 9 | data class Blocks 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.List, 13 | val results: List, 14 | override val nextCursor: String? = null, 15 | override val hasMore: Boolean = false, 16 | val type: String = "block", 17 | val block: Object = Object(), 18 | val requestId: String? = null, 19 | ) : WithObjectType, Pagination 20 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/blocks/RetrieveBlockChildrenRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.blocks 2 | 3 | import notion.api.v1.request.common.Pagination 4 | 5 | // var is intentional here (for the easiness in other JVM languages) 6 | data class RetrieveBlockChildrenRequest 7 | @JvmOverloads 8 | constructor( 9 | val blockId: String, 10 | override var startCursor: String? = null, 11 | override var pageSize: Int? = null, 12 | ) : Pagination { 13 | 14 | fun toQuery(): Map> { 15 | val body = mutableMapOf>() 16 | if (startCursor != null) { 17 | body["start_cursor"] = listOf(startCursor!!) 18 | } 19 | if (pageSize != null) { 20 | body["page_size"] = listOf(pageSize.toString()) 21 | } 22 | return body 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/DateFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class DateFilter 4 | @JvmOverloads 5 | constructor( 6 | var equals: String? = null, 7 | var before: String? = null, 8 | var after: String? = null, 9 | var onOrBefore: String? = null, 10 | var onOrAfter: String? = null, 11 | var pastWeek: DateCondition? = null, 12 | var pastMonth: DateCondition? = null, 13 | var pastYear: DateCondition? = null, 14 | var nextWeek: DateCondition? = null, 15 | var nextMonth: DateCondition? = null, 16 | var nextYear: DateCondition? = null, 17 | var isEmpty: Boolean? = null, 18 | var isNotEmpty: Boolean? = null, 19 | ) { 20 | open class DateCondition 21 | object EmptyDateCondition : DateCondition() 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/request/comments/RetrieveCommentsRequest.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.request.comments 2 | 3 | import notion.api.v1.request.common.Pagination 4 | 5 | // var is intentional here (for the easiness in other JVM languages) 6 | data class RetrieveCommentsRequest 7 | @JvmOverloads 8 | constructor( 9 | val blockId: String, 10 | override var startCursor: String? = null, 11 | override var pageSize: Int? = null, 12 | ) : Pagination { 13 | 14 | fun toQuery(): Map> { 15 | val body = mutableMapOf>() 16 | body["block_id"] = listOf(blockId) 17 | if (startCursor != null) { 18 | body["start_cursor"] = listOf(startCursor!!) 19 | } 20 | if (pageSize != null) { 21 | body["page_size"] = listOf(pageSize.toString()) 22 | } 23 | return body 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/test/kotlin/tests/java_compatibility/NotionClientTest.java: -------------------------------------------------------------------------------- 1 | package tests.java_compatibility; 2 | 3 | import notion.api.v1.NotionClient; 4 | import notion.api.v1.http.HttpUrlConnNotionHttpClient; 5 | import notion.api.v1.logging.StdoutLogger; 6 | import org.junit.Test; 7 | 8 | public class NotionClientTest { 9 | 10 | @Test 11 | public void runInternalAppInitialization() { 12 | NotionClient client = new NotionClient("token"); 13 | client.setLogger(new StdoutLogger()); 14 | client.setHttpClient(new HttpUrlConnNotionHttpClient()); 15 | } 16 | 17 | @Test 18 | public void runOAuthAppInitialization() { 19 | NotionClient client = new NotionClient("clientID", "clientSecret", "redirectUri"); 20 | client.setLogger(new StdoutLogger()); 21 | client.setHttpClient(new HttpUrlConnNotionHttpClient()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/TimestampFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class TimestampFilter 4 | @JvmOverloads 5 | constructor( 6 | var equals: String? = null, 7 | var before: String? = null, 8 | var after: String? = null, 9 | var onOrBefore: String? = null, 10 | var onOrAfter: String? = null, 11 | var pastWeek: TimestampCondition? = null, 12 | var pastMonth: TimestampCondition? = null, 13 | var pastYear: TimestampCondition? = null, 14 | var nextWeek: TimestampCondition? = null, 15 | var nextMonth: TimestampCondition? = null, 16 | var nextYear: TimestampCondition? = null, 17 | var isEmpty: Boolean? = null, 18 | var isNotEmpty: Boolean? = null, 19 | ) { 20 | open class TimestampCondition 21 | object EmptyDateCondition : TimestampCondition() 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/comments/Comments.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.comments 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.ObjectType 5 | import notion.api.v1.model.common.Pagination 6 | import notion.api.v1.model.common.WithObjectType 7 | 8 | // This data class does not have setters as developers never manually modify this 9 | data class Comments 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.List, 13 | val results: List, 14 | override val nextCursor: String? = null, 15 | override val hasMore: Boolean = false, 16 | val type: String = "comment", 17 | // We may revisit Any type here once the Notion API uses it in a meaningful way 18 | val comment: Any? = null, 19 | val requestId: String? = null, 20 | ) : WithObjectType, Pagination 21 | -------------------------------------------------------------------------------- /.github/workflows/ci-build.yml: -------------------------------------------------------------------------------- 1 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 2 | 3 | name: CI Build 4 | 5 | on: [push, pull_request] 6 | 7 | jobs: 8 | build: 9 | name: Java ${{ matrix.java-version }} 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 10 12 | 13 | strategy: 14 | matrix: 15 | java-version: [ '11', '17' ] 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Install JDK 20 | uses: actions/setup-java@v4 21 | with: 22 | java-version: ${{ matrix.java-version }} 23 | distribution: 'temurin' 24 | - name: Check the code format 25 | run: | 26 | mvn spotless:check 27 | - name: Compile the main/test code 28 | run: | 29 | mvn --no-transfer-progress -DfailIfNoTests=false '-Dtest=tests.**.*Test' test 30 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/QueryResults.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.ObjectType 5 | import notion.api.v1.model.common.Pagination 6 | import notion.api.v1.model.common.WithObjectType 7 | import notion.api.v1.model.pages.Page 8 | 9 | // This data class does not have setters as developers never manually modify this 10 | data class QueryResults 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.List, 14 | val results: List, 15 | val type: String, 16 | override val nextCursor: String? = null, 17 | override val hasMore: Boolean = false, 18 | var page: Object? = null, 19 | var database: Object? = null, 20 | var pageOrDatabase: Object? = null, 21 | val requestId: String? = null, 22 | ) : WithObjectType, Pagination 23 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/comments/Comment.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.comments 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.blocks.BlockParent 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.common.WithObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | // This data class does not have setters as developers never manually modify this 11 | data class Comment 12 | @JvmOverloads 13 | constructor( 14 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Comment, 15 | val id: String, 16 | var parent: BlockParent? = null, 17 | val discussionId: String, 18 | val createdTime: String, 19 | val createdBy: User, 20 | val lastEditedTime: String, 21 | var richText: List, 22 | val requestId: String? = null, 23 | ) : WithObjectType 24 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/File.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | // https://developers.notion.com/reference/file-object 4 | data class File 5 | @JvmOverloads 6 | constructor( 7 | val type: FileType, 8 | var external: ExternalFileDetails? = null, 9 | var file: FileDetails? = null, 10 | ) : Icon, Cover { 11 | companion object { 12 | @JvmStatic 13 | fun external(external: ExternalFileDetails): File { 14 | return File(type = FileType.External, external = external) 15 | } 16 | @JvmStatic 17 | fun external(url: String): File { 18 | return external(ExternalFileDetails(url = url)) 19 | } 20 | 21 | @JvmStatic 22 | fun file(file: FileDetails): File { 23 | return File(type = FileType.File, file = file) 24 | } 25 | 26 | @JvmStatic 27 | fun file(url: String, expiryTime: String? = null): File { 28 | return file(FileDetails(url = url, expiryTime = expiryTime)) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/endpoint/EndpointsSupport.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.endpoint 2 | 3 | import java.net.URLEncoder 4 | import notion.api.v1.http.UserAgent 5 | 6 | interface EndpointsSupport { 7 | val token: String? 8 | 9 | fun buildRequestHeaders(additionalOnes: Map): Map { 10 | val commonHeaders = 11 | mapOf( 12 | "Authorization" to "Bearer $token", 13 | "Notion-Version" to "2022-06-28", 14 | "User-Agent" to UserAgent.buildUserAgent(), 15 | ) 16 | .plus(additionalOnes) 17 | 18 | return if (token != null) { 19 | commonHeaders.plus("Authorization" to "Bearer $token") 20 | } else { 21 | commonHeaders 22 | } 23 | } 24 | 25 | fun urlEncode(value: String): String = URLEncoder.encode(value, "UTF-8") 26 | 27 | fun contentTypeJson(): Map = 28 | mapOf("Content-Type" to "application/json; charset=utf-8") 29 | } 30 | -------------------------------------------------------------------------------- /core/src/test/kotlin/tests/java_compatibility/BlocksTest.java: -------------------------------------------------------------------------------- 1 | package tests.java_compatibility; 2 | 3 | import notion.api.v1.model.blocks.ParagraphBlock; 4 | import notion.api.v1.model.pages.PageProperty; 5 | import org.junit.Test; 6 | 7 | import java.util.Arrays; 8 | import java.util.Collections; 9 | 10 | import static org.junit.Assert.assertNotNull; 11 | 12 | public class BlocksTest { 13 | 14 | @Test 15 | public void paragraph() { 16 | ParagraphBlock block = new ParagraphBlock( 17 | new ParagraphBlock.Element( 18 | Arrays.asList(new PageProperty.RichText()), 19 | Collections.emptyList() 20 | ), 21 | "id", 22 | false, 23 | "2021-05-01", 24 | null, 25 | "2021-05-02", 26 | null, 27 | null 28 | ); 29 | assertNotNull(block); 30 | } 31 | 32 | // TODO: add tests for others 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/logging/JavaUtilLogger.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.logging 2 | 3 | import java.util.logging.Level 4 | import java.util.logging.Logger 5 | 6 | class JavaUtilLogger @JvmOverloads constructor(val logger: Logger) : NotionLogger { 7 | 8 | constructor() : this(Logger.getLogger(JavaUtilLogger::class.java.canonicalName)) { 9 | if (this.logger.level == null) { 10 | this.logger.level = Level.ALL 11 | } 12 | } 13 | 14 | override fun isDebugEnabled(): Boolean = logger.isLoggable(Level.FINE) 15 | 16 | override fun debug(message: String, e: Throwable?) { 17 | logger.log(Level.FINE, message, e) 18 | } 19 | 20 | override fun info(message: String, e: Throwable?) { 21 | logger.log(Level.INFO, message, e) 22 | } 23 | 24 | override fun warn(message: String, e: Throwable?) { 25 | logger.log(Level.WARNING, message, e) 26 | } 27 | 28 | override fun error(message: String, e: Throwable?) { 29 | logger.log(Level.SEVERE, message, e) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/BlockElementUpdate.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import notion.api.v1.model.common.ExternalFileDetails 4 | import notion.api.v1.model.common.Icon 5 | import notion.api.v1.model.common.LinkToPage 6 | import notion.api.v1.model.common.SyncedFrom 7 | import notion.api.v1.model.pages.PageProperty 8 | 9 | data class BlockElementUpdate 10 | @JvmOverloads 11 | constructor( 12 | val richText: List? = null, 13 | val caption: List? = null, 14 | val checked: Boolean? = null, 15 | val url: String? = null, 16 | var external: ExternalFileDetails? = null, 17 | var language: String? = null, 18 | var expression: String? = null, // equation 19 | var color: String? = null, 20 | var linkToPage: LinkToPage? = null, 21 | val icon: Icon? = null, 22 | var syncedFrom: SyncedFrom? = null, 23 | val hasColumnHeader: Boolean? = null, // table 24 | val hasRowHeader: Boolean? = null, // table 25 | val cells: List>? = null, 26 | ) 27 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/pages/Page.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.pages 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.Cover 5 | import notion.api.v1.model.common.Icon 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.common.WithObjectType 8 | import notion.api.v1.model.users.User 9 | 10 | // This data class does not have setters as developers never manually modify this 11 | data class Page 12 | @JvmOverloads 13 | constructor( 14 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Page, 15 | val id: String, 16 | val icon: Icon, 17 | val cover: Cover, 18 | val createdTime: String, 19 | val createdBy: User, 20 | val lastEditedTime: String, 21 | val lastEditedBy: User, 22 | val url: String, 23 | val publicUrl: String? = null, 24 | val parent: PageParent? = null, 25 | val archived: Boolean? = false, 26 | val properties: Map, 27 | val requestId: String? = null, 28 | var inTrash: Boolean? = null, 29 | ) : WithObjectType 30 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/json/gson/CoverParser.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.json.gson 2 | 3 | import com.google.gson.* 4 | import java.lang.reflect.Type 5 | import notion.api.v1.model.common.Cover 6 | import notion.api.v1.model.common.File 7 | 8 | class CoverParser(private val unknownPropertyDetection: Boolean = false) : 9 | JsonDeserializer, JsonSerializer { 10 | 11 | override fun deserialize( 12 | json: JsonElement, 13 | typeOfT: Type, 14 | context: JsonDeserializationContext 15 | ): Cover? { 16 | when (json.asJsonObject.get("type").asString) { 17 | "file" -> return context.deserialize(json, File::class.java) 18 | "external" -> return context.deserialize(json, File::class.java) 19 | } 20 | if (unknownPropertyDetection) { 21 | throw IllegalArgumentException("Unsupported cover object detected: $json") 22 | } else { 23 | return null 24 | } 25 | } 26 | 27 | override fun serialize( 28 | src: Cover, 29 | typeOfSrc: Type, 30 | context: JsonSerializationContext 31 | ): JsonElement? = context.serialize(src) 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/pages/PageParent.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.pages 2 | 3 | data class PageParent 4 | @JvmOverloads 5 | constructor( 6 | // Notion stopped using type (as of May 19, 2021) 7 | val type: PageParentType? = null, 8 | var databaseId: String? = null, // type: database 9 | var pageId: String? = null, // type: page 10 | var workspace: Boolean? = null // type: workspace 11 | ) { 12 | 13 | companion object { 14 | @JvmStatic 15 | fun database(databaseId: String): PageParent { 16 | // having the `type` property does not work as of May 19, 2021 17 | return PageParent(type = null, databaseId = databaseId) 18 | } 19 | 20 | @JvmStatic 21 | fun page(pageId: String): PageParent { 22 | // having the `type` property does not work as of May 19, 2021 23 | return PageParent(type = null, pageId = pageId) 24 | } 25 | 26 | @JvmStatic 27 | fun workspace(): PageParent { 28 | // having the `type` property does not work as of May 19, 2021 29 | return PageParent(type = null, workspace = true) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /slf4j/src/main/kotlin/notion/api/v1/logging/Slf4jLogger.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.logging 2 | 3 | import org.slf4j.LoggerFactory 4 | 5 | class Slf4jLogger(name: String = Slf4jLogger::class.java.canonicalName) : NotionLogger { 6 | private val logger = LoggerFactory.getLogger(name) 7 | 8 | override fun isDebugEnabled(): Boolean = logger.isDebugEnabled 9 | 10 | override fun debug(message: String, e: Throwable?) { 11 | if (e != null) { 12 | logger.debug(message, e) 13 | } else { 14 | logger.debug(message) 15 | } 16 | } 17 | 18 | override fun info(message: String, e: Throwable?) { 19 | if (e != null) { 20 | logger.info(message, e) 21 | } else { 22 | logger.info(message) 23 | } 24 | } 25 | 26 | override fun warn(message: String, e: Throwable?) { 27 | if (e != null) { 28 | logger.warn(message, e) 29 | } else { 30 | logger.warn(message) 31 | } 32 | } 33 | 34 | override fun error(message: String, e: Throwable?) { 35 | if (e != null) { 36 | logger.error(message, e) 37 | } else { 38 | logger.error(message) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /slf4j2/src/main/kotlin/notion/api/v1/logging/Slf4jLogger.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.logging 2 | 3 | import org.slf4j.LoggerFactory 4 | 5 | class Slf4jLogger(name: String = Slf4jLogger::class.java.canonicalName) : NotionLogger { 6 | private val logger = LoggerFactory.getLogger(name) 7 | 8 | override fun isDebugEnabled(): Boolean = logger.isDebugEnabled 9 | 10 | override fun debug(message: String, e: Throwable?) { 11 | if (e != null) { 12 | logger.debug(message, e) 13 | } else { 14 | logger.debug(message) 15 | } 16 | } 17 | 18 | override fun info(message: String, e: Throwable?) { 19 | if (e != null) { 20 | logger.info(message, e) 21 | } else { 22 | logger.info(message) 23 | } 24 | } 25 | 26 | override fun warn(message: String, e: Throwable?) { 27 | if (e != null) { 28 | logger.warn(message, e) 29 | } else { 30 | logger.warn(message) 31 | } 32 | } 33 | 34 | override fun error(message: String, e: Throwable?) { 35 | if (e != null) { 36 | logger.error(message, e) 37 | } else { 38 | logger.error(message) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/search/PageSearchResult.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.search 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.Cover 5 | import notion.api.v1.model.common.Icon 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | data class PageSearchResult 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Page, 14 | override val id: String, 15 | override val icon: Icon, 16 | override val cover: Cover, 17 | override val createdTime: String, 18 | override val createdBy: User, 19 | override val lastEditedTime: String, 20 | override val lastEditedBy: User, 21 | val url: String, 22 | val publicUrl: String? = null, 23 | val parent: PageSearchResultParent? = null, 24 | override val archived: Boolean = false, 25 | val properties: Map, 26 | override val requestId: String? = null, 27 | override var inTrash: Boolean? = null, 28 | ) : SearchResult 29 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/Database.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.* 5 | import notion.api.v1.model.users.User 6 | 7 | // This data class does not have setters as developers never manually modify this 8 | data class Database 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Database, 12 | val id: String, 13 | val icon: Icon, 14 | val cover: Cover, 15 | val url: String, 16 | val publicUrl: String? = null, 17 | val createdTime: String, 18 | val createdBy: User, 19 | val lastEditedTime: String, 20 | val lastEditedBy: User, 21 | val parent: DatabaseParent? = null, 22 | val title: List, 23 | val description: List, 24 | @SerializedName("is_inline") val inline: Boolean, 25 | val properties: Map, 26 | val archived: Boolean, 27 | val requestId: String? = null, 28 | var inTrash: Boolean? = null, 29 | ) : WithObjectType 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2021 - Kazuhiro Sera (@seratch) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | 25 | -------------------------------------------------------------------------------- /scripts/set_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | new_version=$1 4 | # ------------------------------------------ 5 | if [[ "$new_version" == "" ]]; then 6 | echo "Give a version to set (e.g., 1.0.0)" 7 | exit 1 8 | fi 9 | 10 | find . -name pom.xml | xargs gsed -i "s/[0-9]\+\.[0-9]\+\.[^S]\+<\/version>/${new_version}<\/version>/g" 11 | find . -name pom.xml | xargs gsed -i "s/[0-9]\+\.[0-9]\+\.[^S]\+-SNAPSHOT<\/version>/${new_version}<\/version>/g" 12 | 13 | if [[ "$new_version" != *-SNAPSHOT ]]; then 14 | gsed -i "s/[0-9]\+\.[0-9]\+\.[^S]\+<\/notion-sdk.version>/${new_version}<\/notion-sdk.version>/g" README.md 15 | gsed -i "s/notionSdkVersion = \"[0-9]\+\.[0-9]\+\.[^S]\+\"/notionSdkVersion = \"${new_version}\"/g" README.md 16 | fi 17 | 18 | echo "package notion.api 19 | 20 | object Metadata { 21 | const val VERSION: String = \"$new_version\" 22 | 23 | fun isLibraryMaintainerMode(): Boolean { 24 | val value = System.getenv(\"NOTION_SDK_JVM_LIBRARY_MAINTAINER_MODE\") 25 | return value != null && ((value == \"1\") or (value == \"true\")) 26 | } 27 | }" > core/src/main/kotlin/notion/api/Metadata.kt 28 | 29 | git diff -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/logging/StdoutLogger.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.logging 2 | 3 | import java.time.ZoneId 4 | import java.util.* 5 | 6 | class StdoutLogger 7 | @JvmOverloads 8 | constructor(val name: String = StdoutLogger::class.java.canonicalName) : NotionLogger { 9 | 10 | override fun isDebugEnabled(): Boolean = true 11 | 12 | private fun now(): String = 13 | Date().toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime().toString() 14 | 15 | private fun buildMessage(level: String, message: String): String { 16 | return "${now()} $level $name - $message" 17 | } 18 | 19 | override fun debug(message: String, e: Throwable?) { 20 | println(buildMessage("DEBUG", message)) 21 | e?.printStackTrace() 22 | } 23 | 24 | override fun info(message: String, e: Throwable?) { 25 | println(buildMessage("INFO", message)) 26 | e?.printStackTrace() 27 | } 28 | 29 | override fun warn(message: String, e: Throwable?) { 30 | println(buildMessage("WARN", message)) 31 | e?.printStackTrace() 32 | } 33 | 34 | override fun error(message: String, e: Throwable?) { 35 | println(buildMessage("ERROR", message)) 36 | e?.printStackTrace() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/json/gson/IconParser.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.json.gson 2 | 3 | import com.google.gson.* 4 | import java.lang.reflect.Type 5 | import notion.api.v1.model.common.Emoji 6 | import notion.api.v1.model.common.File 7 | import notion.api.v1.model.common.Icon 8 | 9 | class IconParser(private val unknownPropertyDetection: Boolean = false) : 10 | JsonDeserializer, JsonSerializer { 11 | 12 | override fun deserialize( 13 | json: JsonElement, 14 | typeOfT: Type, 15 | context: JsonDeserializationContext 16 | ): Icon? { 17 | when (json.asJsonObject.get("type").asString) { 18 | "file" -> return context.deserialize(json, File::class.java) 19 | "external" -> return context.deserialize(json, File::class.java) 20 | "emoji" -> return context.deserialize(json, Emoji::class.java) 21 | } 22 | if (unknownPropertyDetection) { 23 | throw IllegalArgumentException("Unsupported icon object detected: $json") 24 | } else { 25 | return null 26 | } 27 | } 28 | 29 | override fun serialize( 30 | src: Icon, 31 | typeOfSrc: Type, 32 | context: JsonSerializationContext 33 | ): JsonElement? = context.serialize(src) 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/search/SearchResult.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.search 2 | 3 | import notion.api.v1.model.common.Cover 4 | import notion.api.v1.model.common.Icon 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.common.WithObjectType 7 | import notion.api.v1.model.users.User 8 | 9 | interface SearchResult : WithObjectType { 10 | override val objectType: ObjectType 11 | val id: String 12 | val icon: Icon 13 | val cover: Cover 14 | val createdTime: String 15 | val lastEditedTime: String 16 | val createdBy: User 17 | val lastEditedBy: User 18 | val archived: Boolean 19 | val requestId: String? 20 | var inTrash: Boolean? 21 | 22 | fun asDatabase(): DatabaseSearchResult = 23 | if (objectType == ObjectType.Database) this as DatabaseSearchResult 24 | else 25 | throw IllegalStateException( 26 | "Failed to cast $objectType search result to DatabaseSearchResult") 27 | 28 | fun asPage(): PageSearchResult = 29 | if (objectType == ObjectType.Page) this as PageSearchResult 30 | else 31 | throw IllegalStateException( 32 | "Failed to cast $objectType search result to PageSearchResult") 33 | } 34 | -------------------------------------------------------------------------------- /core/src/test/kotlin/tests/json/OAuthTokenResultParserTest.kt: -------------------------------------------------------------------------------- 1 | package tests.json 2 | 3 | import kotlin.test.assertNotNull 4 | import notion.api.v1.json.GsonSerializer 5 | import org.junit.Test 6 | 7 | class OAuthTokenResultParserTest { 8 | private val json = 9 | """ 10 | { 11 | "access_token": "secret_XXXXX", 12 | "token_type": "bearer", 13 | "bot_id": "4cda3e4b-XXX-XXX-XXX-XXX", 14 | "workspace_name": "Kaz's Notion", 15 | "workspace_icon": "https://lh3.googleusercontent.com/a-/AOh14Gi6IRO6Ea30aCqeQFbgbR5HgU7ghyRsGAUjsUo3Ito=s100", 16 | "workspace_id": "841147a2-YYY-YYY-YYY-YYY", 17 | "owner": { 18 | "type": "user", 19 | "user": { 20 | "object": "user", 21 | "id": "94ab783a-ZZZ-ZZZ-ZZZ-ZZZ", 22 | "name": "Kazuhiro Sera", 23 | "avatar_url": "https://lh3.googleusercontent.com/a-/AOh14Gi6IRO6Ea30aCqeQFbgbR5HgU7ghyRsGAUjsUo3Ito=s100", 24 | "type": "person", 25 | "person": { 26 | "email": "seratch@example.com" 27 | } 28 | } 29 | } 30 | } 31 | """.trimIndent() 32 | 33 | @Test 34 | fun testParsing() { 35 | val serializer = GsonSerializer() 36 | val result = serializer.toOAuthTokenResult(json) 37 | assertNotNull(result) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/json/gson/SearchResultParser.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.json.gson 2 | 3 | import com.google.gson.* 4 | import java.lang.reflect.Type 5 | import notion.api.v1.model.search.DatabaseSearchResult 6 | import notion.api.v1.model.search.PageSearchResult 7 | import notion.api.v1.model.search.SearchResult 8 | 9 | class SearchResultParser(private val unknownPropertyDetection: Boolean = false) : 10 | JsonDeserializer, JsonSerializer { 11 | 12 | override fun deserialize( 13 | json: JsonElement, 14 | typeOfT: Type, 15 | context: JsonDeserializationContext 16 | ): SearchResult? { 17 | when (json.asJsonObject.get("object").asString) { 18 | "page" -> return context.deserialize(json, PageSearchResult::class.java) 19 | "database" -> return context.deserialize(json, DatabaseSearchResult::class.java) 20 | } 21 | if (unknownPropertyDetection) { 22 | throw IllegalArgumentException("Unsupported search result object detected: $json") 23 | } else { 24 | return null 25 | } 26 | } 27 | 28 | override fun serialize( 29 | src: SearchResult, 30 | typeOfSrc: Type, 31 | context: JsonSerializationContext 32 | ): JsonElement? = context.serialize(src) 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/PropertyFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter 2 | 3 | import notion.api.v1.model.databases.query.filter.condition.* 4 | 5 | open class PropertyFilter 6 | @JvmOverloads 7 | constructor( 8 | var property: String? = null, // The name or ID of the property to filter on. 9 | var title: TextFilter? = null, 10 | var richText: TextFilter? = null, 11 | var url: TextFilter? = null, 12 | var email: TextFilter? = null, 13 | var phoneNumber: TextFilter? = null, 14 | var number: NumberFilter? = null, 15 | var checkbox: CheckboxFilter? = null, 16 | var select: SelectFilter? = null, 17 | var multiSelect: MultiSelectFilter? = null, 18 | var date: DateFilter? = null, 19 | var timestamp: String? = null, // "created_time", "last_edited_time" 20 | var createdTime: TimestampFilter? = null, 21 | var lastEditedTime: TimestampFilter? = null, 22 | var createdBy: PeopleFilter? = null, 23 | var lastEditedBy: PeopleFilter? = null, 24 | var file: FilesFilter? = null, 25 | var relation: RelationFilter? = null, 26 | var formula: FormulaFilter? = null, 27 | var status: StatusFilter? = null, 28 | var rollup: RollupFilter? = null, 29 | ) : QueryTopLevelFilter, CompoundFilterElement 30 | -------------------------------------------------------------------------------- /okhttp3/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.github.seratch 8 | notion-sdk-jvm-parent 9 | 1.11.2-SNAPSHOT 10 | 11 | 12 | notion-sdk-jvm-okhttp3 13 | 1.11.2-SNAPSHOT 14 | jar 15 | 16 | 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | com.github.seratch 24 | notion-sdk-jvm-core 25 | ${project.version} 26 | 27 | 28 | com.squareup.okhttp3 29 | okhttp 30 | ${okhttp3.version} 31 | 32 | 33 | -------------------------------------------------------------------------------- /okhttp4/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.github.seratch 8 | notion-sdk-jvm-parent 9 | 1.11.2-SNAPSHOT 10 | 11 | 12 | notion-sdk-jvm-okhttp4 13 | 1.11.2-SNAPSHOT 14 | jar 15 | 16 | 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | com.github.seratch 24 | notion-sdk-jvm-core 25 | ${project.version} 26 | 27 | 28 | com.squareup.okhttp3 29 | okhttp 30 | ${okhttp4.version} 31 | 32 | 33 | -------------------------------------------------------------------------------- /okhttp5/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.github.seratch 8 | notion-sdk-jvm-parent 9 | 1.11.2-SNAPSHOT 10 | 11 | 12 | notion-sdk-jvm-okhttp5 13 | 1.11.2-SNAPSHOT 14 | jar 15 | 16 | 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | com.github.seratch 24 | notion-sdk-jvm-core 25 | ${project.version} 26 | 27 | 28 | com.squareup.okhttp3 29 | okhttp 30 | ${okhttp5.version} 31 | 32 | 33 | -------------------------------------------------------------------------------- /core/src/test/kotlin/tests/model/UsersTest.kt: -------------------------------------------------------------------------------- 1 | package tests.model 2 | 3 | import kotlin.test.assertNotNull 4 | import notion.api.v1.json.GsonSerializer 5 | import org.junit.Test 6 | 7 | class UsersTest { 8 | 9 | @Test 10 | fun listUsers() { 11 | val parser = GsonSerializer(true) 12 | val users = parser.toUsers(listUsersResponse) 13 | assertNotNull(users) 14 | } 15 | 16 | private val listUsersResponse = 17 | """ 18 | { 19 | "object": "list", 20 | "results": [ 21 | { 22 | "object": "user", 23 | "id": "94ab783a-9ee8-416d-b9b2-bdb1b0b2b1b3", 24 | "name": "Alice", 25 | "avatar_url": "https://lh3.googleusercontent.com/a-/xxx=s100", 26 | "type": "person", 27 | "person": { 28 | "email": "foo@example.com" 29 | } 30 | }, 31 | { 32 | "object": "user", 33 | "id": "2f22fbed-c837-4bb6-9e49-c0fff7dd5b8b", 34 | "name": "sync-app", 35 | "avatar_url": null, 36 | "type": "bot", 37 | "bot": {} 38 | }, 39 | { 40 | "object": "user", 41 | "id": "3f8cea1d-20eb-4d07-8b3b-9258b648940b", 42 | "name": "awesome-app", 43 | "avatar_url": null, 44 | "type": "bot", 45 | "bot": {} 46 | } 47 | ], 48 | "next_cursor": null, 49 | "has_more": false 50 | } 51 | """.trimIndent() 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/BlockParent.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | data class BlockParent 4 | @JvmOverloads 5 | constructor( 6 | val type: BlockParentType? = null, 7 | var databaseId: String? = null, // type: database 8 | var pageId: String? = null, // type: page 9 | var blockId: String? = null, // type: block 10 | var workspace: Boolean? = null // type: workspace 11 | ) { 12 | 13 | companion object { 14 | @JvmStatic 15 | fun database(databaseId: String): BlockParent { 16 | // having the `type` property does not work as of May 19, 2021 17 | return BlockParent(type = null, databaseId = databaseId) 18 | } 19 | 20 | @JvmStatic 21 | fun page(pageId: String): BlockParent { 22 | // having the `type` property does not work as of May 19, 2021 23 | return BlockParent(type = null, pageId = pageId) 24 | } 25 | 26 | @JvmStatic 27 | fun block(blockId: String): BlockParent { 28 | // having the `type` property does not work as of May 19, 2021 29 | return BlockParent(type = null, blockId = blockId) 30 | } 31 | 32 | @JvmStatic 33 | fun workspace(): BlockParent { 34 | // having the `type` property does not work as of May 19, 2021 35 | return BlockParent(type = null, workspace = true) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/query/filter/condition/RollupFilter.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases.query.filter.condition 2 | 3 | open class RollupFilter 4 | @JvmOverloads 5 | constructor( 6 | var any: Content? = null, 7 | var every: Content? = null, 8 | var none: Content? = null, 9 | ) { 10 | open class Content 11 | @JvmOverloads 12 | constructor( 13 | var title: TextFilter? = null, 14 | var richText: TextFilter? = null, 15 | var url: TextFilter? = null, 16 | var email: TextFilter? = null, 17 | var phoneNumber: TextFilter? = null, 18 | var number: NumberFilter? = null, 19 | var checkbox: CheckboxFilter? = null, 20 | var select: SelectFilter? = null, 21 | var multiSelect: MultiSelectFilter? = null, 22 | var date: DateFilter? = null, 23 | var timestamp: String? = null, // "created_time", "last_edited_time" 24 | var createdTime: TimestampFilter? = null, 25 | var lastEditedTime: TimestampFilter? = null, 26 | var createdBy: PeopleFilter? = null, 27 | var lastEditedBy: PeopleFilter? = null, 28 | var file: FilesFilter? = null, 29 | var relation: RelationFilter? = null, 30 | var formula: FormulaFilter? = null, 31 | var status: StatusFilter? = null, 32 | var rollup: RollupFilter? = null, 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/search/DatabaseSearchResult.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.search 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.Cover 5 | import notion.api.v1.model.common.Icon 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.databases.DatabaseParent 8 | import notion.api.v1.model.databases.DatabaseProperty 9 | import notion.api.v1.model.users.User 10 | 11 | data class DatabaseSearchResult 12 | @JvmOverloads 13 | constructor( 14 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Database, 15 | override val id: String, 16 | override val icon: Icon, 17 | override val cover: Cover, 18 | override val createdTime: String, 19 | override val createdBy: User, 20 | override val lastEditedTime: String, 21 | override val lastEditedBy: User, 22 | override val archived: Boolean, 23 | val url: String, 24 | val publicUrl: String? = null, 25 | val parent: DatabaseParent, 26 | val title: List?, 27 | val description: List?, 28 | @SerializedName("is_inline") val inline: Boolean, 29 | override var inTrash: Boolean? = null, 30 | val properties: Map, 31 | override val requestId: String? = null, 32 | ) : SearchResult 33 | -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.github.seratch 8 | notion-sdk-jvm-parent 9 | 1.11.2-SNAPSHOT 10 | 11 | 12 | notion-sdk-jvm-core 13 | 1.11.2-SNAPSHOT 14 | jar 15 | 16 | 17 | 1.8 18 | 1.8 19 | 2.3.12 20 | 21 | 22 | 23 | 24 | io.ktor 25 | ktor-server-core-jvm 26 | ${ktor.version} 27 | test 28 | 29 | 30 | io.ktor 31 | ktor-server-netty-jvm 32 | ${ktor.version} 33 | test 34 | 35 | 36 | -------------------------------------------------------------------------------- /core/src/test/kotlin/tests/java_compatibility/PagePropertiesTest.java: -------------------------------------------------------------------------------- 1 | package tests.java_compatibility; 2 | 3 | import notion.api.v1.model.common.FormulaType; 4 | import notion.api.v1.model.pages.PageProperty; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertNotNull; 8 | 9 | public class PagePropertiesTest { 10 | 11 | @Test 12 | public void noArgConstructorShouldWork() { 13 | PageProperty property = new PageProperty(); 14 | assertNotNull(property); 15 | } 16 | 17 | @Test 18 | public void richText() { 19 | PageProperty.RichText richText = new PageProperty.RichText(); 20 | assertNotNull(richText); 21 | 22 | PageProperty.RichText.Text text = new PageProperty.RichText.Text(); 23 | text.setContent("Something"); 24 | PageProperty.RichText.Link link = new PageProperty.RichText.Link(); 25 | link.setUrl("https://www.example.com/"); 26 | text.setLink(link); 27 | richText.setText(text); 28 | } 29 | 30 | @Test 31 | public void formula() { 32 | PageProperty.Formula formula = new PageProperty.Formula(FormulaType.Boolean); 33 | formula.setBoolean(false); 34 | assertNotNull(formula); 35 | } 36 | 37 | @Test 38 | public void date() { 39 | PageProperty.Date date = new PageProperty.Date(); 40 | date.setStart("2021-05-13"); 41 | assertNotNull(date); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/BlockColor.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class BlockColor @JvmOverloads constructor(val value: String) { 6 | @SerializedName("default") Default("default"), 7 | @SerializedName("gray") Gray("gray"), 8 | @SerializedName("brown") Brown("brown"), 9 | @SerializedName("orange") Orange("orange"), 10 | @SerializedName("yellow") Yellow("yellow"), 11 | @SerializedName("green") Green("green"), 12 | @SerializedName("blue") Blue("blue"), 13 | @SerializedName("purple") Purple("purple"), 14 | @SerializedName("pink") Pink("pink"), 15 | @SerializedName("red") Red("red"), 16 | @SerializedName("gray_background") GrayBackground("gray_background"), 17 | @SerializedName("brown_background") BrownBackground("brown_background"), 18 | @SerializedName("orange_background") OrangeBackground("orange_background"), 19 | @SerializedName("yellow_background") YellowBackground("yellow_background"), 20 | @SerializedName("green_background") GreenBackground("green_background"), 21 | @SerializedName("blue_background") BlueBackground("blue_background"), 22 | @SerializedName("purple_background") PurpleBackground("purple_background"), 23 | @SerializedName("pink_background") PinkBackground("pink_background"), 24 | @SerializedName("red_background") RedBackground("red_background"); 25 | 26 | override fun toString(): String = value 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/RichTextColor.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class RichTextColor @JvmOverloads constructor(val value: String) { 6 | @SerializedName("default") Default("default"), 7 | @SerializedName("gray") Gray("gray"), 8 | @SerializedName("brown") Brown("brown"), 9 | @SerializedName("orange") Orange("orange"), 10 | @SerializedName("yellow") Yellow("yellow"), 11 | @SerializedName("green") Green("green"), 12 | @SerializedName("blue") Blue("blue"), 13 | @SerializedName("purple") Purple("purple"), 14 | @SerializedName("pink") Pink("pink"), 15 | @SerializedName("red") Red("red"), 16 | @SerializedName("gray_background") GrayBackground("gray_background"), 17 | @SerializedName("brown_background") BrownBackground("brown_background"), 18 | @SerializedName("orange_background") OrangeBackground("orange_background"), 19 | @SerializedName("yellow_background") YellowBackground("yellow_background"), 20 | @SerializedName("green_background") GreenBackground("green_background"), 21 | @SerializedName("blue_background") BlueBackground("blue_background"), 22 | @SerializedName("purple_background") PurpleBackground("purple_background"), 23 | @SerializedName("pink_background") PinkBackground("pink_background"), 24 | @SerializedName("red_background") RedBackground("red_background"); 25 | 26 | override fun toString(): String = value 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/search/PageSearchResultParent.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.search 2 | 3 | data class PageSearchResultParent 4 | @JvmOverloads 5 | constructor( 6 | val type: PageSearchResultParentType? = null, 7 | var databaseId: String? = null, // type: database 8 | var pageId: String? = null, // type: page 9 | var blockId: String? = null, // type: block 10 | var workspace: Boolean? = null // type: workspace 11 | ) { 12 | 13 | companion object { 14 | @JvmStatic 15 | fun database(databaseId: String): PageSearchResultParent { 16 | // having the `type` property does not work as of May 19, 2021 17 | return PageSearchResultParent(type = null, databaseId = databaseId) 18 | } 19 | 20 | @JvmStatic 21 | fun page(pageId: String): PageSearchResultParent { 22 | // having the `type` property does not work as of May 19, 2021 23 | return PageSearchResultParent(type = null, pageId = pageId) 24 | } 25 | 26 | @JvmStatic 27 | fun block(blockId: String): PageSearchResultParent { 28 | // having the `type` property does not work as of May 19, 2021 29 | return PageSearchResultParent(type = null, blockId = blockId) 30 | } 31 | 32 | @JvmStatic 33 | fun workspace(): PageSearchResultParent { 34 | // having the `type` property does not work as of May 19, 2021 35 | return PageSearchResultParent(type = null, workspace = true) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/common/PropertyType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.common 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class PropertyType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("rich_text") RichText("rich_text"), 7 | @SerializedName("number") Number("number"), 8 | @SerializedName("select") Select("select"), 9 | @SerializedName("multi_select") MultiSelect("multi_select"), 10 | @SerializedName("date") Date("date"), 11 | @SerializedName("formula") Formula("formula"), 12 | @SerializedName("relation") Relation("relation"), 13 | @SerializedName("rollup") Rollup("rollup"), 14 | @SerializedName("title") Title("title"), 15 | @SerializedName("people") People("people"), 16 | @SerializedName("files") Files("files"), 17 | @SerializedName("checkbox") Checkbox("checkbox"), 18 | @SerializedName("url") Url("url"), 19 | @SerializedName("email") Email("email"), 20 | @SerializedName("phone_number") PhoneNumber("phone_number"), 21 | @SerializedName("created_time") CreatedTime("created_time"), 22 | @SerializedName("created_by") CreatedBy("created_by"), 23 | @SerializedName("last_edited_time") LastEditedTime("last_edited_time"), 24 | @SerializedName("last_edited_by") LastEditedBy("last_edited_by"), 25 | @SerializedName("unique_id") UniqueId("unique_id"), 26 | @SerializedName("property_item") PropertyItem("property_item"); 27 | 28 | override fun toString(): String = value 29 | } 30 | -------------------------------------------------------------------------------- /httpclient/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.github.seratch 8 | notion-sdk-jvm-parent 9 | 1.11.2-SNAPSHOT 10 | 11 | 12 | notion-sdk-jvm-httpclient 13 | 1.11.2-SNAPSHOT 14 | jar 15 | 16 | 17 | 11 18 | 11 19 | 20 | 21 | 22 | 23 | com.github.seratch 24 | notion-sdk-jvm-core 25 | ${project.version} 26 | 27 | 28 | 29 | 30 | 31 | 32 | maven-compiler-plugin 33 | ${maven-compiler-plugin.version} 34 | 35 | 11 36 | 11 37 | UTF-8 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/UnsupportedBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.users.User 7 | 8 | open class UnsupportedBlock 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 12 | override val type: BlockType = BlockType.Unsupported, 13 | override var id: String? = UUID.randomUUID().toString(), 14 | override var createdTime: String? = null, 15 | override var createdBy: User? = null, 16 | override var lastEditedTime: String? = null, 17 | override var lastEditedBy: User? = null, 18 | override var hasChildren: Boolean? = null, 19 | override var archived: Boolean? = null, 20 | override var parent: BlockParent? = null, 21 | val unsupported: Element? = null, 22 | override val requestId: String? = null, 23 | override var inTrash: Boolean? = null, 24 | ) : Block { 25 | 26 | // for other JVM languages 27 | constructor( 28 | id: String? = UUID.randomUUID().toString(), 29 | hasChildren: Boolean? = null, 30 | createdTime: String? = null, 31 | createdBy: User? = null, 32 | archived: Boolean? = null, 33 | lastEditedTime: String? = null, 34 | lastEditedBy: User? = null, 35 | parent: BlockParent? = null, 36 | ) : this( 37 | ObjectType.Block, 38 | BlockType.Unsupported, 39 | id, 40 | createdTime, 41 | createdBy, 42 | lastEditedTime, 43 | lastEditedBy, 44 | hasChildren, 45 | archived, 46 | parent) 47 | 48 | open class Element 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/json/gson/CompoundFilterElementParser.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.json.gson 2 | 3 | import com.google.gson.* 4 | import java.lang.reflect.Type 5 | import notion.api.v1.model.databases.query.filter.CompoundFilter 6 | import notion.api.v1.model.databases.query.filter.CompoundFilterElement 7 | import notion.api.v1.model.databases.query.filter.PropertyFilter 8 | 9 | class CompoundFilterElementParser(private val unknownPropertyDetection: Boolean = false) : 10 | JsonDeserializer, JsonSerializer { 11 | 12 | override fun deserialize( 13 | json: JsonElement, 14 | typeOfT: Type, 15 | context: JsonDeserializationContext 16 | ): CompoundFilterElement? { 17 | if (json == null) { 18 | return null 19 | } 20 | if (json.asJsonObject.get("or") != null || json.asJsonObject.get("and") != null) { 21 | return context.deserialize(json, CompoundFilter::class.java) 22 | } 23 | if (json.asJsonObject.get("property") != null) { 24 | return context.deserialize(json, PropertyFilter::class.java) 25 | } 26 | if (unknownPropertyDetection) { 27 | throw IllegalArgumentException("Unsupported compound filter item detected: $json") 28 | } else { 29 | return null 30 | } 31 | } 32 | 33 | override fun serialize( 34 | src: CompoundFilterElement, 35 | typeOfSrc: Type, 36 | context: JsonSerializationContext 37 | ): JsonElement? { 38 | if (src is CompoundFilter) { 39 | return context.serialize(src, CompoundFilter::class.java) 40 | } 41 | if (src is PropertyFilter) { 42 | return context.serialize(src, PropertyFilter::class.java) 43 | } 44 | return null 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/DividerBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.users.User 7 | 8 | open class DividerBlock 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 12 | override val type: BlockType = BlockType.Divider, 13 | override var id: String? = UUID.randomUUID().toString(), 14 | override var createdTime: String? = null, 15 | override var createdBy: User? = null, 16 | override var lastEditedTime: String? = null, 17 | override var lastEditedBy: User? = null, 18 | override var hasChildren: Boolean? = null, 19 | override var archived: Boolean? = null, 20 | override var parent: BlockParent? = null, 21 | val divider: Element? = null, 22 | override val requestId: String? = null, 23 | override var inTrash: Boolean? = null, 24 | ) : Block { 25 | 26 | // for other JVM languages 27 | constructor( 28 | divider: Element, 29 | id: String? = UUID.randomUUID().toString(), 30 | hasChildren: Boolean? = null, 31 | createdTime: String? = null, 32 | createdBy: User? = null, 33 | archived: Boolean? = null, 34 | lastEditedTime: String? = null, 35 | lastEditedBy: User? = null, 36 | parent: BlockParent? = null, 37 | ) : this( 38 | ObjectType.Block, 39 | BlockType.Divider, 40 | id, 41 | createdTime, 42 | createdBy, 43 | lastEditedTime, 44 | lastEditedBy, 45 | hasChildren, 46 | archived, 47 | parent, 48 | divider) 49 | 50 | open class Element 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/ColumnBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.users.User 7 | 8 | open class ColumnBlock 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 12 | override val type: BlockType = BlockType.Column, 13 | override var id: String? = UUID.randomUUID().toString(), 14 | override var createdTime: String? = null, 15 | override var createdBy: User? = null, 16 | override var lastEditedTime: String? = null, 17 | override var lastEditedBy: User? = null, 18 | override var hasChildren: Boolean? = null, 19 | override var archived: Boolean? = null, 20 | override var parent: BlockParent? = null, 21 | val column: Element? = null, 22 | override val requestId: String? = null, 23 | override var inTrash: Boolean? = null, 24 | ) : Block { 25 | 26 | // for other JVM languages 27 | constructor( 28 | column: Element, 29 | id: String? = UUID.randomUUID().toString(), 30 | hasChildren: Boolean? = null, 31 | createdTime: String? = null, 32 | createdBy: User? = null, 33 | archived: Boolean? = null, 34 | lastEditedTime: String? = null, 35 | lastEditedBy: User? = null, 36 | parent: BlockParent? = null, 37 | ) : this( 38 | ObjectType.Block, 39 | BlockType.Column, 40 | id, 41 | createdTime, 42 | createdBy, 43 | lastEditedTime, 44 | lastEditedBy, 45 | hasChildren, 46 | archived, 47 | parent, 48 | column) 49 | 50 | open class Element @JvmOverloads constructor() 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/EquationBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.Equation 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.users.User 8 | 9 | open class EquationBlock 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 13 | override val type: BlockType = BlockType.Equation, 14 | override var id: String? = UUID.randomUUID().toString(), 15 | override var createdTime: String? = null, 16 | override var createdBy: User? = null, 17 | override var lastEditedTime: String? = null, 18 | override var lastEditedBy: User? = null, 19 | override var hasChildren: Boolean? = null, 20 | override var archived: Boolean? = null, 21 | override var parent: BlockParent? = null, 22 | val equation: Equation? = null, 23 | override val requestId: String? = null, 24 | override var inTrash: Boolean? = null, 25 | ) : Block { 26 | 27 | // for other JVM languages 28 | constructor( 29 | equation: Equation, 30 | id: String? = UUID.randomUUID().toString(), 31 | hasChildren: Boolean? = null, 32 | createdTime: String? = null, 33 | createdBy: User? = null, 34 | archived: Boolean? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | ObjectType.Block, 40 | BlockType.Equation, 41 | id, 42 | createdTime, 43 | createdBy, 44 | lastEditedTime, 45 | lastEditedBy, 46 | hasChildren, 47 | archived, 48 | parent, 49 | equation) 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/LinkToPageBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.LinkToPage 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.users.User 8 | 9 | open class LinkToPageBlock 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 13 | override val type: BlockType = BlockType.LinkToPage, 14 | override var id: String? = UUID.randomUUID().toString(), 15 | override var createdTime: String? = null, 16 | override var createdBy: User? = null, 17 | override var lastEditedTime: String? = null, 18 | override var lastEditedBy: User? = null, 19 | override var hasChildren: Boolean? = null, 20 | override var archived: Boolean? = null, 21 | override var parent: BlockParent? = null, 22 | val linkToPage: LinkToPage? = null, 23 | override val requestId: String? = null, 24 | override var inTrash: Boolean? = null, 25 | ) : Block { 26 | 27 | // for other JVM languages 28 | constructor( 29 | linkToPage: LinkToPage, 30 | id: String? = UUID.randomUUID().toString(), 31 | hasChildren: Boolean? = null, 32 | createdTime: String? = null, 33 | createdBy: User? = null, 34 | archived: Boolean? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | ObjectType.Block, 40 | BlockType.LinkToPage, 41 | id, 42 | createdTime, 43 | createdBy, 44 | lastEditedTime, 45 | lastEditedBy, 46 | hasChildren, 47 | archived, 48 | parent, 49 | linkToPage) 50 | } 51 | -------------------------------------------------------------------------------- /slf4j2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.github.seratch 8 | notion-sdk-jvm-parent 9 | 1.11.2-SNAPSHOT 10 | 11 | 12 | notion-sdk-jvm-slf4j2 13 | 1.11.2-SNAPSHOT 14 | jar 15 | 16 | 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | com.github.seratch 24 | notion-sdk-jvm-core 25 | ${project.version} 26 | 27 | 28 | org.slf4j 29 | slf4j-api 30 | ${slf4j2.version} 31 | 32 | 33 | 34 | org.slf4j 35 | slf4j-simple 36 | ${slf4j2.version} 37 | test 38 | 39 | 40 | com.github.seratch 41 | notion-sdk-jvm-okhttp3 42 | ${project.version} 43 | test 44 | 45 | 46 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/BreadcrumbBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.users.User 7 | 8 | open class BreadcrumbBlock 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 12 | override val type: BlockType = BlockType.Breadcrumb, 13 | override var id: String? = UUID.randomUUID().toString(), 14 | override var createdTime: String? = null, 15 | override var createdBy: User? = null, 16 | override var lastEditedTime: String? = null, 17 | override var lastEditedBy: User? = null, 18 | override var hasChildren: Boolean? = null, 19 | override var archived: Boolean? = null, 20 | override var parent: BlockParent? = null, 21 | val breadcrumb: Element? = null, 22 | override val requestId: String? = null, 23 | override var inTrash: Boolean? = null, 24 | ) : Block { 25 | 26 | // for other JVM languages 27 | constructor( 28 | breadcrumb: Element, 29 | id: String? = UUID.randomUUID().toString(), 30 | hasChildren: Boolean? = null, 31 | createdTime: String? = null, 32 | createdBy: User? = null, 33 | archived: Boolean? = null, 34 | lastEditedTime: String? = null, 35 | lastEditedBy: User? = null, 36 | parent: BlockParent? = null, 37 | ) : this( 38 | ObjectType.Block, 39 | BlockType.Breadcrumb, 40 | id, 41 | createdTime, 42 | createdBy, 43 | lastEditedTime, 44 | lastEditedBy, 45 | hasChildren, 46 | archived, 47 | parent, 48 | breadcrumb) 49 | 50 | open class Element @JvmOverloads constructor() 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/ColumnListBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.users.User 7 | 8 | open class ColumnListBlock 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 12 | override val type: BlockType = BlockType.ColumnList, 13 | override var id: String? = UUID.randomUUID().toString(), 14 | override var createdTime: String? = null, 15 | override var createdBy: User? = null, 16 | override var lastEditedTime: String? = null, 17 | override var lastEditedBy: User? = null, 18 | override var hasChildren: Boolean? = null, 19 | override var archived: Boolean? = null, 20 | override var parent: BlockParent? = null, 21 | val columnList: Element? = null, 22 | override val requestId: String? = null, 23 | override var inTrash: Boolean? = null, 24 | ) : Block { 25 | 26 | // for other JVM languages 27 | constructor( 28 | columnList: Element, 29 | id: String? = UUID.randomUUID().toString(), 30 | hasChildren: Boolean? = null, 31 | createdTime: String? = null, 32 | createdBy: User? = null, 33 | archived: Boolean? = null, 34 | lastEditedTime: String? = null, 35 | lastEditedBy: User? = null, 36 | parent: BlockParent? = null, 37 | ) : this( 38 | ObjectType.Block, 39 | BlockType.ColumnList, 40 | id, 41 | createdTime, 42 | createdBy, 43 | lastEditedTime, 44 | lastEditedBy, 45 | hasChildren, 46 | archived, 47 | parent, 48 | columnList) 49 | 50 | open class Element @JvmOverloads constructor() 51 | } 52 | -------------------------------------------------------------------------------- /slf4j/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.github.seratch 8 | notion-sdk-jvm-parent 9 | 1.11.2-SNAPSHOT 10 | 11 | 12 | notion-sdk-jvm-slf4j 13 | 1.11.2-SNAPSHOT 14 | jar 15 | 16 | 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | com.github.seratch 24 | notion-sdk-jvm-core 25 | ${project.version} 26 | 27 | 28 | org.slf4j 29 | slf4j-api 30 | ${slf4j.version} 31 | 32 | 33 | 34 | ch.qos.logback 35 | logback-classic 36 | ${logback.version} 37 | test 38 | 39 | 40 | com.github.seratch 41 | notion-sdk-jvm-okhttp3 42 | ${project.version} 43 | test 44 | 45 | 46 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/ChildPageBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.users.User 7 | 8 | open class ChildPageBlock 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 12 | override val type: BlockType = BlockType.ChildPage, 13 | override var id: String? = UUID.randomUUID().toString(), 14 | override var createdTime: String? = null, 15 | override var createdBy: User? = null, 16 | override var lastEditedTime: String? = null, 17 | override var lastEditedBy: User? = null, 18 | override var hasChildren: Boolean? = null, 19 | override var archived: Boolean? = null, 20 | override var parent: BlockParent? = null, 21 | val childPage: Element, 22 | override val requestId: String? = null, 23 | override var inTrash: Boolean? = null, 24 | ) : Block { 25 | 26 | // for other JVM languages 27 | constructor( 28 | childPage: Element, 29 | id: String? = UUID.randomUUID().toString(), 30 | hasChildren: Boolean? = null, 31 | createdTime: String? = null, 32 | createdBy: User? = null, 33 | lastEditedTime: String? = null, 34 | lastEditedBy: User? = null, 35 | parent: BlockParent? = null, 36 | ) : this( 37 | objectType = ObjectType.Block, 38 | type = BlockType.ChildPage, 39 | id = id, 40 | createdTime = createdTime, 41 | createdBy = createdBy, 42 | lastEditedTime = lastEditedTime, 43 | lastEditedBy = lastEditedBy, 44 | hasChildren = hasChildren, 45 | parent = parent, 46 | childPage = childPage) 47 | 48 | open class Element @JvmOverloads constructor(var title: String) 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/LinkPreviewBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.users.User 7 | 8 | open class LinkPreviewBlock 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 12 | override val type: BlockType = BlockType.LinkPreview, 13 | override var id: String? = UUID.randomUUID().toString(), 14 | override var createdTime: String? = null, 15 | override var createdBy: User? = null, 16 | override var lastEditedTime: String? = null, 17 | override var lastEditedBy: User? = null, 18 | override var hasChildren: Boolean? = null, 19 | override var archived: Boolean? = null, 20 | override var parent: BlockParent? = null, 21 | val linkPreview: Element? = null, 22 | override val requestId: String? = null, 23 | override var inTrash: Boolean? = null, 24 | ) : Block { 25 | 26 | // for other JVM languages 27 | constructor( 28 | linkPreview: Element, 29 | id: String? = UUID.randomUUID().toString(), 30 | hasChildren: Boolean? = null, 31 | createdTime: String? = null, 32 | createdBy: User? = null, 33 | archived: Boolean? = null, 34 | lastEditedTime: String? = null, 35 | lastEditedBy: User? = null, 36 | parent: BlockParent? = null, 37 | ) : this( 38 | ObjectType.Block, 39 | BlockType.LinkPreview, 40 | id, 41 | createdTime, 42 | createdBy, 43 | lastEditedTime, 44 | lastEditedBy, 45 | hasChildren, 46 | archived, 47 | parent, 48 | linkPreview) 49 | 50 | open class Element 51 | @JvmOverloads 52 | constructor( 53 | val url: String? = null, 54 | ) 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/ChildDatabaseBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.users.User 7 | 8 | open class ChildDatabaseBlock 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 12 | override val type: BlockType = BlockType.ChildDatabase, 13 | override var id: String? = UUID.randomUUID().toString(), 14 | override var createdTime: String? = null, 15 | override var createdBy: User? = null, 16 | override var lastEditedTime: String? = null, 17 | override var lastEditedBy: User? = null, 18 | override var hasChildren: Boolean? = null, 19 | override var archived: Boolean? = null, 20 | override var parent: BlockParent? = null, 21 | val childDatabase: Element, 22 | override val requestId: String? = null, 23 | override var inTrash: Boolean? = null, 24 | ) : Block { 25 | 26 | // for other JVM languages 27 | constructor( 28 | childDatabase: Element, 29 | id: String? = UUID.randomUUID().toString(), 30 | hasChildren: Boolean? = null, 31 | createdTime: String? = null, 32 | createdBy: User? = null, 33 | lastEditedTime: String? = null, 34 | lastEditedBy: User? = null, 35 | parent: BlockParent? = null, 36 | ) : this( 37 | objectType = ObjectType.Block, 38 | type = BlockType.ChildDatabase, 39 | id = id, 40 | createdTime = createdTime, 41 | createdBy = createdBy, 42 | lastEditedTime = lastEditedTime, 43 | lastEditedBy = lastEditedBy, 44 | hasChildren = hasChildren, 45 | parent = parent, 46 | childDatabase = childDatabase, 47 | ) 48 | 49 | open class Element @JvmOverloads constructor(var title: String) 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/TableBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.users.User 7 | 8 | open class TableBlock 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 12 | override val type: BlockType = BlockType.Table, 13 | override var id: String? = UUID.randomUUID().toString(), 14 | override var createdTime: String? = null, 15 | override var createdBy: User? = null, 16 | override var lastEditedTime: String? = null, 17 | override var lastEditedBy: User? = null, 18 | override var hasChildren: Boolean? = null, 19 | override var archived: Boolean? = null, 20 | override var parent: BlockParent? = null, 21 | val table: Element, 22 | override val requestId: String? = null, 23 | override var inTrash: Boolean? = null, 24 | ) : Block { 25 | 26 | // for other JVM languages 27 | constructor( 28 | table: Element, 29 | id: String? = UUID.randomUUID().toString(), 30 | hasChildren: Boolean? = null, 31 | createdTime: String? = null, 32 | createdBy: User? = null, 33 | lastEditedTime: String? = null, 34 | lastEditedBy: User? = null, 35 | parent: BlockParent? = null, 36 | ) : this( 37 | objectType = ObjectType.Block, 38 | type = BlockType.Table, 39 | id = id, 40 | createdTime = createdTime, 41 | createdBy = createdBy, 42 | lastEditedTime = lastEditedTime, 43 | lastEditedBy = lastEditedBy, 44 | hasChildren = hasChildren, 45 | parent = parent, 46 | table = table) 47 | 48 | open class Element 49 | @JvmOverloads 50 | constructor(var tableWidth: Int, var hasColumnHeader: Boolean, var hasRowHeader: Boolean) 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/TableOfContentsBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.users.User 8 | 9 | open class TableOfContentsBlock 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 13 | override val type: BlockType = BlockType.TableOfContents, 14 | override var id: String? = UUID.randomUUID().toString(), 15 | override var createdTime: String? = null, 16 | override var createdBy: User? = null, 17 | override var lastEditedTime: String? = null, 18 | override var lastEditedBy: User? = null, 19 | override var hasChildren: Boolean? = null, 20 | override var archived: Boolean? = null, 21 | override var parent: BlockParent? = null, 22 | val tableOfContents: Element? = null, 23 | override val requestId: String? = null, 24 | override var inTrash: Boolean? = null, 25 | ) : Block { 26 | 27 | // for other JVM languages 28 | constructor( 29 | tableOfContents: Element, 30 | id: String? = UUID.randomUUID().toString(), 31 | hasChildren: Boolean? = null, 32 | createdTime: String? = null, 33 | createdBy: User? = null, 34 | archived: Boolean? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | ObjectType.Block, 40 | BlockType.TableOfContents, 41 | id, 42 | createdTime, 43 | createdBy, 44 | lastEditedTime, 45 | lastEditedBy, 46 | hasChildren, 47 | archived, 48 | parent, 49 | tableOfContents) 50 | 51 | open class Element @JvmOverloads constructor(var color: BlockColor? = null) 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/EmbedBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.pages.PageProperty 7 | import notion.api.v1.model.users.User 8 | 9 | open class EmbedBlock 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 13 | override val type: BlockType = BlockType.Embed, 14 | override var id: String? = UUID.randomUUID().toString(), 15 | override var createdTime: String? = null, 16 | override var createdBy: User? = null, 17 | override var lastEditedTime: String? = null, 18 | override var lastEditedBy: User? = null, 19 | override var hasChildren: Boolean? = null, 20 | override var archived: Boolean? = null, 21 | override var parent: BlockParent? = null, 22 | val embed: Element? = null, 23 | override val requestId: String? = null, 24 | override var inTrash: Boolean? = null, 25 | ) : Block { 26 | 27 | // for other JVM languages 28 | constructor( 29 | embed: Element, 30 | id: String? = UUID.randomUUID().toString(), 31 | hasChildren: Boolean? = null, 32 | createdTime: String? = null, 33 | createdBy: User? = null, 34 | archived: Boolean? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | ObjectType.Block, 40 | BlockType.Embed, 41 | id, 42 | createdTime, 43 | createdBy, 44 | lastEditedTime, 45 | lastEditedBy, 46 | hasChildren, 47 | archived, 48 | parent, 49 | embed) 50 | 51 | open class Element 52 | @JvmOverloads 53 | constructor( 54 | val url: String? = null, 55 | val caption: List? = null, 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/BookmarkBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.pages.PageProperty 7 | import notion.api.v1.model.users.User 8 | 9 | open class BookmarkBlock 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 13 | override val type: BlockType = BlockType.Bookmark, 14 | override var id: String? = UUID.randomUUID().toString(), 15 | override var createdTime: String? = null, 16 | override var createdBy: User? = null, 17 | override var lastEditedTime: String? = null, 18 | override var lastEditedBy: User? = null, 19 | override var hasChildren: Boolean? = null, 20 | override var archived: Boolean? = null, 21 | override var parent: BlockParent? = null, 22 | val bookmark: Element? = null, 23 | override val requestId: String? = null, 24 | override var inTrash: Boolean? = null, 25 | ) : Block { 26 | 27 | // for other JVM languages 28 | constructor( 29 | bookmark: Element, 30 | id: String? = UUID.randomUUID().toString(), 31 | hasChildren: Boolean? = null, 32 | createdTime: String? = null, 33 | createdBy: User? = null, 34 | archived: Boolean? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | ObjectType.Block, 40 | BlockType.Bookmark, 41 | id, 42 | createdTime, 43 | createdBy, 44 | lastEditedTime, 45 | lastEditedBy, 46 | hasChildren, 47 | archived, 48 | parent, 49 | bookmark) 50 | 51 | open class Element 52 | @JvmOverloads 53 | constructor( 54 | val url: String? = null, 55 | val caption: List? = null, 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/TableRowBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.pages.PageProperty 7 | import notion.api.v1.model.users.User 8 | 9 | open class TableRowBlock 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 13 | override val type: BlockType = BlockType.TableRow, 14 | override var id: String? = UUID.randomUUID().toString(), 15 | override var createdTime: String? = null, 16 | override var createdBy: User? = null, 17 | override var lastEditedTime: String? = null, 18 | override var lastEditedBy: User? = null, 19 | override var hasChildren: Boolean? = null, 20 | override var archived: Boolean? = null, 21 | override var parent: BlockParent? = null, 22 | val tableRow: Element, 23 | override val requestId: String? = null, 24 | override var inTrash: Boolean? = null, 25 | ) : Block { 26 | 27 | // for other JVM languages 28 | constructor( 29 | tableRow: Element, 30 | id: String? = UUID.randomUUID().toString(), 31 | hasChildren: Boolean? = null, 32 | createdTime: String? = null, 33 | createdBy: User? = null, 34 | lastEditedTime: String? = null, 35 | lastEditedBy: User? = null, 36 | parent: BlockParent? = null, 37 | ) : this( 38 | objectType = ObjectType.Block, 39 | type = BlockType.TableRow, 40 | id = id, 41 | createdTime = createdTime, 42 | createdBy = createdBy, 43 | lastEditedTime = lastEditedTime, 44 | lastEditedBy = lastEditedBy, 45 | hasChildren = hasChildren, 46 | parent = parent, 47 | tableRow = tableRow) 48 | 49 | open class Element 50 | @JvmOverloads 51 | constructor(var cells: List> = emptyList()) 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/QuoteBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class QuoteBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override val type: BlockType = BlockType.Quote, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | val quote: Element? = null, 24 | override val requestId: String? = null, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | quote: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | archived: Boolean? = null, 36 | lastEditedTime: String? = null, 37 | lastEditedBy: User? = null, 38 | parent: BlockParent? = null, 39 | ) : this( 40 | ObjectType.Block, 41 | BlockType.Quote, 42 | id, 43 | createdTime, 44 | createdBy, 45 | lastEditedTime, 46 | lastEditedBy, 47 | hasChildren, 48 | archived, 49 | parent, 50 | quote) 51 | 52 | open class Element 53 | @JvmOverloads 54 | constructor(var richText: List? = null, var color: BlockColor? = null) 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/SyncedBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.common.SyncedFrom 7 | import notion.api.v1.model.users.User 8 | 9 | open class SyncedBlock 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 13 | override val type: BlockType = BlockType.SyncedBlock, 14 | override var id: String? = UUID.randomUUID().toString(), 15 | override var createdTime: String? = null, 16 | override var createdBy: User? = null, 17 | override var lastEditedTime: String? = null, 18 | override var lastEditedBy: User? = null, 19 | override var hasChildren: Boolean? = null, 20 | override var archived: Boolean? = null, 21 | override var parent: BlockParent? = null, 22 | val syncedBlock: Element? = null, 23 | override val requestId: String? = null, 24 | override var inTrash: Boolean? = null, 25 | ) : Block { 26 | 27 | // for other JVM languages 28 | constructor( 29 | syncedBlock: Element, 30 | id: String? = UUID.randomUUID().toString(), 31 | hasChildren: Boolean? = null, 32 | createdTime: String? = null, 33 | createdBy: User? = null, 34 | archived: Boolean? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | ObjectType.Block, 40 | BlockType.SyncedBlock, 41 | id, 42 | createdTime, 43 | createdBy, 44 | lastEditedTime, 45 | lastEditedBy, 46 | hasChildren, 47 | archived, 48 | parent, 49 | syncedBlock) 50 | 51 | open class Element 52 | @JvmOverloads 53 | constructor( 54 | val syncedFrom: SyncedFrom? = null, 55 | val children: List? = null, 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/TemplateBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.pages.PageProperty 7 | import notion.api.v1.model.users.User 8 | 9 | open class TemplateBlock 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 13 | override val type: BlockType = BlockType.Template, 14 | override var id: String? = UUID.randomUUID().toString(), 15 | override var createdTime: String? = null, 16 | override var createdBy: User? = null, 17 | override var lastEditedTime: String? = null, 18 | override var lastEditedBy: User? = null, 19 | override var hasChildren: Boolean? = null, 20 | override var archived: Boolean? = null, 21 | override var parent: BlockParent? = null, 22 | val template: Element? = null, 23 | override val requestId: String? = null, 24 | override var inTrash: Boolean? = null, 25 | ) : Block { 26 | 27 | // for other JVM languages 28 | constructor( 29 | template: Element, 30 | id: String? = UUID.randomUUID().toString(), 31 | hasChildren: Boolean? = null, 32 | createdTime: String? = null, 33 | createdBy: User? = null, 34 | archived: Boolean? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | ObjectType.Block, 40 | BlockType.Template, 41 | id, 42 | createdTime, 43 | createdBy, 44 | lastEditedTime, 45 | lastEditedBy, 46 | hasChildren, 47 | archived, 48 | parent, 49 | template) 50 | 51 | open class Element 52 | @JvmOverloads 53 | constructor( 54 | var richText: List? = null, 55 | val children: List? = null, 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/endpoint/SearchSupport.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.endpoint 2 | 3 | import notion.api.v1.exception.NotionAPIError 4 | import notion.api.v1.http.NotionHttpClient 5 | import notion.api.v1.json.NotionJsonSerializer 6 | import notion.api.v1.logging.NotionLogger 7 | import notion.api.v1.model.search.SearchResults 8 | import notion.api.v1.request.search.SearchRequest 9 | 10 | interface SearchSupport : EndpointsSupport { 11 | val httpClient: NotionHttpClient 12 | val jsonSerializer: NotionJsonSerializer 13 | val logger: NotionLogger 14 | val baseUrl: String 15 | 16 | // ----------------------------------------------- 17 | // search 18 | // ----------------------------------------------- 19 | 20 | fun search(query: String): SearchResults { 21 | return search(SearchRequest(query = query)) 22 | } 23 | 24 | fun search( 25 | query: String, 26 | filter: SearchRequest.SearchFilter? = null, 27 | sort: SearchRequest.SearchSort? = null, 28 | startCursor: String? = null, 29 | pageSize: Int? = null, 30 | ): SearchResults { 31 | return search( 32 | SearchRequest( 33 | query = query, 34 | filter = filter, 35 | sort = sort, 36 | startCursor = startCursor, 37 | pageSize = pageSize, 38 | )) 39 | } 40 | 41 | fun search(request: SearchRequest): SearchResults { 42 | val httpResponse = 43 | httpClient.postTextBody( 44 | logger = logger, 45 | url = "$baseUrl/search", 46 | body = jsonSerializer.toJsonString(request), 47 | headers = buildRequestHeaders(contentTypeJson())) 48 | if (httpResponse.status == 200) { 49 | return jsonSerializer.toSearchResults(httpResponse.body) 50 | } else { 51 | throw NotionAPIError( 52 | error = jsonSerializer.toError(httpResponse.body), 53 | httpResponse = httpResponse, 54 | ) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/CodeBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ObjectType 6 | import notion.api.v1.model.pages.PageProperty 7 | import notion.api.v1.model.users.User 8 | 9 | open class CodeBlock 10 | @JvmOverloads 11 | constructor( 12 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 13 | override val type: BlockType = BlockType.Code, 14 | override var id: String? = UUID.randomUUID().toString(), 15 | override var createdTime: String? = null, 16 | override var createdBy: User? = null, 17 | override var lastEditedTime: String? = null, 18 | override var lastEditedBy: User? = null, 19 | override var hasChildren: Boolean? = null, 20 | override var archived: Boolean? = null, 21 | override var parent: BlockParent? = null, 22 | val code: Element? = null, 23 | override val requestId: String? = null, 24 | override var inTrash: Boolean? = null, 25 | ) : Block { 26 | 27 | // for other JVM languages 28 | constructor( 29 | code: Element, 30 | id: String? = UUID.randomUUID().toString(), 31 | hasChildren: Boolean? = null, 32 | createdTime: String? = null, 33 | createdBy: User? = null, 34 | archived: Boolean? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | ObjectType.Block, 40 | BlockType.Code, 41 | id, 42 | createdTime, 43 | createdBy, 44 | lastEditedTime, 45 | lastEditedBy, 46 | hasChildren, 47 | archived, 48 | parent, 49 | code) 50 | 51 | open class Element 52 | @JvmOverloads 53 | constructor( 54 | val caption: List? = null, 55 | val richText: List? = null, 56 | val language: String? = null, 57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/VideoBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ExternalFileDetails 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class VideoBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override val type: BlockType = BlockType.Video, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | val video: Element? = null, 24 | override val requestId: String? = null, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | video: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | archived: Boolean? = null, 36 | lastEditedTime: String? = null, 37 | lastEditedBy: User? = null, 38 | parent: BlockParent? = null, 39 | ) : this( 40 | ObjectType.Block, 41 | BlockType.Video, 42 | id, 43 | createdTime, 44 | createdBy, 45 | lastEditedTime, 46 | lastEditedBy, 47 | hasChildren, 48 | archived, 49 | parent, 50 | video) 51 | 52 | open class Element 53 | @JvmOverloads 54 | constructor( 55 | val caption: List? = null, 56 | val type: String? = "external", 57 | val external: ExternalFileDetails? = null, 58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/AudioBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.FileDetails 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class AudioBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override var type: BlockType = BlockType.Audio, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | val audio: Element, 24 | override val requestId: String? = null, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | audio: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | objectType = ObjectType.Block, 40 | type = BlockType.Audio, 41 | id = id, 42 | createdTime = createdTime, 43 | createdBy = createdBy, 44 | lastEditedTime = lastEditedTime, 45 | lastEditedBy = lastEditedBy, 46 | hasChildren = hasChildren, 47 | parent = parent, 48 | audio = audio) 49 | 50 | open class Element 51 | @JvmOverloads 52 | constructor( 53 | val caption: List? = null, 54 | val type: String = "audio", 55 | val file: FileDetails? = null, 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/CalloutBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.Icon 7 | import notion.api.v1.model.common.ObjectType 8 | import notion.api.v1.model.pages.PageProperty 9 | import notion.api.v1.model.users.User 10 | 11 | open class CalloutBlock 12 | @JvmOverloads 13 | constructor( 14 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 15 | override val type: BlockType = BlockType.Callout, 16 | override var id: String? = UUID.randomUUID().toString(), 17 | override var createdTime: String? = null, 18 | override var createdBy: User? = null, 19 | override var lastEditedTime: String? = null, 20 | override var lastEditedBy: User? = null, 21 | override var hasChildren: Boolean? = null, 22 | override var archived: Boolean? = null, 23 | override var parent: BlockParent? = null, 24 | val callout: Element? = null, 25 | override val requestId: String? = null, 26 | override var inTrash: Boolean? = null, 27 | ) : Block { 28 | 29 | // for other JVM languages 30 | constructor( 31 | callout: Element, 32 | id: String? = UUID.randomUUID().toString(), 33 | hasChildren: Boolean? = null, 34 | createdTime: String? = null, 35 | createdBy: User? = null, 36 | archived: Boolean? = null, 37 | lastEditedTime: String? = null, 38 | lastEditedBy: User? = null, 39 | parent: BlockParent? = null, 40 | ) : this( 41 | ObjectType.Block, 42 | BlockType.Callout, 43 | id, 44 | createdTime, 45 | createdBy, 46 | lastEditedTime, 47 | lastEditedBy, 48 | hasChildren, 49 | archived, 50 | parent, 51 | callout) 52 | 53 | open class Element 54 | @JvmOverloads 55 | constructor( 56 | var richText: List? = null, 57 | val icon: Icon? = null, 58 | var color: BlockColor? = null 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/ToggleBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class ToggleBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override val type: BlockType = BlockType.Toggle, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | val toggle: Element, 24 | override val requestId: String? = null, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | toggle: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | objectType = ObjectType.Block, 40 | type = BlockType.Toggle, 41 | id = id, 42 | createdTime = createdTime, 43 | createdBy = createdBy, 44 | lastEditedTime = lastEditedTime, 45 | lastEditedBy = lastEditedBy, 46 | hasChildren = hasChildren, 47 | parent = parent, 48 | toggle = toggle) 49 | 50 | open class Element 51 | @JvmOverloads 52 | constructor( 53 | var richText: List, 54 | var children: List? = null, 55 | var color: BlockColor? = null 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/ParagraphBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class ParagraphBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override var type: BlockType = BlockType.Paragraph, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | val paragraph: Element, 24 | override val requestId: String? = null, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | paragraph: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | objectType = ObjectType.Block, 40 | type = BlockType.Paragraph, 41 | id = id, 42 | createdTime = createdTime, 43 | createdBy = createdBy, 44 | lastEditedTime = lastEditedTime, 45 | lastEditedBy = lastEditedBy, 46 | hasChildren = hasChildren, 47 | parent = parent, 48 | paragraph = paragraph) 49 | 50 | open class Element 51 | @JvmOverloads 52 | constructor( 53 | var richText: List, 54 | var children: List? = null, 55 | var color: BlockColor? = null, 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/endpoint/OAuthSupport.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.endpoint 2 | 3 | import java.util.* 4 | import notion.api.v1.exception.NotionOAuthAPIError 5 | import notion.api.v1.http.NotionHttpClient 6 | import notion.api.v1.json.NotionJsonSerializer 7 | import notion.api.v1.logging.NotionLogger 8 | import notion.api.v1.model.oauth.OAuthTokenResult 9 | import notion.api.v1.request.oauth.ExchangeAuthCodeRequest 10 | 11 | interface OAuthSupport : EndpointsSupport { 12 | val clientId: String? 13 | val clientSecret: String? 14 | val redirectUri: String? 15 | val httpClient: NotionHttpClient 16 | val jsonSerializer: NotionJsonSerializer 17 | val logger: NotionLogger 18 | val baseUrl: String 19 | 20 | fun exchangeAuthCode(code: String, state: String): OAuthTokenResult { 21 | return exchangeAuthCode( 22 | ExchangeAuthCodeRequest( 23 | code = code, 24 | state = state, 25 | redirectUri = this.redirectUri!!, 26 | )) 27 | } 28 | 29 | fun exchangeAuthCode(request: ExchangeAuthCodeRequest): OAuthTokenResult { 30 | if (this.redirectUri == null) { 31 | throw IllegalStateException("Setting redirectUri to NotionClient is required") 32 | } 33 | val base64Value = 34 | String( 35 | Base64.getEncoder() 36 | .encode("${this.clientId}:${this.clientSecret}".toByteArray(Charsets.UTF_8)), 37 | Charsets.UTF_8) 38 | val httpResponse = 39 | httpClient.postTextBody( 40 | logger = logger, 41 | url = "$baseUrl/oauth/token", 42 | body = jsonSerializer.toJsonString(request), 43 | headers = 44 | buildRequestHeaders( 45 | contentTypeJson().plus("Authorization" to "Basic $base64Value"))) 46 | if (httpResponse.status == 200) { 47 | return jsonSerializer.toOAuthTokenResult(httpResponse.body) 48 | } else { 49 | throw NotionOAuthAPIError( 50 | error = jsonSerializer.toOAuthError(httpResponse.body), 51 | httpResponse = httpResponse, 52 | ) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/ToDoBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class ToDoBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override val type: BlockType = BlockType.ToDo, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | override val requestId: String? = null, 24 | val toDo: Element, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | toDo: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | objectType = ObjectType.Block, 40 | type = BlockType.ToDo, 41 | id = id, 42 | createdTime = createdTime, 43 | createdBy = createdBy, 44 | lastEditedTime = lastEditedTime, 45 | lastEditedBy = lastEditedBy, 46 | hasChildren = hasChildren, 47 | parent = parent, 48 | toDo = toDo) 49 | 50 | open class Element 51 | @JvmOverloads 52 | constructor( 53 | var checked: Boolean = false, 54 | var richText: List? = null, 55 | var children: List? = null, 56 | var color: BlockColor? = null 57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/PDFBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ExternalFileDetails 6 | import notion.api.v1.model.common.FileDetails 7 | import notion.api.v1.model.common.ObjectType 8 | import notion.api.v1.model.pages.PageProperty 9 | import notion.api.v1.model.users.User 10 | 11 | open class PDFBlock 12 | @JvmOverloads 13 | constructor( 14 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 15 | override val type: BlockType = BlockType.PDF, 16 | override var id: String? = UUID.randomUUID().toString(), 17 | override var createdTime: String? = null, 18 | override var createdBy: User? = null, 19 | override var lastEditedTime: String? = null, 20 | override var lastEditedBy: User? = null, 21 | override var hasChildren: Boolean? = null, 22 | override var archived: Boolean? = null, 23 | override var parent: BlockParent? = null, 24 | val pdf: Element? = null, 25 | override val requestId: String? = null, 26 | override var inTrash: Boolean? = null, 27 | ) : Block { 28 | 29 | // for other JVM languages 30 | constructor( 31 | pdf: Element, 32 | id: String? = UUID.randomUUID().toString(), 33 | hasChildren: Boolean? = null, 34 | createdTime: String? = null, 35 | createdBy: User? = null, 36 | archived: Boolean? = null, 37 | lastEditedTime: String? = null, 38 | lastEditedBy: User? = null, 39 | parent: BlockParent? = null, 40 | ) : this( 41 | ObjectType.Block, 42 | BlockType.PDF, 43 | id, 44 | createdTime, 45 | createdBy, 46 | lastEditedTime, 47 | lastEditedBy, 48 | hasChildren, 49 | archived, 50 | parent, 51 | pdf) 52 | 53 | open class Element 54 | @JvmOverloads 55 | constructor( 56 | val caption: List? = null, 57 | val type: String? = null, 58 | val file: FileDetails? = null, 59 | val external: ExternalFileDetails? = null, 60 | ) 61 | } 62 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/HeadingTwoBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class HeadingTwoBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override val type: BlockType = BlockType.HeadingTwo, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | @SerializedName("heading_2") val heading2: Element, 24 | override val requestId: String? = null, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | heading2: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | objectType = ObjectType.Block, 40 | type = BlockType.HeadingTwo, 41 | id = id, 42 | createdTime = createdTime, 43 | createdBy = createdBy, 44 | lastEditedTime = lastEditedTime, 45 | lastEditedBy = lastEditedBy, 46 | hasChildren = hasChildren, 47 | parent = parent, 48 | heading2 = heading2) 49 | 50 | open class Element( 51 | var richText: List, 52 | var isToggleable: Boolean? = null, 53 | var color: BlockColor? = null, 54 | var children: List? = null, 55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/ImageBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ExternalFileDetails 6 | import notion.api.v1.model.common.FileDetails 7 | import notion.api.v1.model.common.ObjectType 8 | import notion.api.v1.model.pages.PageProperty 9 | import notion.api.v1.model.users.User 10 | 11 | open class ImageBlock 12 | @JvmOverloads 13 | constructor( 14 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 15 | override val type: BlockType = BlockType.Image, 16 | override var id: String? = UUID.randomUUID().toString(), 17 | override var createdTime: String? = null, 18 | override var createdBy: User? = null, 19 | override var lastEditedTime: String? = null, 20 | override var lastEditedBy: User? = null, 21 | override var hasChildren: Boolean? = null, 22 | override var archived: Boolean? = null, 23 | override var parent: BlockParent? = null, 24 | val image: Element? = null, 25 | override val requestId: String? = null, 26 | override var inTrash: Boolean? = null, 27 | ) : Block { 28 | 29 | // for other JVM languages 30 | constructor( 31 | image: Element, 32 | id: String? = UUID.randomUUID().toString(), 33 | hasChildren: Boolean? = null, 34 | createdTime: String? = null, 35 | createdBy: User? = null, 36 | archived: Boolean? = null, 37 | lastEditedTime: String? = null, 38 | lastEditedBy: User? = null, 39 | parent: BlockParent? = null, 40 | ) : this( 41 | ObjectType.Block, 42 | BlockType.Image, 43 | id, 44 | createdTime, 45 | createdBy, 46 | lastEditedTime, 47 | lastEditedBy, 48 | hasChildren, 49 | archived, 50 | parent, 51 | image) 52 | 53 | open class Element 54 | @JvmOverloads 55 | constructor( 56 | val type: String? = null, 57 | val external: ExternalFileDetails? = null, 58 | val file: FileDetails? = null, 59 | val caption: List? = null, 60 | ) 61 | } 62 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/BulletedListItemBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class BulletedListItemBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override val type: BlockType = BlockType.BulletedListItem, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | val bulletedListItem: Element, 24 | override val requestId: String? = null, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | bulletedListItem: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | objectType = ObjectType.Block, 40 | type = BlockType.BulletedListItem, 41 | id = id, 42 | createdTime = createdTime, 43 | createdBy = createdBy, 44 | lastEditedTime = lastEditedTime, 45 | lastEditedBy = lastEditedBy, 46 | hasChildren = hasChildren, 47 | parent = parent, 48 | bulletedListItem = bulletedListItem) 49 | 50 | open class Element 51 | @JvmOverloads 52 | constructor( 53 | var richText: List, 54 | var children: List? = null, 55 | var color: BlockColor? = null 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/NumberedListItemBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class NumberedListItemBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override val type: BlockType = BlockType.NumberedListItem, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | val numberedListItem: Element, 24 | override val requestId: String? = null, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | numberedListItem: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | objectType = ObjectType.Block, 40 | type = BlockType.NumberedListItem, 41 | id = id, 42 | createdTime = createdTime, 43 | createdBy = createdBy, 44 | lastEditedTime = lastEditedTime, 45 | lastEditedBy = lastEditedBy, 46 | hasChildren = hasChildren, 47 | parent = parent, 48 | numberedListItem = numberedListItem) 49 | 50 | open class Element 51 | @JvmOverloads 52 | constructor( 53 | var richText: List, 54 | var children: List? = null, 55 | var color: BlockColor? = null 56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/BlockType.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | enum class BlockType @JvmOverloads constructor(val value: String) { 6 | @SerializedName("paragraph") Paragraph("paragraph"), 7 | @SerializedName("heading_1") HeadingOne("heading_1"), 8 | @SerializedName("heading_2") HeadingTwo("heading_2"), 9 | @SerializedName("heading_3") HeadingThree("heading_3"), 10 | @SerializedName("bulleted_list_item") BulletedListItem("bulleted_list_item"), 11 | @SerializedName("numbered_list_item") NumberedListItem("numbered_list_item"), 12 | @SerializedName("link_to_page") LinkToPage("link_to_page"), 13 | @SerializedName("link_preview") LinkPreview("link_preview"), 14 | @SerializedName("equation") Equation("equation"), 15 | @SerializedName("bookmark") Bookmark("bookmark"), 16 | @SerializedName("callout") Callout("callout"), 17 | @SerializedName("column") Column("column"), 18 | @SerializedName("column_list") ColumnList("column_list"), 19 | @SerializedName("breadcrumb") Breadcrumb("breadcrumb"), 20 | @SerializedName("table_of_contents") TableOfContents("table_of_contents"), 21 | @SerializedName("divider") Divider("divider"), 22 | @SerializedName("video") Video("video"), 23 | @SerializedName("quote") Quote("quote"), 24 | @SerializedName("to_do") ToDo("to_do"), 25 | @SerializedName("toggle") Toggle("toggle"), 26 | @SerializedName("code") Code("code"), 27 | @SerializedName("embed") Embed("embed"), 28 | @SerializedName("image") Image("image"), 29 | @SerializedName("file") File("file"), 30 | @SerializedName("pdf") PDF("pdf"), 31 | @SerializedName("child_page") ChildPage("child_page"), 32 | @SerializedName("child_database") ChildDatabase("child_database"), 33 | @SerializedName("synced_block") SyncedBlock("synced_block"), 34 | @SerializedName("table") Table("table"), 35 | @SerializedName("table_row") TableRow("table_row"), 36 | @SerializedName("template") Template("template"), 37 | @SerializedName("audio") Audio("audio"), 38 | @SerializedName("unsupported") Unsupported("unsupported"); 39 | 40 | override fun toString(): String = value 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/HeadingOneBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class HeadingOneBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override val type: BlockType = BlockType.HeadingOne, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | @SerializedName("heading_1") val heading1: Element, 24 | override val requestId: String? = null, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | heading1: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | objectType = ObjectType.Block, 40 | type = BlockType.HeadingOne, 41 | id = id, 42 | createdTime = createdTime, 43 | createdBy = createdBy, 44 | lastEditedTime = lastEditedTime, 45 | lastEditedBy = lastEditedBy, 46 | hasChildren = hasChildren, 47 | parent = parent, 48 | heading1 = heading1) 49 | 50 | open class Element 51 | @JvmOverloads 52 | constructor( 53 | var richText: List, 54 | var isToggleable: Boolean? = null, 55 | var color: BlockColor? = null, 56 | var children: List? = null, 57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/HeadingThreeBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.BlockColor 6 | import notion.api.v1.model.common.ObjectType 7 | import notion.api.v1.model.pages.PageProperty 8 | import notion.api.v1.model.users.User 9 | 10 | open class HeadingThreeBlock 11 | @JvmOverloads 12 | constructor( 13 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 14 | override val type: BlockType = BlockType.HeadingThree, 15 | override var id: String? = UUID.randomUUID().toString(), 16 | override var createdTime: String? = null, 17 | override var createdBy: User? = null, 18 | override var lastEditedTime: String? = null, 19 | override var lastEditedBy: User? = null, 20 | override var hasChildren: Boolean? = null, 21 | override var archived: Boolean? = null, 22 | override var parent: BlockParent? = null, 23 | @SerializedName("heading_3") val heading3: Element, 24 | override val requestId: String? = null, 25 | override var inTrash: Boolean? = null, 26 | ) : Block { 27 | 28 | // for other JVM languages 29 | constructor( 30 | heading3: Element, 31 | id: String? = UUID.randomUUID().toString(), 32 | hasChildren: Boolean? = null, 33 | createdTime: String? = null, 34 | createdBy: User? = null, 35 | lastEditedTime: String? = null, 36 | lastEditedBy: User? = null, 37 | parent: BlockParent? = null, 38 | ) : this( 39 | objectType = ObjectType.Block, 40 | type = BlockType.HeadingThree, 41 | id = id, 42 | createdTime = createdTime, 43 | createdBy = createdBy, 44 | lastEditedTime = lastEditedTime, 45 | lastEditedBy = lastEditedBy, 46 | hasChildren = hasChildren, 47 | parent = parent, 48 | heading3 = heading3) 49 | 50 | open class Element 51 | @JvmOverloads 52 | constructor( 53 | var richText: List, 54 | var isToggleable: Boolean? = null, 55 | var color: BlockColor? = null, 56 | var children: List? = null, 57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/blocks/FileBlock.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.blocks 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import java.util.* 5 | import notion.api.v1.model.common.ExternalFileDetails 6 | import notion.api.v1.model.common.FileDetails 7 | import notion.api.v1.model.common.ObjectType 8 | import notion.api.v1.model.pages.PageProperty 9 | import notion.api.v1.model.users.User 10 | 11 | open class FileBlock 12 | @JvmOverloads 13 | constructor( 14 | @SerializedName("object") override val objectType: ObjectType = ObjectType.Block, 15 | override val type: BlockType = BlockType.File, 16 | override var id: String? = UUID.randomUUID().toString(), 17 | override var createdTime: String? = null, 18 | override var createdBy: User? = null, 19 | override var lastEditedTime: String? = null, 20 | override var lastEditedBy: User? = null, 21 | override var hasChildren: Boolean? = null, 22 | override var archived: Boolean? = null, 23 | override var parent: BlockParent? = null, 24 | val file: Element? = null, 25 | override val requestId: String? = null, 26 | override var inTrash: Boolean? = null, 27 | ) : Block { 28 | 29 | // for other JVM languages 30 | constructor( 31 | file: Element, 32 | id: String? = UUID.randomUUID().toString(), 33 | hasChildren: Boolean? = null, 34 | createdTime: String? = null, 35 | createdBy: User? = null, 36 | archived: Boolean? = null, 37 | lastEditedTime: String? = null, 38 | lastEditedBy: User? = null, 39 | parent: BlockParent? = null, 40 | ) : this( 41 | ObjectType.Block, 42 | BlockType.File, 43 | id, 44 | createdTime, 45 | createdBy, 46 | lastEditedTime, 47 | lastEditedBy, 48 | hasChildren, 49 | archived, 50 | parent, 51 | file) 52 | 53 | open class Element 54 | @JvmOverloads 55 | constructor( 56 | val caption: List? = null, 57 | val type: String? = null, // "file", "external", 58 | val name: String? = null, 59 | val file: FileDetails? = null, 60 | val external: ExternalFileDetails? = null, 61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /core/src/test/kotlin/tests/model/SearchResultTest.kt: -------------------------------------------------------------------------------- 1 | package tests.model 2 | 3 | import kotlin.test.assertNotNull 4 | import notion.api.v1.json.GsonSerializer 5 | import org.junit.Test 6 | 7 | class SearchResultTest { 8 | @Test 9 | fun parse() { 10 | val serializer = GsonSerializer(true) 11 | val searchResults = serializer.toSearchResults(json) 12 | assertNotNull(searchResults) 13 | } 14 | 15 | private val json = 16 | """ 17 | { 18 | "object": "list", 19 | "results": [ 20 | { 21 | "object": "page", 22 | "id": "4ca9549a-9ec4-4e1f-846d-6c37f4313687", 23 | "created_time": "2021-05-16T13:09:31.119Z", 24 | "last_edited_time": "2021-05-16T13:31:00.000Z", 25 | "parent": { 26 | "type": "database_id", 27 | "database_id": "dfd4ecb5-2d43-443e-97eb-4700db2c4f75" 28 | }, 29 | "archived": false, 30 | "properties": { 31 | "Done": { 32 | "id": ":APL" 33 | }, 34 | "Link": { 35 | "id": "Jf>F" 36 | }, 37 | "Phone Number": { 38 | "id": "MyWZ" 39 | }, 40 | "Velocity Points": { 41 | "id": "SIsY" 42 | }, 43 | "Assignee": { 44 | "id": "ZKb?" 45 | }, 46 | "Last Edited Time": { 47 | "id": "ZMd=" 48 | }, 49 | "Created Time": { 50 | "id": "ZSgO" 51 | }, 52 | "Tags": { 53 | "id": "[r|\\" 54 | }, 55 | "Description": { 56 | "id": "_;qC" 57 | }, 58 | "Last Editor": { 59 | "id": "`Jbr" 60 | }, 61 | "Contact": { 62 | "id": "fIt_" 63 | }, 64 | "Attachments": { 65 | "id": "hhy?" 66 | }, 67 | "Task List Relation": { 68 | "id": "i[;j" 69 | }, 70 | "Due": { 71 | "id": "j=nT" 72 | }, 73 | "Severity": { 74 | "id": "lZ`?" 75 | }, 76 | "Creator": { 77 | "id": "m`c{" 78 | }, 79 | "Column": { 80 | "id": "q=>K" 81 | }, 82 | "Title": { 83 | "id": "title" 84 | } 85 | } 86 | } 87 | ], 88 | "next_cursor": null, 89 | "has_more": false 90 | } 91 | """.trimIndent() 92 | } 93 | -------------------------------------------------------------------------------- /core/src/test/kotlin/tests/java_compatibility/RequestsTest.java: -------------------------------------------------------------------------------- 1 | package tests.java_compatibility; 2 | 3 | import notion.api.v1.model.pages.PageParent; 4 | import notion.api.v1.model.pages.PageParentType; 5 | import notion.api.v1.request.blocks.AppendBlockChildrenRequest; 6 | import notion.api.v1.request.blocks.RetrieveBlockChildrenRequest; 7 | import notion.api.v1.request.databases.ListDatabasesRequest; 8 | import notion.api.v1.request.databases.QueryDatabaseRequest; 9 | import notion.api.v1.request.databases.RetrieveDatabaseRequest; 10 | import notion.api.v1.request.pages.CreatePageRequest; 11 | import notion.api.v1.request.pages.RetrievePageRequest; 12 | import notion.api.v1.request.pages.UpdatePageRequest; 13 | import notion.api.v1.request.search.SearchRequest; 14 | import notion.api.v1.request.users.RetrieveUserRequest; 15 | import org.junit.Test; 16 | 17 | import java.util.Collections; 18 | 19 | import static org.junit.Assert.assertNotNull; 20 | 21 | public class RequestsTest { 22 | 23 | @Test 24 | public void instantiateWithRequiredArgs() { 25 | assertNotNull(new AppendBlockChildrenRequest("database-id", Collections.emptyList())); 26 | 27 | assertNotNull(new RetrieveBlockChildrenRequest("database-id")); 28 | 29 | assertNotNull(new ListDatabasesRequest()); 30 | 31 | assertNotNull(new QueryDatabaseRequest("database-id")); 32 | 33 | assertNotNull(new RetrieveDatabaseRequest("database-id")); 34 | 35 | assertNotNull(new CreatePageRequest(new PageParent(PageParentType.DatabaseId), Collections.emptyMap())); 36 | assertNotNull(new CreatePageRequest(PageParent.database("database-id"), Collections.emptyMap())); 37 | assertNotNull(new CreatePageRequest(PageParent.page("page-id"), Collections.emptyMap())); 38 | 39 | assertNotNull(new RetrievePageRequest("page-id")); 40 | 41 | assertNotNull(new UpdatePageRequest("page-id", Collections.emptyMap())); 42 | 43 | assertNotNull(new SearchRequest("query")); 44 | assertNotNull(new SearchRequest("query", new SearchRequest.SearchFilter())); 45 | assertNotNull(new SearchRequest("query", new SearchRequest.SearchFilter(), new SearchRequest.SearchSort())); 46 | assertNotNull(new SearchRequest("query")); 47 | 48 | assertNotNull(new RetrieveUserRequest("user-id")); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/NotionClient.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1 2 | 3 | import java.io.Closeable 4 | import notion.api.v1.endpoint.* 5 | import notion.api.v1.http.HttpUrlConnNotionHttpClient 6 | import notion.api.v1.http.NotionHttpClient 7 | import notion.api.v1.json.GsonSerializer 8 | import notion.api.v1.json.NotionJsonSerializer 9 | import notion.api.v1.logging.NotionLogger 10 | import notion.api.v1.logging.StdoutLogger 11 | 12 | class NotionClient 13 | // We don't intentionally use @JvmOverloads here. Refer to the following constructors for details. 14 | // @JvmOverloads 15 | constructor( 16 | override var token: String? = null, 17 | override var clientId: String? = null, 18 | override var clientSecret: String? = null, 19 | override var redirectUri: String? = null, 20 | override var httpClient: NotionHttpClient = defaultHttpClient, 21 | override var logger: NotionLogger = defaultLogger, 22 | override var jsonSerializer: NotionJsonSerializer = defaultJsonSerializer, 23 | override var baseUrl: String = defaultBaseUrl, 24 | ) : 25 | AutoCloseable, 26 | Closeable, 27 | DatabasesSupport, 28 | PagesSupport, 29 | BlocksSupport, 30 | CommentsSupport, 31 | SearchSupport, 32 | UsersSupport, 33 | OAuthSupport { 34 | 35 | // Internal app initialization 36 | // This constructor is for Java and other languages 37 | constructor( 38 | token: String 39 | ) : this( 40 | token = token, 41 | clientId = null, 42 | clientSecret = null, 43 | redirectUri = null, 44 | ) 45 | 46 | // OAuth wired app initialization 47 | // This constructor is for Java and other languages 48 | constructor( 49 | clientId: String, 50 | clientSecret: String, 51 | redirectUri: String 52 | ) : this( 53 | token = null, 54 | clientId = clientId, 55 | clientSecret = clientSecret, 56 | redirectUri = redirectUri, 57 | ) 58 | 59 | companion object { 60 | @JvmStatic val defaultBaseUrl: String = "https://api.notion.com/v1" 61 | @JvmStatic val defaultHttpClient: NotionHttpClient = HttpUrlConnNotionHttpClient() 62 | @JvmStatic val defaultLogger: NotionLogger = StdoutLogger() 63 | @JvmStatic val defaultJsonSerializer: NotionJsonSerializer = GsonSerializer() 64 | } 65 | 66 | override fun close() { 67 | httpClient.close() 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/json/NotionJsonSerializer.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.json 2 | 3 | import notion.api.v1.model.blocks.Block 4 | import notion.api.v1.model.blocks.Blocks 5 | import notion.api.v1.model.comments.Comment 6 | import notion.api.v1.model.comments.Comments 7 | import notion.api.v1.model.databases.Database 8 | import notion.api.v1.model.databases.Databases 9 | import notion.api.v1.model.databases.QueryResults 10 | import notion.api.v1.model.error.Error 11 | import notion.api.v1.model.error.OAuthError 12 | import notion.api.v1.model.oauth.OAuthTokenResult 13 | import notion.api.v1.model.pages.Page 14 | import notion.api.v1.model.pages.PagePropertyItem 15 | import notion.api.v1.model.search.SearchResults 16 | import notion.api.v1.model.users.User 17 | import notion.api.v1.model.users.Users 18 | import notion.api.v1.request.blocks.AppendBlockChildrenRequest 19 | import notion.api.v1.request.comments.CreateCommentRequest 20 | import notion.api.v1.request.databases.CreateDatabaseRequest 21 | import notion.api.v1.request.databases.QueryDatabaseRequest 22 | import notion.api.v1.request.databases.UpdateDatabaseRequest 23 | import notion.api.v1.request.oauth.ExchangeAuthCodeRequest 24 | import notion.api.v1.request.pages.CreatePageRequest 25 | import notion.api.v1.request.pages.UpdatePageRequest 26 | import notion.api.v1.request.search.SearchRequest 27 | 28 | interface NotionJsonSerializer { 29 | 30 | fun toBlock(body: String): Block 31 | fun toBlocks(body: String): Blocks 32 | fun toComment(body: String): Comment 33 | fun toComments(body: String): Comments 34 | fun toDatabase(body: String): Database 35 | fun toDatabases(body: String): Databases 36 | fun toError(body: String): Error 37 | fun toOAuthError(body: String): OAuthError 38 | fun toPage(body: String): Page 39 | fun toPagePropertyItem(body: String): PagePropertyItem 40 | fun toQueryResults(body: String): QueryResults 41 | fun toSearchResults(body: String): SearchResults 42 | fun toOAuthTokenResult(body: String): OAuthTokenResult 43 | fun toUser(body: String): User 44 | fun toUsers(body: String): Users 45 | 46 | fun toJsonString(request: CreateDatabaseRequest): String 47 | fun toJsonString(request: UpdateDatabaseRequest): String 48 | fun toJsonString(blockProperties: Map): String 49 | fun toJsonString(request: AppendBlockChildrenRequest): String 50 | fun toJsonString(request: CreatePageRequest): String 51 | fun toJsonString(request: CreateCommentRequest): String 52 | fun toJsonString(request: SearchRequest): String 53 | fun toJsonString(request: QueryDatabaseRequest): String 54 | fun toJsonString(request: UpdatePageRequest): String 55 | fun toJsonString(request: ExchangeAuthCodeRequest): String 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/http/NotionHttpClient.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.http 2 | 3 | import java.io.Closeable 4 | import java.net.URLEncoder 5 | import notion.api.v1.logging.NotionLogger 6 | 7 | interface NotionHttpClient : AutoCloseable, Closeable { 8 | 9 | fun get( 10 | logger: NotionLogger, 11 | url: String, 12 | query: Map> = emptyMap(), 13 | headers: Map, 14 | ): NotionHttpResponse 15 | 16 | fun postTextBody( 17 | logger: NotionLogger, 18 | url: String, 19 | query: Map> = emptyMap(), 20 | body: String, 21 | headers: Map 22 | ): NotionHttpResponse 23 | 24 | fun patchTextBody( 25 | logger: NotionLogger, 26 | url: String, 27 | query: Map> = emptyMap(), 28 | body: String, 29 | headers: Map 30 | ): NotionHttpResponse 31 | 32 | fun delete( 33 | logger: NotionLogger, 34 | url: String, 35 | query: Map> = emptyMap(), 36 | headers: Map, 37 | ): NotionHttpResponse 38 | 39 | override fun close() {} 40 | 41 | // ------------------------------ 42 | 43 | fun urlEncode(value: String): String = URLEncoder.encode(value, "UTF-8") 44 | 45 | fun buildQueryString(query: Map>) = 46 | query 47 | .map { params -> 48 | params.value.joinToString(separator = "&") { 49 | "${urlEncode(params.key)}=${urlEncode(it)}" 50 | } 51 | } 52 | .joinToString(prefix = "?", separator = "&") 53 | 54 | fun buildFullUrl(url: String, q: String) = url + if (q != "?") q else "" 55 | 56 | fun debugLogStart( 57 | logger: NotionLogger, 58 | method: String, 59 | fullUrl: String, 60 | body: String?, 61 | ) { 62 | if (logger.isDebugEnabled()) { 63 | val b = if (body == null || body.isEmpty()) "" else "body $body\n" 64 | logger.debug("""Sending a request: 65 | $method $fullUrl 66 | $b 67 | """.trimIndent().trimMargin()) 68 | } 69 | } 70 | 71 | fun debugLogSuccess(logger: NotionLogger, startTimeMillis: Long, response: NotionHttpResponse) { 72 | if (logger.isDebugEnabled()) { 73 | val responseTimeMillis = System.currentTimeMillis() - startTimeMillis 74 | logger.debug( 75 | """Received a response ($responseTimeMillis millis): 76 | status ${response.status} 77 | body ${response.body} 78 | """ 79 | .trimIndent() 80 | .trimMargin()) 81 | } 82 | } 83 | 84 | fun warnLogFailure(logger: NotionLogger, e: Exception) { 85 | logger.warn("Failed to disconnect from Notion: ${e.message}", e) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/pages/PagePropertyItem.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.pages 2 | 3 | import com.google.gson.annotations.SerializedName 4 | import notion.api.v1.model.common.* 5 | import notion.api.v1.model.databases.DatabaseProperty 6 | import notion.api.v1.model.users.User 7 | 8 | data class PagePropertyItem 9 | @JvmOverloads 10 | constructor( 11 | @SerializedName("object") 12 | val objectType: ObjectType = ObjectType.PropertyItem, // "property_item" or "list" 13 | val type: PropertyType = PropertyType.PropertyItem, // can be "property_item" 14 | val results: List? = null, // for pagination 15 | val nextCursor: String? = null, // for pagination 16 | val hasMore: Boolean? = null, // for pagination 17 | val propertyItem: Element? = null, 18 | var id: String? = null, 19 | var title: PageProperty.RichText? = null, 20 | var richText: PageProperty.RichText? = null, 21 | var select: DatabaseProperty.Select.Option? = null, 22 | var multiSelect: List? = null, 23 | var number: Number? = null, 24 | var date: PageProperty.Date? = null, 25 | var people: List? = null, 26 | var checkbox: Boolean? = null, 27 | var url: String? = null, 28 | var phoneNumber: String? = null, 29 | var email: String? = null, 30 | var files: List? = null, 31 | var relation: List? = null, 32 | var formula: PageProperty.Formula? = null, 33 | var rollup: PageProperty.Rollup? = null, 34 | val createdBy: User? = null, 35 | val lastEditedBy: User? = null, 36 | val createdTime: String? = null, 37 | val lastEditedTime: String? = null, 38 | val requestId: String? = null, 39 | ) { 40 | data class Element( 41 | val type: PropertyType, // can be "property_item" 42 | val nextUrl: String, 43 | var id: String? = null, 44 | var title: PageProperty.RichText? = null, 45 | var richText: PageProperty.RichText? = null, 46 | var select: DatabaseProperty.Select.Option? = null, 47 | var multiSelect: List? = null, 48 | var number: Number? = null, 49 | var date: PageProperty.Date? = null, 50 | var people: List? = null, 51 | var checkbox: Boolean? = null, 52 | var url: String? = null, 53 | var phoneNumber: String? = null, 54 | var email: String? = null, 55 | var files: List? = null, 56 | var relation: List? = null, 57 | var formula: PageProperty.Formula? = null, 58 | var rollup: PageProperty.Rollup? = null, 59 | val createdBy: User? = null, 60 | val lastEditedBy: User? = null, 61 | val createdTime: String? = null, 62 | val lastEditedTime: String? = null 63 | ) 64 | } 65 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/model/databases/DatabasePropertySchema.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.model.databases 2 | 3 | import notion.api.v1.model.common.OptionColor 4 | 5 | interface DatabasePropertySchema 6 | 7 | open class TitlePropertySchema @JvmOverloads constructor(val title: Map = emptyMap()) : 8 | DatabasePropertySchema 9 | 10 | open class RichTextPropertySchema 11 | @JvmOverloads 12 | constructor(val richText: Map = emptyMap()) : DatabasePropertySchema 13 | 14 | open class NumberPropertySchema @JvmOverloads constructor(val number: Number = Number()) : 15 | DatabasePropertySchema { 16 | open class Number(val format: String? = null) 17 | } 18 | 19 | open class SelectOptionSchema 20 | @JvmOverloads 21 | constructor(val name: String, val color: OptionColor? = null, val id: String? = null) 22 | 23 | open class SelectPropertySchema 24 | @JvmOverloads 25 | constructor(select: List? = null) : DatabasePropertySchema { 26 | val select = mapOf("options" to select) 27 | } 28 | 29 | open class MultiSelectPropertySchema 30 | @JvmOverloads 31 | constructor(multiSelect: List? = null) : DatabasePropertySchema { 32 | val multiSelect = mapOf("options" to multiSelect) 33 | } 34 | 35 | class DatePropertySchema @JvmOverloads constructor(val date: Map = emptyMap()) : 36 | DatabasePropertySchema 37 | 38 | open class PeoplePropertySchema 39 | @JvmOverloads 40 | constructor(val people: Map = emptyMap()) : DatabasePropertySchema 41 | 42 | open class FilePropertySchema @JvmOverloads constructor(val files: Map = emptyMap()) : 43 | DatabasePropertySchema 44 | 45 | open class CheckboxPropertySchema 46 | @JvmOverloads 47 | constructor(val checkbox: Map = emptyMap()) : DatabasePropertySchema 48 | 49 | open class URLPropertySchema @JvmOverloads constructor(val url: Map = emptyMap()) : 50 | DatabasePropertySchema 51 | 52 | open class EmailPropertySchema @JvmOverloads constructor(val email: Map = emptyMap()) : 53 | DatabasePropertySchema 54 | 55 | open class PhoneNumberPropertySchema 56 | @JvmOverloads 57 | constructor(val phoneNumber: Map = emptyMap()) : DatabasePropertySchema 58 | 59 | open class CreatedTimePropertySchema 60 | @JvmOverloads 61 | constructor(val createdTime: Map = emptyMap()) : DatabasePropertySchema 62 | 63 | open class CreatedByPropertySchema 64 | @JvmOverloads 65 | constructor(val createdBy: Map = emptyMap()) : DatabasePropertySchema 66 | 67 | open class LastEditedTimePropertySchema 68 | @JvmOverloads 69 | constructor(val lastEditedTime: Map = emptyMap()) : DatabasePropertySchema 70 | 71 | open class LastEditedByPropertySchema 72 | @JvmOverloads 73 | constructor(val lastEditedBy: Map = emptyMap()) : DatabasePropertySchema 74 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/endpoint/CommentsSupport.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.endpoint 2 | 3 | import notion.api.v1.exception.NotionAPIError 4 | import notion.api.v1.http.NotionHttpClient 5 | import notion.api.v1.json.NotionJsonSerializer 6 | import notion.api.v1.logging.NotionLogger 7 | import notion.api.v1.model.comments.* 8 | import notion.api.v1.model.pages.PageParent 9 | import notion.api.v1.model.pages.PageProperty 10 | import notion.api.v1.request.comments.* 11 | 12 | interface CommentsSupport : EndpointsSupport { 13 | val httpClient: NotionHttpClient 14 | val jsonSerializer: NotionJsonSerializer 15 | val logger: NotionLogger 16 | val baseUrl: String 17 | 18 | // ----------------------------------------------- 19 | // createComment 20 | // ----------------------------------------------- 21 | 22 | fun createComment(parent: PageParent, richText: List): Comment { 23 | return createComment(CreateCommentRequest(parent = parent, richText = richText)) 24 | } 25 | fun createComment(discussionId: String, richText: List): Comment { 26 | return createComment(CreateCommentRequest(discussionId = discussionId, richText = richText)) 27 | } 28 | 29 | fun createComment(comment: CreateCommentRequest): Comment { 30 | val httpResponse = 31 | httpClient.postTextBody( 32 | logger = logger, 33 | url = "$baseUrl/comments", 34 | body = jsonSerializer.toJsonString(comment), 35 | headers = buildRequestHeaders(contentTypeJson())) 36 | if (httpResponse.status == 200) { 37 | return jsonSerializer.toComment(httpResponse.body) 38 | } else { 39 | throw NotionAPIError( 40 | error = jsonSerializer.toError(httpResponse.body), 41 | httpResponse = httpResponse, 42 | ) 43 | } 44 | } 45 | 46 | // ----------------------------------------------- 47 | // retrieveComments 48 | // ----------------------------------------------- 49 | 50 | fun retrieveComments( 51 | blockId: String, 52 | pageSize: Int? = null, 53 | ): Comments { 54 | return retrieveComments(RetrieveCommentsRequest(blockId = blockId, pageSize = pageSize)) 55 | } 56 | 57 | fun retrieveComments( 58 | blockId: String, 59 | startCursor: String? = null, 60 | pageSize: Int? = null, 61 | ): Comments { 62 | return retrieveComments( 63 | RetrieveCommentsRequest(blockId = blockId, startCursor = startCursor, pageSize = pageSize)) 64 | } 65 | 66 | fun retrieveComments(request: RetrieveCommentsRequest): Comments { 67 | val httpResponse = 68 | httpClient.get( 69 | logger = logger, 70 | url = "$baseUrl/comments", 71 | query = request.toQuery(), 72 | headers = buildRequestHeaders(emptyMap())) 73 | if (httpResponse.status == 200) { 74 | return jsonSerializer.toComments(httpResponse.body) 75 | } else { 76 | throw NotionAPIError( 77 | error = jsonSerializer.toError(httpResponse.body), 78 | httpResponse = httpResponse, 79 | ) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/endpoint/UsersSupport.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.endpoint 2 | 3 | import notion.api.v1.exception.NotionAPIError 4 | import notion.api.v1.http.NotionHttpClient 5 | import notion.api.v1.json.NotionJsonSerializer 6 | import notion.api.v1.logging.NotionLogger 7 | import notion.api.v1.model.users.User 8 | import notion.api.v1.model.users.Users 9 | import notion.api.v1.request.users.ListUsersRequest 10 | import notion.api.v1.request.users.RetrieveUserRequest 11 | 12 | interface UsersSupport : EndpointsSupport { 13 | val httpClient: NotionHttpClient 14 | val jsonSerializer: NotionJsonSerializer 15 | val logger: NotionLogger 16 | val baseUrl: String 17 | 18 | // ----------------------------------------------- 19 | // retrieveBotUser 20 | // ----------------------------------------------- 21 | 22 | fun retrieveBotUser(): User { 23 | val httpResponse = 24 | httpClient.get( 25 | logger = logger, url = "$baseUrl/users/me", headers = buildRequestHeaders(emptyMap())) 26 | if (httpResponse.status == 200) { 27 | return jsonSerializer.toUser(httpResponse.body) 28 | } else { 29 | throw NotionAPIError( 30 | error = jsonSerializer.toError(httpResponse.body), 31 | httpResponse = httpResponse, 32 | ) 33 | } 34 | } 35 | 36 | // ----------------------------------------------- 37 | // retrieveUser 38 | // ----------------------------------------------- 39 | 40 | fun retrieveUser(userId: String): User { 41 | return retrieveUser(RetrieveUserRequest(userId)) 42 | } 43 | 44 | fun retrieveUser(request: RetrieveUserRequest): User { 45 | val httpResponse = 46 | httpClient.get( 47 | logger = logger, 48 | url = "$baseUrl/users/${urlEncode(request.userId)}", 49 | headers = buildRequestHeaders(emptyMap())) 50 | if (httpResponse.status == 200) { 51 | return jsonSerializer.toUser(httpResponse.body) 52 | } else { 53 | throw NotionAPIError( 54 | error = jsonSerializer.toError(httpResponse.body), 55 | httpResponse = httpResponse, 56 | ) 57 | } 58 | } 59 | 60 | // ----------------------------------------------- 61 | // listUsers 62 | // ----------------------------------------------- 63 | 64 | fun listUsers(): Users { 65 | return listUsers(ListUsersRequest(null, null)) 66 | } 67 | 68 | fun listUsers(pageSize: Int? = null, startCursor: String? = null): Users { 69 | return listUsers(ListUsersRequest(startCursor = startCursor, pageSize = pageSize)) 70 | } 71 | 72 | fun listUsers(request: ListUsersRequest): Users { 73 | val httpResponse = 74 | httpClient.get( 75 | logger = logger, 76 | url = "$baseUrl/users", 77 | query = request.buildPaginationParams(), 78 | headers = buildRequestHeaders(emptyMap())) 79 | if (httpResponse.status == 200) { 80 | return jsonSerializer.toUsers(httpResponse.body) 81 | } else { 82 | throw NotionAPIError( 83 | error = jsonSerializer.toError(httpResponse.body), 84 | httpResponse = httpResponse, 85 | ) 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/json/gson/GsonUnknownFieldDetection.kt: -------------------------------------------------------------------------------- 1 | package notion.api.v1.json.gson 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.JsonParseException 5 | import com.google.gson.TypeAdapter 6 | import com.google.gson.TypeAdapterFactory 7 | import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory 8 | import com.google.gson.reflect.TypeToken 9 | import java.lang.reflect.Field 10 | 11 | class GsonUnknownFieldDetection : TypeAdapterFactory { 12 | 13 | override fun create(gson: Gson, type: TypeToken?): TypeAdapter? { 14 | // If the type adapter is a reflective type adapter, we want to modify the implementation using 15 | // reflection. The trick is to replace the Map object used to look up the property name. Instead 16 | // of returning null if the property is not found, 17 | // we throw a Json exception to terminate the deserialization. 18 | val delegate = gson.getDelegateAdapter(this, type) 19 | 20 | // Check if the type adapter is a reflective, cause this solution only work for reflection. 21 | if (delegate is ReflectiveTypeAdapterFactory.Adapter<*, *>) { 22 | 23 | // This code is only compatible with GSON 2.11.0+ 24 | try { 25 | var adaptorClass: Class<*> = delegate.javaClass 26 | var fieldsDataField: Field? = null 27 | while (fieldsDataField == null && adaptorClass != Any::class.java) { 28 | try { 29 | fieldsDataField = adaptorClass.getDeclaredField("fieldsData") 30 | } catch (_ignore: NoSuchFieldException) { 31 | // Since GSON v2.10, the internal class hierarchy has been changed 32 | // 1) com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$FieldReflectionAdapter 33 | // 2) com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter 34 | adaptorClass = adaptorClass.superclass 35 | } 36 | } 37 | if (fieldsDataField == null) { 38 | val message = "Failed to access fieldsData inside the GSON library" 39 | throw IllegalStateException(message) 40 | } 41 | fieldsDataField.isAccessible = true 42 | val fieldData = fieldsDataField[delegate] 43 | val deserializedFieldsField = fieldData.javaClass.getDeclaredField("deserializedFields") 44 | deserializedFieldsField.isAccessible = true 45 | var deserializedFields = deserializedFieldsField[fieldData] as Map 46 | val sb = StringBuilder() 47 | for (key in deserializedFields.keys) { 48 | sb.append("$key, ") 49 | } 50 | val boundFieldsStr = sb.append("... (" + type!!.type.typeName + ")").toString() 51 | // Then replace it with our implementation throwing exception if the value is null. 52 | deserializedFields = 53 | object : LinkedHashMap(deserializedFields) { 54 | override fun get(key: String): Any { 55 | return super.get(key) 56 | ?: throw JsonParseException( 57 | "Unknown property detected: $key in $boundFieldsStr") 58 | } 59 | } 60 | // Finally, push our custom map back using reflection. 61 | deserializedFieldsField[fieldData] = deserializedFields 62 | } catch (e: Exception) { 63 | // Should never happen if the implementation doesn't change. 64 | throw IllegalStateException(e) 65 | } 66 | } 67 | return delegate 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /core/src/main/kotlin/notion/api/v1/http/HttpUrlConnPatchMethodWorkaround.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program and the accompanying materials are made available under the 5 | * terms of the Eclipse Public License v. 2.0, which is available at 6 | * http://www.eclipse.org/legal/epl-2.0. 7 | * 8 | * This Source Code may also be made available under the following Secondary 9 | * Licenses when the conditions for such availability set forth in the 10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, 11 | * version 2 with the GNU Classpath Exception, which is available at 12 | * https://www.gnu.org/software/classpath/license.html. 13 | * 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 15 | */ 16 | package notion.api.v1.http 17 | 18 | import java.lang.reflect.Field 19 | import java.net.HttpURLConnection 20 | import java.net.ProtocolException 21 | import java.security.AccessController 22 | import java.security.PrivilegedActionException 23 | import java.security.PrivilegedExceptionAction 24 | 25 | /** 26 | * Thanks to 27 | * https://github.com/eclipse-ee4j/jersey/blob/3.0.2/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java#L473 28 | */ 29 | object HttpUrlConnPatchMethodWorkaround { 30 | 31 | fun setPatchRequestMethod(conn: HttpURLConnection) { 32 | try { 33 | conn.requestMethod = "PATCH" // Check whether we are running on a buggy JRE 34 | } catch (pe: ProtocolException) { 35 | try { 36 | AccessController.doPrivileged( 37 | PrivilegedExceptionAction { 38 | try { 39 | conn.requestMethod = "PATCH" 40 | } catch (pe: ProtocolException) { 41 | var connectionClass: Class<*>? = conn.javaClass 42 | val delegateField: Field? 43 | try { 44 | delegateField = connectionClass!!.getDeclaredField("delegate") 45 | delegateField.isAccessible = true 46 | val delegateConnection = delegateField[conn] as HttpURLConnection 47 | setPatchRequestMethod(delegateConnection) 48 | } catch (e: NoSuchFieldException) { 49 | // Ignore for now, keep going 50 | } catch (e: IllegalArgumentException) { 51 | throw RuntimeException(e) 52 | } catch (e: IllegalAccessException) { 53 | throw RuntimeException(e) 54 | } 55 | try { 56 | var methodField: Field 57 | while (connectionClass != null) { 58 | try { 59 | methodField = connectionClass.getDeclaredField("method") 60 | } catch (e: NoSuchFieldException) { 61 | connectionClass = connectionClass.superclass 62 | continue 63 | } 64 | methodField.isAccessible = true 65 | methodField[conn] = "PATCH" 66 | break 67 | } 68 | } catch (e: Exception) { 69 | throw RuntimeException(e) 70 | } 71 | } 72 | null 73 | }) 74 | } catch (e: PrivilegedActionException) { 75 | val cause: Throwable? = e.cause 76 | if (cause is RuntimeException) { 77 | throw cause 78 | } else { 79 | throw RuntimeException(cause) 80 | } 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /okhttp3/src/test/kotlin/integration_tests/SimpleTest.kt: -------------------------------------------------------------------------------- 1 | package integration_tests 2 | 3 | import kotlin.test.assertNotNull 4 | import notion.api.v1.NotionClient 5 | import notion.api.v1.http.OkHttp3Client 6 | import notion.api.v1.model.pages.Page 7 | import notion.api.v1.model.pages.PageParent 8 | import notion.api.v1.model.pages.PageProperty 9 | import notion.api.v1.request.search.SearchRequest 10 | import org.junit.Test 11 | 12 | typealias prop = PageProperty 13 | 14 | class SimpleTest { 15 | 16 | @Test 17 | fun pages() { 18 | NotionClient(token = System.getenv("NOTION_TOKEN")).use { client -> 19 | client.httpClient = OkHttp3Client() 20 | 21 | // Find the "Test Database" from the list 22 | val database = 23 | client 24 | .search( 25 | query = "Test Database", 26 | filter = SearchRequest.SearchFilter("database", property = "object")) 27 | .results 28 | .find { it.asDatabase().properties.containsKey("Severity") } 29 | ?.asDatabase() 30 | ?: throw IllegalStateException( 31 | "Create a database named 'Test Database' and invite this app's user!") 32 | 33 | // All the options for "Severity" property (select type) 34 | val severityOptions = database.properties?.get("Severity")?.select?.options 35 | // All the options for "Tags" property (multi_select type) 36 | val tagOptions = database.properties?.get("Tags")?.multiSelect?.options 37 | // The user object for "Assignee" property (people type) 38 | val assignee = client.listUsers().results[0] // just picking the first user up 39 | 40 | val newPage: Page = 41 | client.createPage( 42 | // Use the "Test Database" as this page's parent 43 | parent = PageParent.database(databaseId = database.id), 44 | // Set values to the page's properties 45 | // (these must be pre-defined before this API call) 46 | properties = 47 | mapOf( 48 | "Title" to 49 | prop( 50 | title = 51 | listOf( 52 | PageProperty.RichText( 53 | text = 54 | PageProperty.RichText.Text(content = "Fix a bug")))), 55 | "Severity" to prop(select = severityOptions?.find { it.name == "High" }), 56 | "Tags" to prop(multiSelect = tagOptions), 57 | "Due" to 58 | prop(date = PageProperty.Date(start = "2021-05-13", end = "2021-12-31")), 59 | "Velocity Points" to prop(number = 3), 60 | "Assignee" to prop(people = listOf(assignee)), 61 | "Done" to prop(checkbox = true), 62 | "Link" to prop(url = "https://www.example.com"), 63 | "Contact" to prop(email = "foo@example.com"), 64 | )) 65 | assertNotNull(newPage) 66 | 67 | val patchResult = 68 | client.updatePage( 69 | pageId = newPage.id, 70 | // Update only "Severity" property 71 | properties = 72 | mapOf( 73 | "Severity" to prop(select = severityOptions?.find { it.name == "Medium" }), 74 | )) 75 | assertNotNull(patchResult) 76 | 77 | val fetchedPage = client.retrievePage(newPage.id) 78 | assertNotNull(fetchedPage) 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /okhttp4/src/test/kotlin/integration_tests/SimpleTest.kt: -------------------------------------------------------------------------------- 1 | package integration_tests 2 | 3 | import kotlin.test.assertNotNull 4 | import notion.api.v1.NotionClient 5 | import notion.api.v1.http.OkHttp4Client 6 | import notion.api.v1.model.pages.Page 7 | import notion.api.v1.model.pages.PageParent 8 | import notion.api.v1.model.pages.PageProperty 9 | import notion.api.v1.request.search.SearchRequest 10 | import org.junit.Test 11 | 12 | typealias prop = PageProperty 13 | 14 | class SimpleTest { 15 | 16 | @Test 17 | fun pages() { 18 | NotionClient(token = System.getenv("NOTION_TOKEN")).use { client -> 19 | client.httpClient = OkHttp4Client() 20 | 21 | // Find the "Test Database" from the list 22 | val database = 23 | client 24 | .search( 25 | query = "Test Database", 26 | filter = SearchRequest.SearchFilter("database", property = "object")) 27 | .results 28 | .find { it.asDatabase().properties.containsKey("Severity") } 29 | ?.asDatabase() 30 | ?: throw IllegalStateException( 31 | "Create a database named 'Test Database' and invite this app's user!") 32 | 33 | // All the options for "Severity" property (select type) 34 | val severityOptions = database.properties?.get("Severity")?.select?.options 35 | // All the options for "Tags" property (multi_select type) 36 | val tagOptions = database.properties?.get("Tags")?.multiSelect?.options 37 | // The user object for "Assignee" property (people type) 38 | val assignee = client.listUsers().results[0] // just picking the first user up 39 | 40 | val newPage: Page = 41 | client.createPage( 42 | // Use the "Test Database" as this page's parent 43 | parent = PageParent.database(databaseId = database.id), 44 | // Set values to the page's properties 45 | // (these must be pre-defined before this API call) 46 | properties = 47 | mapOf( 48 | "Title" to 49 | prop( 50 | title = 51 | listOf( 52 | PageProperty.RichText( 53 | text = 54 | PageProperty.RichText.Text(content = "Fix a bug")))), 55 | "Severity" to prop(select = severityOptions?.find { it.name == "High" }), 56 | "Tags" to prop(multiSelect = tagOptions), 57 | "Due" to 58 | prop(date = PageProperty.Date(start = "2021-05-13", end = "2021-12-31")), 59 | "Velocity Points" to prop(number = 3), 60 | "Assignee" to prop(people = listOf(assignee)), 61 | "Done" to prop(checkbox = true), 62 | "Link" to prop(url = "https://www.example.com"), 63 | "Contact" to prop(email = "foo@example.com"), 64 | )) 65 | assertNotNull(newPage) 66 | 67 | val patchResult = 68 | client.updatePage( 69 | pageId = newPage.id, 70 | // Update only "Severity" property 71 | properties = 72 | mapOf( 73 | "Severity" to prop(select = severityOptions?.find { it.name == "Medium" }), 74 | )) 75 | assertNotNull(patchResult) 76 | 77 | val fetchedPage = client.retrievePage(newPage.id) 78 | assertNotNull(fetchedPage) 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /okhttp5/src/test/kotlin/integration_tests/SimpleTest.kt: -------------------------------------------------------------------------------- 1 | package integration_tests 2 | 3 | import kotlin.test.assertNotNull 4 | import notion.api.v1.NotionClient 5 | import notion.api.v1.http.OkHttp5Client 6 | import notion.api.v1.model.pages.Page 7 | import notion.api.v1.model.pages.PageParent 8 | import notion.api.v1.model.pages.PageProperty 9 | import notion.api.v1.request.search.SearchRequest 10 | import org.junit.Test 11 | 12 | typealias prop = PageProperty 13 | 14 | class SimpleTest { 15 | 16 | @Test 17 | fun pages() { 18 | NotionClient(token = System.getenv("NOTION_TOKEN")).use { client -> 19 | client.httpClient = OkHttp5Client() 20 | 21 | // Find the "Test Database" from the list 22 | val database = 23 | client 24 | .search( 25 | query = "Test Database", 26 | filter = SearchRequest.SearchFilter("database", property = "object")) 27 | .results 28 | .find { it.asDatabase().properties.containsKey("Severity") } 29 | ?.asDatabase() 30 | ?: throw IllegalStateException( 31 | "Create a database named 'Test Database' and invite this app's user!") 32 | 33 | // All the options for "Severity" property (select type) 34 | val severityOptions = database.properties?.get("Severity")?.select?.options 35 | // All the options for "Tags" property (multi_select type) 36 | val tagOptions = database.properties?.get("Tags")?.multiSelect?.options 37 | // The user object for "Assignee" property (people type) 38 | val assignee = client.listUsers().results[0] // just picking the first user up 39 | 40 | val newPage: Page = 41 | client.createPage( 42 | // Use the "Test Database" as this page's parent 43 | parent = PageParent.database(databaseId = database.id), 44 | // Set values to the page's properties 45 | // (these must be pre-defined before this API call) 46 | properties = 47 | mapOf( 48 | "Title" to 49 | prop( 50 | title = 51 | listOf( 52 | PageProperty.RichText( 53 | text = 54 | PageProperty.RichText.Text(content = "Fix a bug")))), 55 | "Severity" to prop(select = severityOptions?.find { it.name == "High" }), 56 | "Tags" to prop(multiSelect = tagOptions), 57 | "Due" to 58 | prop(date = PageProperty.Date(start = "2021-05-13", end = "2021-12-31")), 59 | "Velocity Points" to prop(number = 3), 60 | "Assignee" to prop(people = listOf(assignee)), 61 | "Done" to prop(checkbox = true), 62 | "Link" to prop(url = "https://www.example.com"), 63 | "Contact" to prop(email = "foo@example.com"), 64 | )) 65 | assertNotNull(newPage) 66 | 67 | val patchResult = 68 | client.updatePage( 69 | pageId = newPage.id, 70 | // Update only "Severity" property 71 | properties = 72 | mapOf( 73 | "Severity" to prop(select = severityOptions?.find { it.name == "Medium" }), 74 | )) 75 | assertNotNull(patchResult) 76 | 77 | val fetchedPage = client.retrievePage(newPage.id) 78 | assertNotNull(fetchedPage) 79 | } 80 | } 81 | } 82 | --------------------------------------------------------------------------------