diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000..2d19fc7 --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml new file mode 100644 index 0000000..74d8c97 --- /dev/null +++ b/.github/workflows/R-CMD-check.yaml @@ -0,0 +1,49 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +name: R-CMD-check + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: macos-latest, r: 'release'} + - {os: windows-latest, r: 'release'} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::rcmdcheck + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml new file mode 100644 index 0000000..a7276e8 --- /dev/null +++ b/.github/workflows/pkgdown.yaml @@ -0,0 +1,48 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + release: + types: [published] + workflow_dispatch: + +name: pkgdown + +jobs: + pkgdown: + runs-on: ubuntu-latest + # Only restrict concurrency for non-PR jobs + concurrency: + group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::pkgdown, local::. + needs: website + + - name: Build site + run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) + shell: Rscript {0} + + - name: Deploy to GitHub pages 🚀 + if: github.event_name != 'pull_request' + uses: JamesIves/github-pages-deploy-action@v4.5.0 + with: + clean: false + branch: gh-pages + folder: docs diff --git a/.gitignore b/.gitignore index 0bc377e..687c8a5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ .Rhistory .Rproj.user/DAAF7741/cpp-definition-cache .Rproj.user +docs diff --git a/DESCRIPTION b/DESCRIPTION index ec35605..486ae4e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,12 +1,22 @@ Package: notionR Title: R interfase for Notion API -Version: 0.0.0.9000 +Version: 0.0.0.9001 Author: Eduardo Flores -Depends: R (>= 2.10) Maintainer: Eduardo Flores Description: Provides wrappers to access the Notion API using R. -License: `use_mit_license()` +License: MIT + file LICENSE +URL: https://Eflores89.github.io/notionR/, + https://github.com/Eflores89/notionR +Depends: + R (>= 2.10) +Imports: + dplyr, + httr, + httr2, + stringi, + tibble, + tidyr Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1 diff --git a/LICENSE b/LICENSE index 3e22417..803a826 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,2 @@ -MIT License - -Copyright (c) 2021 Eduardo Flores - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +YEAR: 2024 +COPYRIGHT HOLDER: notionR authors diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..acaba23 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 notionR authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NAMESPACE b/NAMESPACE index 5edc196..56dd14c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -8,11 +8,12 @@ export(add_relation_id_filter) export(add_select_filter) export(archivePage) export(createNotionPage) +export(deleteBlock) export(getMultiSelectValues) export(getNotionDatabase) export(getNotionDatabaseMetadata) -export(getNotionPage) export(getNotionPageContent) +export(getNotionPage_WIP) export(isEmptyNotionDatabaseExport) export(normalizeChromePageIds) export(notion_filter) @@ -33,9 +34,17 @@ importFrom(dplyr,group_by) importFrom(dplyr,summarise) importFrom(httr,GET) importFrom(httr,PATCH) -importFrom(httr,POST) +importFrom(httr,accept) +importFrom(httr,add_headers) importFrom(httr,content) importFrom(httr,content_type) +importFrom(httr2,req_body_json) +importFrom(httr2,req_headers) +importFrom(httr2,req_perform) +importFrom(httr2,req_url_path) +importFrom(httr2,request) +importFrom(httr2,resp_body_json) +importFrom(httr2,resp_status_desc) importFrom(stringi,stri_split_regex) importFrom(tibble,enframe) importFrom(tidyr,pivot_wider) diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..bf1d71b --- /dev/null +++ b/NEWS.md @@ -0,0 +1,7 @@ +# notionR 0.0.0.9001 + +* Start move to httr2 + +# notionR 0.0.0.9000 + +* First release diff --git a/R/addBlockH1.R b/R/addBlockH1.R index e90851b..8380e23 100644 --- a/R/addBlockH1.R +++ b/R/addBlockH1.R @@ -1,10 +1,11 @@ #' Adds an H1 (heading one) Block to a Page #' #' Id refers to a page id, content should be only text. -#' @param secret API token -#' @param id Page id where block will be appended -#' @param content content to append as H1 -#' @param toggle defaults to FALSE. If TRUE, will create an H1 Toggle. +#' +#' @param secret API token +#' @param id Page id where block will be appended +#' @param content content to append as H1 +#' @param toggle defaults to FALSE. If TRUE, will create an H1 Toggle. #' #' @importFrom httr PATCH #' @export diff --git a/R/addBlockH2.R b/R/addBlockH2.R index f3ccf11..9205588 100644 --- a/R/addBlockH2.R +++ b/R/addBlockH2.R @@ -1,10 +1,11 @@ -#' Adds an H2 (heading two) Block to a Page +#' Adds an H2 (heading two) Block to a Page #' -#' Id refers to a page id, content should be only text. -#' @param secret API token -#' @param id Page id where block will be appended -#' @param content content to append as H2 -#' @param toggle defaults to FALSE. If TRUE, will create an H1 Toggle. +#' Id refers to a page id, content should be only text. +#' +#' @param secret API token +#' @param id Page id where block will be appended +#' @param content content to append as H2 +#' @param toggle defaults to FALSE. If TRUE, will create an H1 Toggle. #' #' @importFrom httr PATCH #' @export diff --git a/R/addBlockParagraph.R b/R/addBlockParagraph.R index f4d12f7..19980c2 100644 --- a/R/addBlockParagraph.R +++ b/R/addBlockParagraph.R @@ -1,9 +1,10 @@ -#' Adds a Paragraph Block to a Page +#' Adds a Paragraph Block to a Page #' -#' Id refers to a page id, content should be only text. HTML will export to text. -#' @param secret API token -#' @param id Page id where block will be appended -#' @param content content to append +#' Id refers to a page id, content should be only text. HTML will export to text. +#' +#' @param secret API token +#' @param id Page id where block will be appended +#' @param content content to append #' #' @importFrom httr PATCH #' @export diff --git a/R/deleteBlock.R b/R/deleteBlock.R index 593f591..31f51f2 100644 --- a/R/deleteBlock.R +++ b/R/deleteBlock.R @@ -10,9 +10,7 @@ #' @param id block id #' #' -#' @importFrom httr PATCH -#' @importFrom httr content -#' @importFrom httr content_type +#' @importFrom httr PATCH content content_type add_headers accept #' @export deleteBlock <- function(secret, id){ diff --git a/R/filters.R b/R/filters.R index 138f41d..28b428d 100644 --- a/R/filters.R +++ b/R/filters.R @@ -9,6 +9,7 @@ #' #' @param . List of filter conditions #' @param sort List of sort conditions. NULL by default. +#' @param ... A combination of filters #' #' #' @examples diff --git a/R/getMultiSelectValues.R b/R/getMultiSelectValues.R index a29fef3..35d2675 100644 --- a/R/getMultiSelectValues.R +++ b/R/getMultiSelectValues.R @@ -9,7 +9,7 @@ #' @return vector #' #' @param column vector of column in data.frame (usually, after using getNotionDatabase, in form db$column_name ) -#' @strip_string String by which we should strip >1 selects in a single database row. Defaults to "|", as this is the default behaviour in getNotionDatabase(). +#' @param strip_string String by which we should strip >1 selects in a single database row. Defaults to "|", as this is the default behaviour in getNotionDatabase(). #' @param no_na Strip all NA's? Defaults to TRUE. #' @param only_unique Export only unique values in vector? Defaults to TRUE. #' @param show_progress Print the count of values? Defaults to TRUE. diff --git a/R/getNotionDatabase.R b/R/getNotionDatabase.R index 0781047..cca876d 100644 --- a/R/getNotionDatabase.R +++ b/R/getNotionDatabase.R @@ -15,32 +15,56 @@ #' @param cover_icon also include cover and icon metadata? #' #' -#' @importFrom httr POST -#' @importFrom httr content #' @importFrom tibble enframe #' @importFrom dplyr %>% #' @importFrom dplyr group_by #' @importFrom dplyr summarise #' @importFrom tidyr pivot_wider #' @importFrom dplyr bind_rows +#' @importFrom httr2 request req_url_path req_headers req_body_json req_perform +#' @importFrom httr2 resp_status_desc resp_body_json #' @export getNotionDatabase <- function(secret, database, filters = NULL, show_progress = FALSE, all_pages = TRUE, cover_icon = FALSE){ options(dplyr.summarise.inform = FALSE) # to supress all the grouping warnings! - # +++++++++ construct headers - headers = c(`Authorization` = secret, `Notion-Version` = '2022-02-22', `Content-Type` = 'application/json' ) - # +++++++++ api call ------------------------------------------------------------- - callAPI <- function(database, headers, filters, cursor){ - res <- httr::POST(url = paste0('https://api.notion.com/v1/databases/', database, '/query'), - httr::add_headers(.headers = headers), - body = list("filter" = filters, - "start_cursor" = cursor), - # start_cursor = cursor, - encode = "json") - if(show_progress){ print(paste0("!! API Call: https://api.notion.com/v1/databases/", database, "/query")) } - - return( httr::content(res) ) + callAPI_httr2 <- function(database, filters, cursor, page_size = 100, secret, show_progress) { + if (!is.numeric(page_size) || page_size < 1 || page_size > 100) { + stop("page_size should be a numeric between 1 and 100") + } + + # data to send + data_to_send <- list( + "filter" = filters, + # "sorts" = sorts, # not implemented + "start_cursor" = cursor, + # There must be at least one not NULL in the list, hence page_size + "page_size" = page_size + ) + # Remove NULL to avoid bad request + data_to_send[sapply(data_to_send, is.null)] <- NULL + + # add data to the request + the_req <- request("https://api.notion.com/") %>% + req_url_path(paste0("/v1/databases/", database, "/query")) %>% + req_headers("Authorization" = paste("Bearer" , secret)) %>% + req_headers("Content-Type" = "application/json") %>% + req_headers("Notion-Version" = "2022-06-28") %>% + req_body_json(data = data_to_send) + + # Perform the request + resp <- req_perform(the_req) + # Check if ok + resp_status_desc(resp) + + # Get response as list + res <- resp_body_json(resp) + + if(show_progress){ + print(paste0("!! API Call: https://api.notion.com/v1/databases/", database, "/query")) + } + + return(res) } # +++++++++ this function "flattens" the results into a usable data.frame with 1 row per page (like the real database) @@ -101,10 +125,16 @@ getNotionDatabase <- function(secret, database, filters = NULL, show_progress = while( new_cursor ){ if(show_progress){ print(paste0("- cursor: ", cursor, " / new_cursor: ", new_cursor )) } - r <- callAPI(database = database, - headers = headers, - filters = filters, - cursor = cursor) + # r <- callAPI(database = database, + # headers = headers, + # filters = filters, + # cursor = cursor) + # + r <- callAPI_httr2(database = database, + filters = filters, + cursor = cursor, + secret = secret, + show_progress = show_progress) new_cursor <- r$has_more cursor <- r$next_cursor @@ -120,10 +150,16 @@ getNotionDatabase <- function(secret, database, filters = NULL, show_progress = # no pagination, just the top 100 if(show_progress){ print(paste0("++++ NO PAGINATION: ")) } cursor <- NULL - r <- callAPI(database = database, - headers = headers, - filters = filters, - cursor = cursor) + # r <- callAPI(database = database, + # headers = headers, + # filters = filters, + # cursor = cursor) + + r <- callAPI_httr2(database = database, + filters = filters, + cursor = cursor, + secret = secret, + show_progress = show_progress) dd <- getItemsAndFlattenIntoDataFrame( r$results ) } diff --git a/R/globals.R b/R/globals.R new file mode 100644 index 0000000..061c531 --- /dev/null +++ b/R/globals.R @@ -0,0 +1,4 @@ +globalVariables(unique(c( + # getItemsAndFlattenIntoDataFrame + "name", "value" +))) diff --git a/R/isEmptyNotionDatabaseExport.R b/R/isEmptyNotionDatabaseExport.R index 8a596c7..fb22462 100644 --- a/R/isEmptyNotionDatabaseExport.R +++ b/R/isEmptyNotionDatabaseExport.R @@ -1,4 +1,10 @@ +#' Is the database output empty ? +#' +#' @param dataframe The database output +#' #' @export isEmptyNotionDatabaseExport <- function(dataframe){ - if( (nrow(dataframe) == 1 & names(dataframe)[1] == "results" & dataframe[1,1] == "none") ){ TRUE }else{ FALSE } + isTRUE(nrow(dataframe) == 1 & + names(dataframe)[1] == "results" & + dataframe[1,1] == "none") } diff --git a/R/updateCheckbox.R b/R/updateCheckbox.R index 4e7adca..fe91f63 100644 --- a/R/updateCheckbox.R +++ b/R/updateCheckbox.R @@ -1,10 +1,11 @@ #' Updates a Checkbox Property #' -#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). -#' @param secret API token -#' @param id Page id to be updated -#' @param property_name name of property to update (should be a checkbox type property) -#' @param value value to update. Use R bollean object. Defaults to TRUE. +#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). +#' +#' @param secret API token +#' @param id Page id to be updated +#' @param property_name name of property to update (should be a checkbox type property) +#' @param value value to update. Use R bollean object. Defaults to TRUE. #' #' @importFrom httr PATCH #' @export diff --git a/R/updateDate.R b/R/updateDate.R index 81c1b4a..01970cf 100644 --- a/R/updateDate.R +++ b/R/updateDate.R @@ -1,10 +1,11 @@ #' Updates a Date property #' -#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). -#' @param secret API token -#' @param id Page id to be updated -#' @param property_name name of property to update (should be a date type property) -#' @param value value to update +#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). +#' +#' @param secret API token +#' @param id Page id to be updated +#' @param property_name name of property to update (should be a date type property) +#' @param value value to update #' #' @importFrom httr PATCH #' @export diff --git a/R/updateEmoji.R b/R/updateEmoji.R index 7e6d33d..b4e8f4d 100644 --- a/R/updateEmoji.R +++ b/R/updateEmoji.R @@ -1,9 +1,10 @@ #' Updates an Emoji Property of a page #' -#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). -#' @param secret API token -#' @param id Page id to be updated -#' @param emoji emoji to update to +#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). +#' +#' @param secret API token +#' @param id Page id to be updated +#' @param emoji emoji to update to #' #' @importFrom httr PATCH #' @export diff --git a/R/updateMultiSelect.R b/R/updateMultiSelect.R index f6fa723..914b92d 100644 --- a/R/updateMultiSelect.R +++ b/R/updateMultiSelect.R @@ -1,12 +1,13 @@ #' Updates a Select Property #' -#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). -#' @param secret API token -#' @param id Page id to be updated -#' @param property_name name of property to update (should be a multiselect type property) -#' @param value value(s) to update. Could be 1 value or multiple, created with c(). +#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). #' -#' @details This will rewrite whatever is already in the property. It will NOT append another select. +#' @param secret API token +#' @param id Page id to be updated +#' @param property_name name of property to update (should be a multiselect type property) +#' @param value value(s) to update. Could be 1 value or multiple, created with c(). +#' +#' @details This will rewrite whatever is already in the property. It will NOT append another select. #' #' @importFrom httr PATCH #' @export diff --git a/R/updateNumber.R b/R/updateNumber.R index a685f2f..a2a9d9e 100644 --- a/R/updateNumber.R +++ b/R/updateNumber.R @@ -1,10 +1,11 @@ #' Updates a Number Property #' -#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). -#' @param secret API token -#' @param id Page id to be updated -#' @param property_name name of property to update (should be a number type property) -#' @param value value to update +#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). +#' +#' @param secret API token +#' @param id Page id to be updated +#' @param property_name name of property to update (should be a number type property) +#' @param value value to update #' #' @importFrom httr PATCH #' @export diff --git a/R/updateRelationship.R b/R/updateRelationship.R index 8328d88..6e3b8b3 100644 --- a/R/updateRelationship.R +++ b/R/updateRelationship.R @@ -1,10 +1,11 @@ #' Updates (adds) a relationship to a page id #' -#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). -#' @param secret API token -#' @param id Page id to be updated -#' @param property_name name of property to update (should be a relationship type property) -#' @param value value to update (should be a unique page id) +#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). +#' +#' @param secret API token +#' @param id Page id to be updated +#' @param property_name name of property to update (should be a relationship type property) +#' @param value value to update (should be a unique page id) #' #' @importFrom httr PATCH #' @export diff --git a/R/updateSelect.R b/R/updateSelect.R index 7168bd5..a3b70fa 100644 --- a/R/updateSelect.R +++ b/R/updateSelect.R @@ -1,10 +1,11 @@ #' Updates a Select Property #' -#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). -#' @param secret API token -#' @param id Page id to be updated -#' @param property_name name of property to update (should be a select type property) -#' @param value value to update +#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). +#' +#' @param secret API token +#' @param id Page id to be updated +#' @param property_name name of property to update (should be a select type property) +#' @param value value to update #' #' @importFrom httr PATCH #' @export diff --git a/R/updateText.R b/R/updateText.R index 6a08acc..09ee910 100644 --- a/R/updateText.R +++ b/R/updateText.R @@ -1,10 +1,11 @@ #' Updates a Text Property #' -#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). -#' @param secret API token -#' @param id Page id to be updated -#' @param property_name name of property to update (should be a text type property) -#' @param value value to update +#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). +#' +#' @param secret API token +#' @param id Page id to be updated +#' @param property_name name of property to update (should be a text type property) +#' @param value value to update #' #' @importFrom httr PATCH #' @export diff --git a/R/updateURL.R b/R/updateURL.R index 964e5b4..3244689 100644 --- a/R/updateURL.R +++ b/R/updateURL.R @@ -1,10 +1,11 @@ #' Updates a URL Property #' -#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). -#' @param secret API token -#' @param id Page id to be updated -#' @param property_name name of property to update (should be a URL type property) -#' @param value value to update +#' Id refers to a page in a database, and should be normalized using normalizeChromeId(). +#' +#' @param secret API token +#' @param id Page id to be updated +#' @param property_name name of property to update (should be a URL type property) +#' @param value value to update #' #' @importFrom httr PATCH #' @export diff --git a/README.Rmd b/README.Rmd new file mode 100644 index 0000000..5e4f221 --- /dev/null +++ b/README.Rmd @@ -0,0 +1,138 @@ +--- +output: github_document +--- + + + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + fig.path = "man/figures/README-", + out.width = "100%" +) +``` + +# notionR + + +[![R-CMD-check](https://github.com/Eflores89/notionR/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/Eflores89/notionR/actions/workflows/R-CMD-check.yaml) + + +The goal of notionR is to connect to Notion API from R. Create, Modify, Download databases or pages from Notion. + +This is a wrapper functions to access [Notion API](https://developers.notion.com") using R + +**This package is work in progress! Use at your own risk!** + + +## Installation + +You can install the development version of notionR like so: + +``` r +pak::pak("Eflores89/notionR") +``` + +## Access to Notion API + +You need to be the **owner** of the Notion Workspace to create an integration. + +- Read the "Getting Started" from Notion API : https://developers.notion.com/docs/getting-started +- Build your first integration : https://developers.notion.com/docs/create-a-notion-integration +- Remember the name of the integration +- Store its API Secret + +The only way for other users of your workspace to be able to use the API integration is to share the API Secret with them: choose the authorization wisely. See this page for more information about authorization : https://developers.notion.com/docs/authorization + +We recommend to store your API Secret in a environment variable in your prefered .Renviron file. + +```r +usethis::edit_r_environ() +``` + +Add a variable like: + +``` +NOTION_API_SECRET="secret_xxx111" +``` + + +## Example + +### Get a specific database table content + +- Open the database you want to retrieve on Notion +- Open it as a full page +- Click on the "..." on the top right of the page +- Go to "Connexions" +- "Add connexion" and choose your own integration in the list + + The database is now accessible with your API Secret +- Get database ID + + Get the full URL of the page, and retrieve characters between last `/` and `?` + - e.g. If the URL is `https://www.notion.so/00001111bbbbcccc?v=ddddeeee33334444`, the database ID is `00001111bbbbcccc` + + +You have now all information to download the database as follows: + +```{r, eval=FALSE} +library(notionR) + +DATABASE_ID <- "00001111bbbbcccc" + +data_project <- getNotionDatabase( + secret = Sys.getenv("NOTION_API_SECRET"), + database = DATABASE_ID +) + +data_project +``` +``` +# A tibble: 26 × 70 + archived created_by.id created_by.object created_time + + 1 FALSE xxxxx-7e0a-480… user 2023-11-22T… + 2 FALSE xxxxx-7e0a-480… user 2023-10-28T… + 3 FALSE xxxxx-7e0a-480… user 2023-10-02T… + 4 FALSE xxxxx-7e0a-480… user 2023-09-30T… + 5 FALSE xxxxx-7e0a-480… user 2023-09-23T… + 6 FALSE xxxxx-7e0a-480… user 2023-09-23T… + 7 FALSE xxxxx-7e0a-480… user 2023-09-23T… + 8 FALSE xxxxx-7e0a-480… user 2023-09-23T… + 9 FALSE xxxxx-7e0a-480… user 2023-09-08T… +10 FALSE xxxxx-7e0a-480… user 2023-08-26T… +# ℹ 16 more rows +# ℹ 66 more variables: icon.emoji , icon.type , +# id , last_edited_by.id , +# last_edited_by.object , last_edited_time , +# object , parent.database_id , +# parent.type , properties.Achievement.id , +# properties.Achievement.rollup.function , … +# ℹ Use `print(n = ...)` to see more rows +``` + +To filter on some specific parameters see `?filters`. +You can use code as follows: + +```{r, eval=FALSE} +DATABASE_ID <- "00001111bbbbcccc" + +# using {notionR} built-in functions + +data_project <- getNotionDatabase( + secret = Sys.getenv("NOTION_API_SECRET"), + database = DATABASE_ID, + filters = add_checkbox_filter("my property with checkbox", equals = FALSE) +) + +# Or using list directly + +data_project <- getNotionDatabase( + secret = Sys.getenv("NOTION_API_SECRET"), + database = DATABASE_ID, + filters = list(property = "my property with checkbox", checkbox = list(equals = FALSE)) +) +data_project +``` + +See the documentation to get all available filters : https://developers.notion.com/reference/post-database-query-filter diff --git a/README.md b/README.md index 11fda74..2285685 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,134 @@ + + + # notionR + + +[![R-CMD-check](https://github.com/Eflores89/notionR/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/Eflores89/notionR/actions/workflows/R-CMD-check.yaml) + + +The goal of notionR is to connect to Notion API from R. Create, Modify, +Download databases or pages from Notion. + +This is a wrapper functions to access [Notion +API](https://developers.notion.com%22) using R + +**This package is work in progress! Use at your own risk!** + +## Installation + +You can install the development version of notionR like so: + +``` r +pak::pak("Eflores89/notionR") +``` + +## Access to Notion API + +You need to be the **owner** of the Notion Workspace to create an +integration. + +- Read the “Getting Started” from Notion API : + +- Build your first integration : + +- Remember the name of the integration +- Store its API Secret + +The only way for other users of your workspace to be able to use the API +integration is to share the API Secret with them: choose the +authorization wisely. See this page for more information about +authorization : + +We recommend to store your API Secret in a environment variable in your +prefered .Renviron file. + +``` r +usethis::edit_r_environ() +``` + +Add a variable like: + + NOTION_API_SECRET="secret_xxx111" + +## Example + +### Get a specific database table content + +- Open the database you want to retrieve on Notion +- Open it as a full page +- Click on the “…” on the top right of the page +- Go to “Connexions” +- “Add connexion” and choose your own integration in the list + - The database is now accessible with your API Secret +- Get database ID + - Get the full URL of the page, and retrieve characters between last + `/` and `?` + - e.g. If the URL is + `https://www.notion.so/00001111bbbbcccc?v=ddddeeee33334444`, the + database ID is `00001111bbbbcccc` + +You have now all information to download the database as follows: + +``` r +library(notionR) + +DATABASE_ID <- "00001111bbbbcccc" + +data_project <- getNotionDatabase( + secret = Sys.getenv("NOTION_API_SECRET"), + database = DATABASE_ID +) + +data_project +``` + + # A tibble: 26 × 70 + archived created_by.id created_by.object created_time + + 1 FALSE xxxxx-7e0a-480… user 2023-11-22T… + 2 FALSE xxxxx-7e0a-480… user 2023-10-28T… + 3 FALSE xxxxx-7e0a-480… user 2023-10-02T… + 4 FALSE xxxxx-7e0a-480… user 2023-09-30T… + 5 FALSE xxxxx-7e0a-480… user 2023-09-23T… + 6 FALSE xxxxx-7e0a-480… user 2023-09-23T… + 7 FALSE xxxxx-7e0a-480… user 2023-09-23T… + 8 FALSE xxxxx-7e0a-480… user 2023-09-23T… + 9 FALSE xxxxx-7e0a-480… user 2023-09-08T… + 10 FALSE xxxxx-7e0a-480… user 2023-08-26T… + # ℹ 16 more rows + # ℹ 66 more variables: icon.emoji , icon.type , + # id , last_edited_by.id , + # last_edited_by.object , last_edited_time , + # object , parent.database_id , + # parent.type , properties.Achievement.id , + # properties.Achievement.rollup.function , … + # ℹ Use `print(n = ...)` to see more rows + +To filter on some specific parameters see `?filters`. +You can use code as follows: + +``` r +DATABASE_ID <- "00001111bbbbcccc" + +# using {notionR} built-in functions + +data_project <- getNotionDatabase( + secret = Sys.getenv("NOTION_API_SECRET"), + database = DATABASE_ID, + filters = add_checkbox_filter("my property with checkbox", equals = FALSE) +) + +# Or using list directly - -
-

