|
# this script imported all 789 of my journal entries |
|
# that I had previously exported from Daylio to CSV |
|
# into Notion, using the Notion API. |
|
# the project served as a great way to dive into |
|
# using APIs with R, httr, and jsonlite. |
|
|
|
library(here) |
|
library(fs) |
|
library(tidyverse) |
|
library(lubridate) |
|
library(jsonlite) |
|
library(httr) |
|
library(glue) |
|
|
|
api_url <- "https://api.notion.com/v1" |
|
api_key <- "ADD API KEY HERE" |
|
database_id <- "ADD PARENT DATABASE ID HERE" |
|
notion_version <- "2022-02-22" |
|
|
|
headers <- c( |
|
"Authorization" = paste("Bearer", api_key), |
|
"Content-Type" = "application/json", |
|
"Notion-Version" = notion_version |
|
) |
|
|
|
title_from_date <- function(x) { |
|
# idea was to title entries with the date, including the weekday name |
|
glue("{weekdays(x)} {month(x)}/{day(x)}/{year(x) %% 100}") |
|
} |
|
|
|
write_date <- function(date) { |
|
# write dates to JSON in Notion's format with my time zone |
|
# maybe this would work w/o being so explicit re: format_ISO8601() |
|
# but I wanted to be sure |
|
list( |
|
date = list( |
|
start = format_ISO8601(date), |
|
time_zone = "America/Chicago" |
|
) |
|
) |
|
} |
|
|
|
write_select <- function(value) { |
|
# a "select" field, as Notion takes them. |
|
# used for my "mood" |
|
list( |
|
select = list( |
|
name = value |
|
) |
|
) |
|
} |
|
|
|
write_tags <- function(tags) { |
|
# a "multi-select" field, as Notion takes them. |
|
# used for my "activities" |
|
list( |
|
multi_select = map(tags, ~list(name = .x)) |
|
) |
|
} |
|
|
|
write_title <- function(title) { |
|
# a "title" field, as Notion takes them. |
|
# used for my title, as created by title_from_date() above |
|
list( |
|
title = list( |
|
list( |
|
type = "text", |
|
text = list( |
|
content = title |
|
) |
|
) |
|
) |
|
) |
|
} |
|
|
|
write_content <- function(content) { |
|
# a list of child blocks to populate a Notion page |
|
# used for the content of my entries |
|
map( |
|
content, |
|
~ list( |
|
object = "block", |
|
type = "paragraph", |
|
paragraph = list( |
|
rich_text = list( |
|
list( |
|
type = "text", |
|
text = list(content = .x) |
|
) |
|
) |
|
) |
|
) |
|
) |
|
} |
|
|
|
is_na <- function(x) { |
|
# to avoid annoying warnings about is.na() on vectors. |
|
# this function itself is not vectorized, |
|
# and should only be used within a loop or mapping function. |
|
if (length(x) > 1) return(FALSE) |
|
return(is.na(x)) |
|
} |
|
|
|
write_body <- function(date, mood, activities, title, entry) { |
|
# put it all together to create the data to be sent, as a list. |
|
# assemble properties: mandatory and optional |
|
properties <- list( |
|
title = write_title(title), |
|
Entered = write_date(date) |
|
) |
|
if (!is.na(mood)) properties$Mood <- write_select(mood) |
|
if (!is_na(activities)) properties$Activities <- write_tags(activities) |
|
|
|
# assemble page: parent and properties |
|
resp <- list( |
|
parent = list(database_id = database_id), |
|
properties = properties |
|
) |
|
|
|
# add content to page |
|
if (!is_na(entry)) resp$children <- write_content(entry) |
|
|
|
resp |
|
} |
|
|
|
send_entry <- function(body) { |
|
# send the entry. return the Notion API response. |
|
resp <- POST( |
|
url = glue("{api_url}/pages"), |
|
body = body, |
|
config = add_headers(.headers = headers) |
|
) |
|
content(resp) |
|
} |
|
|
|
# read in my entries as exported from Daylio, process them, & export to Notion! |
|
# save the API responses for reference and troubleshooting. |
|
# activities are pipe-delimited. |
|
# in entries, paragraphs are delimited by double spaces. |
|
# every Notion response has an "object" key. |
|
# in this case, object is either "page" or "error." |
|
x <- |
|
here() |> |
|
dir_ls(type = "file", regexp = r"{daylio.*\.csv}") |> |
|
read_csv() |> |
|
arrange(full_date, time) |> |
|
mutate( |
|
date = ymd_hms(paste(full_date, time)), |
|
activities = str_split(activities, r"{ \| }"), |
|
title = title_from_date(date), |
|
entry = str_split(note, " "), |
|
data_list = pmap(list(date, mood, activities, title, entry), write_body), |
|
body = map_chr(data_list, toJSON, auto_unbox = TRUE), |
|
response = map(body, send_entry), |
|
response_type = map_chr(response, ~.x$object) |
|
) |> |
|
select(-c(full_date, weekday, time, note, note_title)) |
|
|
|
saveRDS(x, file = here("responses.rds")) |
|
|
|
save.image() |