nblm_core/client/api/
notebooks.rs

1use reqwest::Method;
2
3use crate::error::Result;
4use crate::models::{
5    AccountRole, BatchDeleteNotebooksRequest, BatchDeleteNotebooksResponse, CreateNotebookRequest,
6    ListRecentlyViewedResponse, Notebook, ShareRequest, ShareResponse,
7};
8
9use crate::client::NblmClient;
10
11const PAGE_SIZE_MIN: u32 = 1;
12const PAGE_SIZE_MAX: u32 = 500;
13
14/// Notebook-related API implementations
15impl NblmClient {
16    pub async fn create_notebook(&self, title: impl Into<String>) -> Result<Notebook> {
17        let url = self
18            .url_builder
19            .build_url(&self.url_builder.notebooks_collection())?;
20        let request = CreateNotebookRequest {
21            title: title.into(),
22        };
23        self.http
24            .request_json(Method::POST, url, Some(&request))
25            .await
26    }
27
28    /// Delete notebooks using the batchDelete API.
29    ///
30    /// # Known Issues (as of 2025-10-19)
31    ///
32    /// The API only accepts a single notebook name despite being named "batchDelete".
33    /// Multiple names result in HTTP 400 error. Use `delete_notebooks` which handles
34    /// this limitation by calling the API once per notebook.
35    pub async fn batch_delete_notebooks(
36        &self,
37        request: BatchDeleteNotebooksRequest,
38    ) -> Result<BatchDeleteNotebooksResponse> {
39        let path = format!("{}:batchDelete", self.url_builder.notebooks_collection());
40        let url = self.url_builder.build_url(&path)?;
41        self.http
42            .request_json(Method::POST, url, Some(&request))
43            .await
44    }
45
46    /// Delete one or more notebooks.
47    ///
48    /// # Implementation Note
49    ///
50    /// Despite the underlying API being named "batchDelete", it only accepts one notebook
51    /// at a time (as of 2025-10-19). This method works around this limitation by calling
52    /// the API sequentially for each notebook.
53    pub async fn delete_notebooks(
54        &self,
55        notebook_names: Vec<String>,
56    ) -> Result<BatchDeleteNotebooksResponse> {
57        // TODO: Remove sequential processing when API supports true batch deletion
58        for name in &notebook_names {
59            let request = BatchDeleteNotebooksRequest {
60                names: vec![name.clone()],
61            };
62            self.batch_delete_notebooks(request).await?;
63        }
64        // Return empty response after all deletions succeed
65        Ok(BatchDeleteNotebooksResponse::default())
66    }
67
68    // TODO: This method has not been tested due to the requirement of setting up additional user accounts.
69    pub async fn share_notebook(
70        &self,
71        notebook_id: &str,
72        accounts: Vec<AccountRole>,
73    ) -> Result<ShareResponse> {
74        let path = format!("{}:share", self.url_builder.notebook_path(notebook_id));
75        let url = self.url_builder.build_url(&path)?;
76        let request = ShareRequest {
77            account_and_roles: accounts,
78        };
79        self.http
80            .request_json(Method::POST, url, Some(&request))
81            .await
82    }
83
84    /// List recently viewed notebooks.
85    ///
86    /// # Pagination
87    ///
88    /// The `page_size` parameter can be used to limit the number of results.
89    /// Valid range is 1-500. Default is 500 notebooks.
90    pub async fn list_recently_viewed(
91        &self,
92        page_size: Option<u32>,
93    ) -> Result<ListRecentlyViewedResponse> {
94        let path = format!(
95            "{}:listRecentlyViewed",
96            self.url_builder.notebooks_collection()
97        );
98        let mut url = self.url_builder.build_url(&path)?;
99        if let Some(size) = page_size {
100            let clamped = size.clamp(PAGE_SIZE_MIN, PAGE_SIZE_MAX);
101            url.query_pairs_mut()
102                .append_pair("pageSize", &clamped.to_string());
103        }
104        self.http
105            .request_json::<(), _>(Method::GET, url, None::<&()>)
106            .await
107    }
108}