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()))
 |