Notion package for R

-

- Wrapper functions to access Notion API using R -

-
-
+data_project <- getNotionDatabase( + secret = Sys.getenv("NOTION_API_SECRET"), + database = DATABASE_ID, + filters = list(property = "my property with checkbox", checkbox = list(equals = FALSE)) +) +data_project +``` -

⚠️ This package is work in progress! Use at your own risk!

+See the documentation to get all available filters : + diff --git a/_pkgdown.yml b/_pkgdown.yml new file mode 100644 index 0000000..c198be5 --- /dev/null +++ b/_pkgdown.yml @@ -0,0 +1,8 @@ +url: https://Eflores89.github.io/notionR/ + +development: + mode: auto + +template: + bootstrap: 5 + diff --git a/dev/config_attachment.yaml b/dev/config_attachment.yaml new file mode 100644 index 0000000..46e24ec --- /dev/null +++ b/dev/config_attachment.yaml @@ -0,0 +1,12 @@ +path.n: NAMESPACE +path.d: DESCRIPTION +dir.r: R +dir.v: vignettes +dir.t: tests +extra.suggests: ~ +pkg_ignore: ~ +document: yes +normalize: yes +inside_rmd: no +must.exist: yes +check_if_suggests_is_installed: yes diff --git a/dev/dev_history.Rmd b/dev/dev_history.Rmd new file mode 100644 index 0000000..1f702a4 --- /dev/null +++ b/dev/dev_history.Rmd @@ -0,0 +1,30 @@ +# Set documentation + +```{r} +usethis::use_readme_rmd() +usethis::use_mit_license() +usethis::use_news_md() + +# CI/CD +# _check +usethis::use_github_action("check-standard") +# _pkgdown +usethis::use_pkgdown() +usethis::use_github_action("pkgdown") +``` + +# Deal with dependencies + +```{r} +attachment::att_amend_desc() +usethis::use_build_ignore("dev") +``` + + +# Check package + +```{r} +devtools::check() +``` + + diff --git a/man/addBlockH1.Rd b/man/addBlockH1.Rd index 9bfe9ac..bc2d01c 100644 --- a/man/addBlockH1.Rd +++ b/man/addBlockH1.Rd @@ -6,10 +6,15 @@ \usage{ addBlockH1(secret, id, content, toggle = FALSE) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id where block will be appended} + +\item{content}{content to append as H1} + +\item{toggle}{defaults to FALSE. If TRUE, will create an H1 Toggle.} +} \description{ Id refers to a page id, content should be only text. -@param secret API token -@param id Page id where block will be appended -@param content content to append as H1 -@param toggle defaults to FALSE. If TRUE, will create an H1 Toggle. } diff --git a/man/addBlockH2.Rd b/man/addBlockH2.Rd index aa69ea6..1cebe33 100644 --- a/man/addBlockH2.Rd +++ b/man/addBlockH2.Rd @@ -6,10 +6,15 @@ \usage{ addBlockH2(secret, id, content, toggle = FALSE) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id where block will be appended} + +\item{content}{content to append as H2} + +\item{toggle}{defaults to FALSE. If TRUE, will create an H1 Toggle.} +} \description{ Id refers to a page id, content should be only text. -@param secret API token -@param id Page id where block will be appended -@param content content to append as H2 -@param toggle defaults to FALSE. If TRUE, will create an H1 Toggle. } diff --git a/man/addBlockParagraph.Rd b/man/addBlockParagraph.Rd index 918a149..e2f4ada 100644 --- a/man/addBlockParagraph.Rd +++ b/man/addBlockParagraph.Rd @@ -6,9 +6,13 @@ \usage{ addBlockParagraph(secret, id, content) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id where block will be appended} + +\item{content}{content to append} +} \description{ Id refers to a page id, content should be only text. HTML will export to text. -@param secret API token -@param id Page id where block will be appended -@param content content to append } diff --git a/man/deleteBlock.Rd b/man/deleteBlock.Rd new file mode 100644 index 0000000..164161f --- /dev/null +++ b/man/deleteBlock.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/deleteBlock.R +\name{deleteBlock} +\alias{deleteBlock} +\title{Delete a Block} +\usage{ +deleteBlock(secret, id) +} +\arguments{ +\item{secret}{Notion API token} + +\item{id}{block id} +} +\value{ +list of response +} +\description{ +Deletes a block +} +\author{ +Eduardo Flores +} diff --git a/man/filters.Rd b/man/filters.Rd index 5b243e2..f2ad8e1 100644 --- a/man/filters.Rd +++ b/man/filters.Rd @@ -24,6 +24,8 @@ add_relation_id_filter(property, equals) \item{sort}{List of sort conditions. NULL by default.} +\item{...}{A combination of filters} + \item{property}{name or id of property (column) in database} \item{equals}{TRUE (default) or FALSE condition to meet in checkbox. Equals (contains) for select filter.} diff --git a/man/getMultiSelectValues.Rd b/man/getMultiSelectValues.Rd index 721d7c5..0b75586 100644 --- a/man/getMultiSelectValues.Rd +++ b/man/getMultiSelectValues.Rd @@ -15,6 +15,8 @@ getMultiSelectValues( \arguments{ \item{column}{vector of column in data.frame (usually, after using getNotionDatabase, in form db$column_name )} +\item{strip_string}{String by which we should strip >1 selects in a single database row. Defaults to "|", as this is the default behaviour in getNotionDatabase().} + \item{no_na}{Strip all NA's? Defaults to TRUE.} \item{only_unique}{Export only unique values in vector? Defaults to TRUE.} diff --git a/man/getNotionPage.Rd b/man/getNotionPage_WIP.Rd similarity index 77% rename from man/getNotionPage.Rd rename to man/getNotionPage_WIP.Rd index 847eae6..20df491 100644 --- a/man/getNotionPage.Rd +++ b/man/getNotionPage_WIP.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/getNotionPage.R -\name{getNotionPage} -\alias{getNotionPage} +\name{getNotionPage_WIP} +\alias{getNotionPage_WIP} \title{Get a Page} \usage{ -getNotionPage(secret, id) +getNotionPage_WIP(secret, id) } \arguments{ \item{secret}{Notion API token} diff --git a/man/isEmptyNotionDatabaseExport.Rd b/man/isEmptyNotionDatabaseExport.Rd new file mode 100644 index 0000000..8353067 --- /dev/null +++ b/man/isEmptyNotionDatabaseExport.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/isEmptyNotionDatabaseExport.R +\name{isEmptyNotionDatabaseExport} +\alias{isEmptyNotionDatabaseExport} +\title{Is the database output empty ?} +\usage{ +isEmptyNotionDatabaseExport(dataframe) +} +\arguments{ +\item{dataframe}{The database output} +} +\description{ +Is the database output empty ? +} diff --git a/man/updateCheckbox.Rd b/man/updateCheckbox.Rd index e9fbfc1..87c6a4a 100644 --- a/man/updateCheckbox.Rd +++ b/man/updateCheckbox.Rd @@ -6,10 +6,15 @@ \usage{ updateCheckbox(secret, id, property_name, value = TRUE) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id to be updated} + +\item{property_name}{name of property to update (should be a checkbox type property)} + +\item{value}{value to update. Use R bollean object. Defaults to TRUE.} +} \description{ Id refers to a page in a database, and should be normalized using normalizeChromeId(). -@param secret API token -@param id Page id to be updated -@param property_name name of property to update (should be a checkbox type property) -@param value value to update. Use R bollean object. Defaults to TRUE. } diff --git a/man/updateDate.Rd b/man/updateDate.Rd index f152736..0d255e6 100644 --- a/man/updateDate.Rd +++ b/man/updateDate.Rd @@ -6,10 +6,15 @@ \usage{ updateDate(secret, id, property_name, value) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id to be updated} + +\item{property_name}{name of property to update (should be a date type property)} + +\item{value}{value to update} +} \description{ Id refers to a page in a database, and should be normalized using normalizeChromeId(). -@param secret API token -@param id Page id to be updated -@param property_name name of property to update (should be a date type property) -@param value value to update } diff --git a/man/updateEmoji.Rd b/man/updateEmoji.Rd index fc6a111..3af3ad1 100644 --- a/man/updateEmoji.Rd +++ b/man/updateEmoji.Rd @@ -6,9 +6,13 @@ \usage{ updateEmoji(secret, id, emoji) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id to be updated} + +\item{emoji}{emoji to update to} +} \description{ Id refers to a page in a database, and should be normalized using normalizeChromeId(). -@param secret API token -@param id Page id to be updated -@param emoji emoji to update to } diff --git a/man/updateMultiSelect.Rd b/man/updateMultiSelect.Rd index 820eea2..cfcd435 100644 --- a/man/updateMultiSelect.Rd +++ b/man/updateMultiSelect.Rd @@ -6,13 +6,18 @@ \usage{ updateMultiSelect(secret, id, property_name, value) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id to be updated} + +\item{property_name}{name of property to update (should be a multiselect type property)} + +\item{value}{value(s) to update. Could be 1 value or multiple, created with c().} +} \description{ Id refers to a page in a database, and should be normalized using normalizeChromeId(). -@param secret API token -@param id Page id to be updated -@param property_name name of property to update (should be a multiselect type property) -@param value value(s) to update. Could be 1 value or multiple, created with c(). } \details{ -@details This will rewrite whatever is already in the property. It will NOT append another select. +This will rewrite whatever is already in the property. It will NOT append another select. } diff --git a/man/updateNumber.Rd b/man/updateNumber.Rd index be16c6f..bb035ac 100644 --- a/man/updateNumber.Rd +++ b/man/updateNumber.Rd @@ -6,10 +6,15 @@ \usage{ updateNumber(secret, id, property_name, value) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id to be updated} + +\item{property_name}{name of property to update (should be a number type property)} + +\item{value}{value to update} +} \description{ Id refers to a page in a database, and should be normalized using normalizeChromeId(). -@param secret API token -@param id Page id to be updated -@param property_name name of property to update (should be a number type property) -@param value value to update } diff --git a/man/updateRelationship.Rd b/man/updateRelationship.Rd index 542972f..80df453 100644 --- a/man/updateRelationship.Rd +++ b/man/updateRelationship.Rd @@ -6,10 +6,15 @@ \usage{ updateRelationship(secret, id, property_name, value) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id to be updated} + +\item{property_name}{name of property to update (should be a relationship type property)} + +\item{value}{value to update (should be a unique page id)} +} \description{ Id refers to a page in a database, and should be normalized using normalizeChromeId(). -@param secret API token -@param id Page id to be updated -@param property_name name of property to update (should be a relationship type property) -@param value value to update (should be a unique page id) } diff --git a/man/updateSelect.Rd b/man/updateSelect.Rd index 76f19e0..03ab862 100644 --- a/man/updateSelect.Rd +++ b/man/updateSelect.Rd @@ -6,10 +6,15 @@ \usage{ updateSelect(secret, id, property_name, value) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id to be updated} + +\item{property_name}{name of property to update (should be a select type property)} + +\item{value}{value to update} +} \description{ Id refers to a page in a database, and should be normalized using normalizeChromeId(). -@param secret API token -@param id Page id to be updated -@param property_name name of property to update (should be a select type property) -@param value value to update } diff --git a/man/updateText.Rd b/man/updateText.Rd index 4174433..3889478 100644 --- a/man/updateText.Rd +++ b/man/updateText.Rd @@ -6,10 +6,15 @@ \usage{ updateText(secret, id, property_name, value) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id to be updated} + +\item{property_name}{name of property to update (should be a text type property)} + +\item{value}{value to update} +} \description{ Id refers to a page in a database, and should be normalized using normalizeChromeId(). -@param secret API token -@param id Page id to be updated -@param property_name name of property to update (should be a text type property) -@param value value to update } diff --git a/man/updateURL.Rd b/man/updateURL.Rd index be22905..0331ab7 100644 --- a/man/updateURL.Rd +++ b/man/updateURL.Rd @@ -6,10 +6,15 @@ \usage{ updateURL(secret, id, property_name, value) } +\arguments{ +\item{secret}{API token} + +\item{id}{Page id to be updated} + +\item{property_name}{name of property to update (should be a URL type property)} + +\item{value}{value to update} +} \description{ Id refers to a page in a database, and should be normalized using normalizeChromeId(). -@param secret API token -@param id Page id to be updated -@param property_name name of property to update (should be a URL type property) -@param value value to update } diff --git a/test.R b/test.R deleted file mode 100644 index 8d06ca9..0000000 --- a/test.R +++ /dev/null @@ -1,18 +0,0 @@ -# package testing - - - - -# to test ------------- - - -"YiIx" - -"tu}s" - - - - - - -