defmodule Notion do
@moduledoc false
def get_documentation do
File.ls!("#{__DIR__}/docs")
|> format_documentation
end
defp format_documentation(files) do
Enum.reduce(files, %{}, fn file, module_names ->
json =
File.read!("#{__DIR__}/docs/#{file}")
|> Jason.decode!()
doc = Notion.Documentation.new(json, file)
module_names
|> Map.put_new(doc.module, [])
|> update_in([doc.module], &(&1 ++ [doc]))
end)
end
end
alias Notion.Documentation
require Logger
Enum.each(Notion.get_documentation(), fn {module_name, functions} ->
module =
module_name
|> String.split(".")
|> Enum.map(&Macro.camelize/1)
|> Enum.reduce(Notion, &Module.concat(&2, &1))
Logger.warning("module: #{inspect(module)}", "🐛": :" 355217549")
defmodule module do
Enum.each(functions, fn doc ->
function_name = doc.function
path_params_with_values = Documentation.path_params_with_values(doc)
function_arguments = Documentation.function_arguments(doc)
required_params_with_values = Documentation.required_params_with_values(doc)
@doc """
#{Documentation.to_doc_string(doc)}
"""
def unquote(function_name)(unquote_splicing(function_arguments), optional_params \\ %{})
when is_map(optional_params) do
required_params_map = Enum.into(unquote(required_params_with_values), %{})
# Logger.warning("required_params_map: #{inspect(required_params_map)}", "🐛": :" 1231437220")
url = Application.get_env(:notion_api, :base_url, "https://api.notion.com")
# path_params are substituted into the url in the path_parameter_substition funtion
# the remaining required and optional params are mereged here and eventually converted to JSON in the body_params_processing function
param_map =
optional_params
# strip out empty optional params. importantly, retain empty required params
|> Map.reject(fn {_, v} -> v == nil end)
|> Map.merge(required_params_map)
# token is special case we inject into header
|> Map.reject(fn {k, _} -> k == :token end)
|> Enum.map(fn {key, val} ->
# Logger.warning("param key: #{inspect(key)}", "🐛": :" 801437221")
# Logger.warning("param val: #{inspect(val)}", "🐛": :" 801437222")
convert_param_value(key, val)
end)
# convert into map
|> Enum.into(%{})
# Logger.warning("param_map: #{inspect(param_map)}", "🐛": :" 801437223")
# Logger.warning(
# "unq path_params_with_values: #{inspect(unquote(path_params_with_values))}",
# "🐛": :" 801437224"
# )
# Logger.warning(
# "argument_value_keyword_list: #{inspect(unquote(argument_value_keyword_list))}",
# "🐛": :" 801437225"
# )
url_path =
path_parameter_substition(unquote(doc.endpoint), unquote(path_params_with_values))
headers = [
{"Content-Type", "application/json; charset=utf-8"},
{"Authorization", "Bearer #{get_token(optional_params)}"},
{"Notion-Version", "2022-02-22"}
]
case unquote(doc.function) do
:get ->
get!(
"#{url}/#{url_path}",
headers
)
:patch ->
patch!(
"#{url}/#{url_path}",
headers,
body_params_processing(
unquote(function_name),
param_map,
unquote(function_arguments)
)
)
:post ->
post!(
"#{url}/#{url_path}",
headers,
body_params_processing(
unquote(function_name),
param_map,
unquote(function_arguments)
)
)
:delete ->
Logger.error("TODO 3577386783", "🐛": :" 3577386783")
_ ->
Logger.error("Should never get here", "🐛": :" 3577386789")
end
end
end)
defp get!(url, headers) do
# Logger.warning("get: #{inspect(url)}", "🐛": :" 12345280240")
Application.get_env(:notion_api, :web_http_client, Notion.DefaultClient).get!(url, headers)
end
defp post!(url, headers, body) do
# Logger.warning("post: #{inspect(url)}", "🐛": :" 12345280440")
# Logger.warning("post: #{inspect(headers)}", "🐛": :" 12345280441")
# Logger.warning("post: #{inspect(body)}", "🐛": :" 12345280442")
Application.get_env(:notion_api, :web_http_client, Notion.DefaultClient).post!(
url,
headers,
body
)
end
defp patch!(url, headers, body) do
# Logger.warning("patch: #{inspect(url)}", "🐛": :" 1234215315")
# Logger.warning("patch: #{inspect(headers)}", "🐛": :" 1234215316")
# Logger.warning("patch: #{inspect(body)}", "🐛": :" 1234215317")
Application.get_env(:notion_api, :web_http_client, Notion.DefaultClient).patch!(
url,
headers,
body
)
end
defp get_token(%{token: token}), do: token
defp get_token(_), do: Application.get_env(:notion_api, :internal_integration_token)
# if we have any non-Jason supported types, we can convert them here
defp convert_param_value(key, value) do
{key, value}
end
defp path_parameter_substition(endpoint, path_params_with_values) do
# Logger.warning("path_parameter_substition endpoint: #{inspect(endpoint)}",
# "🐛": :" 1339620391"
# )
# Logger.warning(
# "path_parameter_substition path_params_with_values: #{inspect(path_params_with_values)}",
# "🐛": :" 1339620392"
# )
Enum.reduce(path_params_with_values, endpoint, fn {key, val}, acc ->
# Logger.warning("{key, val}: #{inspect({key, val})}", "🐛": :" 794991620")
# Logger.warning("acc: #{inspect(acc)}", "🐛": :" 794991620")
path_sub_key = to_string(key)
String.replace(acc, path_sub_key, val)
end)
# |> tap(fn x ->
# Logger.warning("path_parameter_substition return value: #{inspect(x)}",
# "🐛": :" 3580239419"
# )
# end)
end
# notion API seems to only use JASON for reqest body and response body
defp body_params_processing(_, params, _) do
Jason.encode!(params)
end
end
end)