186 lines
6.4 KiB
Nim
186 lines
6.4 KiB
Nim
import std/httpclient, std/json, std/logging, std/sequtils, std/tables, std/strutils
|
|
|
|
import buffoonery/jsonutils
|
|
|
|
import hff_notion_api_client/config
|
|
import hff_notion_api_client/models
|
|
import hff_notion_api_client/sequtils_ext
|
|
import hff_notion_api_client/utils
|
|
|
|
type
|
|
NotionClientConfig* = object
|
|
apiBaseUrl*: string
|
|
apiVersion*: string
|
|
configDbId*: string
|
|
integrationToken*: string
|
|
|
|
NotionClient* = ref object
|
|
http: HttpClient
|
|
apiBaseUrl: string
|
|
config*: HffNotionConfig
|
|
|
|
proc loadNotionConfig(http: HttpClient, cfg: NotionClientConfig): HffNotionConfig =
|
|
let url = cfg.apiBaseUrl & "/databases/" & cfg.configDbId & "/query"
|
|
let body = $(%*{ "page_size": NOTION_MAX_PAGE_SIZE })
|
|
|
|
debug "loadNotionConfig\n\tPOST " & url & "\n\t" & $body
|
|
let resp = http.postContent(url, body)
|
|
let resultsJson = parseJson(resp)["results"]
|
|
|
|
result = parseHffNotionConfig(resultsJson)
|
|
|
|
proc initNotionClient*(cfg: NotionClientConfig): NotionClient =
|
|
result = NotionClient(
|
|
apiBaseUrl: cfg.apiBaseUrl,
|
|
http: newHttpClient(headers = newHttpHeaders([
|
|
("Content-Type", "application/json"),
|
|
("Authorization", "Bearer " & cfg.integrationToken),
|
|
("Notion-Version", cfg.apiVersion)
|
|
], true)))
|
|
|
|
result.config = result.http.loadNotionConfig(cfg)
|
|
|
|
proc `%`*(c: NotionClientConfig): JsonNode =
|
|
%*{
|
|
"apiBaseUrl": c.apiBaseUrl,
|
|
"apiVersion": c.apiVersion,
|
|
"configDbId": c.configDbId,
|
|
"integrationToken": c.integrationToken
|
|
}
|
|
|
|
proc parseNotionClientConfig*(n: JsonNode): NotionClientConfig =
|
|
NotionClientConfig(
|
|
apiBaseUrl: n.getOrFail("apiBaseUrl").getStr,
|
|
apiVersion: n.getOrFail("apiVersion").getStr,
|
|
configDbId: n.getOrFail("configDbId").getStr,
|
|
integrationToken: n.getOrFail("integrationToken").getStr)
|
|
|
|
proc fetchAllPages*(
|
|
http: HttpClient,
|
|
url: string,
|
|
bodyTemplate = %*{ "page_size": NOTION_MAX_PAGE_SIZE}): seq[JsonNode] =
|
|
|
|
result = @[]
|
|
var nextCursor: string = ""
|
|
|
|
while true:
|
|
let body = parseJson($bodyTemplate)
|
|
if not nextCursor.isEmptyOrWhitespace: body["start_cursor"] = %nextCursor
|
|
|
|
debug "Fetching pages from database:\n\tPOST " & url & "\n\t" & $body
|
|
let jsonResp = parseJson(http.postContent(url, $body))
|
|
|
|
result = result & jsonResp["results"].getElems
|
|
if jsonResp.hasKey("next_cursor") and jsonResp["next_cursor"].kind != JNull:
|
|
nextCursor = jsonResp["next_cursor"].getStr
|
|
|
|
if nextCursor.isEmptyOrWhitespace: break
|
|
|
|
template fetchDatabaseObject*(notion: NotionClient, dbId: string): untyped =
|
|
let resp = notion.http.get(notion.apiBaseUrl & "/databases/" & dbId)
|
|
|
|
if not resp.status.startsWith("2"):
|
|
debug resp.body
|
|
raise newException(HttpRequestError, "API Request failed: " & resp.body)
|
|
parseJson(resp.body)
|
|
|
|
template fetchPage*(notion: NotionClient, pageId: string): untyped =
|
|
let resp = notion.http.get(notion.apiBaseUrl & "/pages/" & pageId)
|
|
|
|
if not resp.status.startsWith("2"):
|
|
debug resp.body
|
|
raise newException(HttpRequestError, "API Request failed: " & resp.body)
|
|
parseJson(resp.body)
|
|
|
|
template createDbPage*(notion: NotionClient, parentDbId: string, r: typed): untyped =
|
|
let page = r.toPage
|
|
page["parent"] = %*{ "database_id": parentDbId }
|
|
|
|
let resp = notion.http.post(notion.apiBaseUrl & "/pages", $page)
|
|
|
|
if not resp.status.startsWith("2"):
|
|
debug resp.body
|
|
raise newException(HttpRequestError, "API Request failed: " & resp.body)
|
|
parseJson(resp.body)
|
|
|
|
template updatePage*(notion: NotionClient, r: typed): JsonNode =
|
|
let page = r.toPage
|
|
|
|
let resp = notion.http.patch(notion.apiBaseUrl & "/pages/" & r.id, $page)
|
|
|
|
if not resp.status.startsWith("2"): debug resp.body
|
|
parseJson(resp.body)
|
|
|
|
template delete*(notion: NotionClient, r: typed): string =
|
|
let resp = notion.http.delete(notion.apiBaseUrl & "/blocks/" & r.id)
|
|
|
|
if not resp.status.startsWith("2"): debug resp.body
|
|
parseJson(resp.body)["id"].getStr
|
|
|
|
proc fetchSyncRecords*(notion: NotionClient): seq[SyncRecord] =
|
|
let respRecords = notion.http.fetchAllPages(
|
|
notion.apiBaseUrl & "/databases/" & notion.config.syncRecordsDbId & "/query")
|
|
|
|
return respRecords.mapIt(syncRecordFromPage(it))
|
|
|
|
proc create*(notion: NotionClient, r: SyncRecord): SyncRecord =
|
|
return syncRecordFromPage(createDbPage(notion, notion.config.syncRecordsDbId, r))
|
|
|
|
proc update*(notion: NotionClient, r: SyncRecord): SyncRecord =
|
|
return syncRecordFromPage(updatePage(notion, r))
|
|
|
|
proc fetchAddress*(notion: NotionClient, addressId: string): Address =
|
|
return addressFromPage(notion.fetchPage(addressId))
|
|
|
|
proc fetchAddresses*(notion: NotionClient): seq[Address] =
|
|
let respRecords = notion.http.fetchAllPages(
|
|
notion.apiBaseUrl & "/databases/" & notion.config.addressesDbId & "/query")
|
|
|
|
return resprecords.mapIt(addressFromPage(it))
|
|
|
|
proc create*(notion: NotionClient, a: Address): Address =
|
|
return addressFromPage(notion.createDbPage(notion.config.addressesDbId , a))
|
|
|
|
proc update*(notion: NotionClient, r: Address): Address =
|
|
return addressFromPage(updatePage(notion, r))
|
|
|
|
proc fetchFamily*(notion: NotionClient, familyId: string): Family =
|
|
return familyFromPage(notion.fetchPage(familyId))
|
|
|
|
proc fetchFamilies*(notion: NotionClient): seq[Family] =
|
|
let respRecords = notion.http.fetchAllPages(
|
|
notion.apiBaseUrl & "/databases/" & notion.config.familiesDbId & "/query")
|
|
|
|
return respRecords.mapIt(familyFromPage(it))
|
|
|
|
proc create*(notion: NotionClient, f: Family): Family =
|
|
return familyFromPage(notion.createDbPage(notion.config.familiesDbId , f))
|
|
|
|
proc update*(notion: NotionClient, r: Family): Family =
|
|
return familyFromPage(updatePage(notion, r))
|
|
|
|
proc fetchPerson*(notion: NotionClient, personId: string): Person =
|
|
return personFromPage(notion.fetchPage(personId))
|
|
|
|
proc fetchPeople*(notion: NotionClient): seq[Person] =
|
|
let respRecords = notion.http.fetchAllPages(
|
|
notion.apiBaseUrl & "/databases/" & notion.config.peopleDbId & "/query")
|
|
|
|
return respRecords.mapIt(personFromPage(it))
|
|
|
|
proc create*(notion: NotionClient, p: Person): Person =
|
|
return personFromPage(notion.createDbPage(notion.config.peopleDbId, p))
|
|
|
|
proc update*(notion: NotionClient, r: Person): Person =
|
|
return personFromPage(updatePage(notion, r))
|
|
|
|
proc persist*[T](notion: NotionClient, r: T): T =
|
|
if r.id.isEmptyOrWhitespace: notion.create(r)
|
|
else: notion.update(r)
|
|
|
|
proc fetchMembershipDataSet*(notion: NotionClient): MembershipDataSet =
|
|
result = MembershipDataSet(
|
|
addresses: mapById(notion.fetchAddresses()),
|
|
families: mapById(notion.fetchFamilies()),
|
|
people: mapById(notion.fetchPeople()))
|