pub mod structs;
use crate::structs::block::*;
use crate::structs::common::*;
use crate::structs::database::*;
use crate::structs::page::*;
use crate::structs::query_filter::*;
use anyhow::{Error, Result};
use dotenvy::dotenv;
use reqwest as request;
#[derive(Debug)]
pub struct Notion {
pub api_key: String,
pub database_id: String,
}
impl Notion {
pub fn new() -> Self {
dotenv().ok();
let api_key = std::env::var("NOTION_API_KEY").expect("NOTION_API_KEY must be set");
let database_id = std::env::var("NOTION_DATABASE_ID").unwrap_or("".to_string());
Notion {
api_key,
database_id,
}
}
pub fn database(&mut self, database_id: String) -> &mut Self {
self.database_id = database_id.to_string();
return self;
}
pub async fn retrieve_a_database(&self) -> Result<Database> {
let url = format!("https://api.notion.com/v1/databases/{}", self.database_id);
let client = request::Client::new();
let content = client
.get(&url)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", self.api_key))
.header("Notion-Version", "2022-06-28")
.send()
.await?
.text()
.await?;
let mut database = serde_json::from_str::<Database>(&content)?;
if database.status == 0 {
database.status = 200;
}
return Ok(database);
}
pub async fn query_database(&self, filter: QueryFilter) -> Result<PageResponse> {
let url = format!(
"https://api.notion.com/v1/databases/{}/query",
self.database_id
);
let query = filter.build();
let client = request::Client::new();
let content = client
.post(&url)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", self.api_key))
.header("Notion-Version", "2022-06-28")
.body(query)
.send()
.await?
.text()
.await?;
let mut response = serde_json::from_str::<PageResponse>(&content)?;
if response.status != 0 {
return Err(Error::msg(
format!("Failed to query database: {}", response.message).to_string(),
));
} else {
response.status = 200;
}
return Ok(response);
}
pub async fn create_a_page(&self, page: &Page) -> Result<Page> {
let url = "https://api.notion.com/v1/pages";
let client = request::Client::new();
let data = serde_json::to_string(page)?;
let content = client
.post(url)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", self.api_key))
.header("Notion-Version", "2022-06-28")
.body(data)
.send()
.await?
.text()
.await?;
let mut page = serde_json::from_str::<Page>(&content)?;
if page.status != 0 {
return Err(Error::msg(
format!("Failed to create page: {}", page.message).to_string(),
));
} else {
page.status = 200;
}
return Ok(page);
}
pub async fn update_a_page(&self, page_id: String, page: &Page) -> Result<Page> {
let url = format!("https://api.notion.com/v1/pages/{}", page_id);
let client = request::Client::new();
let data = serde_json::to_string(page)?;
let content = client
.patch(&url)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", self.api_key))
.header("Notion-Version", "2022-06-28")
.body(data)
.send()
.await?
.text()
.await?;
let mut page = serde_json::from_str::<Page>(&content)?;
if page.status != 0 {
return Err(Error::msg(
format!("Failed to update page: {}", page.message).to_string(),
));
} else {
page.status = 200;
}
return Ok(page);
}
pub async fn archive_a_page(
&self,
page_id: String,
parent_id: String,
parent_type: ParentType,
) -> Result<Page> {
let mut page = Page {
archived: true,
..Default::default()
};
match parent_type {
ParentType::Database => {
page.parent.type_name = parent_type;
page.parent.database_id = Some(parent_id.to_string());
}
ParentType::Page => {
page.parent.type_name = parent_type;
page.parent.page_id = Some(parent_id.to_string());
}
ParentType::Workspace => {
page.parent.type_name = parent_type;
page.parent.workspace_id = Some(parent_id.to_string());
}
ParentType::Block => {
page.parent.type_name = parent_type;
page.parent.block_id = Some(parent_id.to_string());
}
}
let page = self.update_a_page(page_id, &page).await?;
return Ok(page);
}
pub async fn append_block_children(
&self,
parent_id: String,
blocks: Vec<Block>,
) -> Result<BlockResponse> {
let url = format!("https://api.notion.com/v1/blocks/{}/children", parent_id);
let client = request::Client::new();
let mut res_blocks: Vec<Block> = Vec::new();
for i in (0..blocks.len()).step_by(100) {
let end_index = std::cmp::min(i + 100, blocks.len());
let block_body = BlockBody {
children: blocks[i..end_index].to_vec(),
};
let data = serde_json::to_string(&block_body)?;
let content = client
.patch(&url)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", self.api_key))
.header("Notion-Version", "2022-06-28")
.body(data)
.send()
.await?
.text()
.await?;
let _bby = serde_json::from_str::<BlockResponse>(&content)?;
if _bby.status != 0 {
return Err(Error::msg(
format!("Failed to append block children: {}", _bby.message).to_string(),
));
} else {
res_blocks.extend(_bby.results);
}
}
let res_block = BlockResponse {
object: "list".to_string(),
results: res_blocks,
status: 200,
..Default::default()
};
return Ok(res_block);
}
}
#[cfg(test)]
mod tests;