aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/todo/README.md19
-rw-r--r--examples/todo/commands.rs1
-rw-r--r--examples/todo/commands/configure.rs70
-rw-r--r--examples/todo/main.rs76
4 files changed, 166 insertions, 0 deletions
diff --git a/examples/todo/README.md b/examples/todo/README.md
new file mode 100644
index 0000000..b22d08b
--- /dev/null
+++ b/examples/todo/README.md
@@ -0,0 +1,19 @@
+# Notion database todo example
+
+This example is builds a todo list using a notion database.
+
+## Setup your notion api token
+
+Create an `internal` integration here: https://www.notion.so/my-integrations
+
+```bash
+ export NOTION_API_TOKEN='secret_token_here'
+```
+> Notice the space before the export command.
+> This will prevent your terminal from storing this token in your shell history...
+
+## Selecting the database to use
+
+```bash
+cargo run --example todo -- config
+```
diff --git a/examples/todo/commands.rs b/examples/todo/commands.rs
new file mode 100644
index 0000000..a78a393
--- /dev/null
+++ b/examples/todo/commands.rs
@@ -0,0 +1 @@
+pub mod configure;
diff --git a/examples/todo/commands/configure.rs b/examples/todo/commands/configure.rs
new file mode 100644
index 0000000..42ffafd
--- /dev/null
+++ b/examples/todo/commands/configure.rs
@@ -0,0 +1,70 @@
+use crate::TodoConfig;
+use anyhow::Result;
+use notion::models::search::NotionSearch;
+use notion::models::{Database, DatabaseId};
+use notion::{AsIdentifier, NotionApi};
+use skim::{Skim, SkimItem, SkimItemReceiver, SkimItemSender, SkimOptions};
+use std::borrow::Cow;
+use std::ops::Deref;
+use std::sync::Arc;
+
+fn skim_select_database(databases: Vec<Database>) -> Result<DatabaseId> {
+ let options = SkimOptions::default();
+
+ let (sender, receiver): (SkimItemSender, SkimItemReceiver) = crossbeam_channel::bounded(500);
+
+ struct SkimDB {
+ db: Database,
+ }
+
+ impl SkimItem for SkimDB {
+ fn text(&self) -> Cow<str> {
+ Cow::Owned(self.db.title_plain_text())
+ }
+ }
+
+ for db in databases {
+ sender.send(Arc::new(SkimDB { db }))?;
+ }
+
+ // `run_with` would read and show items from the stream
+ let selected_items = Skim::run_with(&options, Some(receiver))
+ .filter(|out| !out.is_abort)
+ .map(|out| out.selected_items)
+ .unwrap_or_else(|| Vec::new());
+
+ let db = selected_items
+ .first()
+ .expect("No database selected, aborting...")
+ .clone();
+ let db: &SkimDB = db
+ .deref()
+ .as_any()
+ .downcast_ref()
+ .expect("Couldn't cast back to SkimDB");
+
+ let database_id = db.db.id();
+
+ Ok(database_id)
+}
+
+pub async fn configure(notion_api: NotionApi) -> Result<()> {
+ let databases: Vec<Database> = notion_api
+ .search(NotionSearch::filter_by_databases())
+ .await?
+ .only_databases()
+ .results;
+
+ let database_id = skim_select_database(databases)?;
+
+ println!("Selected database's id: {}", database_id);
+
+ let bytes = toml::to_vec(&TodoConfig {
+ api_token: None,
+ task_database_id: Some(database_id),
+ })?;
+
+ std::fs::write("../todo_config.toml", bytes)?;
+
+ Ok(())
+}
diff --git a/examples/todo/main.rs b/examples/todo/main.rs
new file mode 100644
index 0000000..2283549
--- /dev/null
+++ b/examples/todo/main.rs
@@ -0,0 +1,76 @@
+mod commands;
+
+use anyhow::{Context, Result};
+use clap::Clap;
+use notion::models::DatabaseId;
+use notion::NotionApi;
+use serde::{Deserialize, Serialize};
+
+// https://docs.rs/clap/3.0.0-beta.2/clap/
+#[derive(Clap)]
+#[clap(version = "1.0", author = "Kevin K. <kbknapp@gmail.com>")]
+struct Opts {
+ #[clap(subcommand)]
+ command: SubCommand,
+}
+
+#[derive(Clap)]
+enum SubCommand {
+ /// Configure what database this notion-todo example uses
+ Config,
+ /// List all todos
+ List,
+ /// Add a todo item to the notion database
+ Add,
+ /// Complete a todo item
+ Check,
+}
+
+#[derive(Deserialize, Serialize)]
+struct TodoConfig {
+ api_token: Option<String>,
+ task_database_id: Option<DatabaseId>,
+}
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ let opts: Opts = Opts::parse();
+
+ // https://docs.rs/config/0.11.0/config/
+ let config = config::Config::default()
+ .with_merged(config::File::with_name("todo_config"))
+ .unwrap_or_default()
+ .with_merged(config::Environment::with_prefix("NOTION"))?;
+
+ let config: TodoConfig = config.try_into().context("Failed to read config")?;
+
+ let notion_api = NotionApi::new(
+ std::env::var("NOTION_API_TOKEN")
+ .or(config
+ .api_token
+ .ok_or(anyhow::anyhow!("No api token from config")))
+ .context(
+ "No Notion API token found in either the environment variable \
+ `NOTION_API_TOKEN` or the config file!",
+ )?,
+ )?;
+
+ match opts.command {
+ SubCommand::Config => commands::configure::configure(notion_api).await,
+ SubCommand::List => list_tasks(notion_api),
+ SubCommand::Add => add_task(notion_api),
+ SubCommand::Check => complete_task(notion_api),
+ }
+}
+
+fn list_tasks(_notion_api: NotionApi) -> Result<()> {
+ Ok(())
+}
+
+fn add_task(_notion_api: NotionApi) -> Result<()> {
+ Ok(())
+}
+
+fn complete_task(_notion_api: NotionApi) -> Result<()> {
+ Ok(())
+}