| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | import json | 
					
						
							|  |  |  | import logging | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  | from typing import List, Dict, Any, Optional | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  | import requests | 
					
						
							|  |  |  | from flask import current_app | 
					
						
							|  |  |  | from langchain.document_loaders.base import BaseLoader | 
					
						
							|  |  |  | from langchain.schema import Document | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  | from extensions.ext_database import db | 
					
						
							|  |  |  | from models.dataset import Document as DocumentModel | 
					
						
							|  |  |  | from models.source import DataSourceBinding | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | logger = logging.getLogger(__name__) | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | BLOCK_CHILD_URL_TMPL = "https://api.notion.com/v1/blocks/{block_id}/children" | 
					
						
							|  |  |  | DATABASE_URL_TMPL = "https://api.notion.com/v1/databases/{database_id}/query" | 
					
						
							|  |  |  | SEARCH_URL = "https://api.notion.com/v1/search" | 
					
						
							| 
									
										
										
										
											2023-09-27 16:06:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | RETRIEVE_PAGE_URL_TMPL = "https://api.notion.com/v1/pages/{page_id}" | 
					
						
							|  |  |  | RETRIEVE_DATABASE_URL_TMPL = "https://api.notion.com/v1/databases/{database_id}" | 
					
						
							|  |  |  | HEADING_TYPE = ['heading_1', 'heading_2', 'heading_3'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  | class NotionLoader(BaseLoader): | 
					
						
							|  |  |  |     def __init__( | 
					
						
							|  |  |  |             self, | 
					
						
							|  |  |  |             notion_access_token: str, | 
					
						
							|  |  |  |             notion_workspace_id: str, | 
					
						
							|  |  |  |             notion_obj_id: str, | 
					
						
							|  |  |  |             notion_page_type: str, | 
					
						
							|  |  |  |             document_model: Optional[DocumentModel] = None | 
					
						
							|  |  |  |     ): | 
					
						
							|  |  |  |         self._document_model = document_model | 
					
						
							|  |  |  |         self._notion_workspace_id = notion_workspace_id | 
					
						
							|  |  |  |         self._notion_obj_id = notion_obj_id | 
					
						
							|  |  |  |         self._notion_page_type = notion_page_type | 
					
						
							|  |  |  |         self._notion_access_token = notion_access_token | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not self._notion_access_token: | 
					
						
							|  |  |  |             integration_token = current_app.config.get('NOTION_INTEGRATION_TOKEN') | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |             if integration_token is None: | 
					
						
							|  |  |  |                 raise ValueError( | 
					
						
							|  |  |  |                     "Must specify `integration_token` or set environment " | 
					
						
							|  |  |  |                     "variable `NOTION_INTEGRATION_TOKEN`." | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |             self._notion_access_token = integration_token | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def from_document(cls, document_model: DocumentModel): | 
					
						
							|  |  |  |         data_source_info = document_model.data_source_info_dict | 
					
						
							|  |  |  |         if not data_source_info or 'notion_page_id' not in data_source_info \ | 
					
						
							|  |  |  |                 or 'notion_workspace_id' not in data_source_info: | 
					
						
							|  |  |  |             raise ValueError("no notion page found") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         notion_workspace_id = data_source_info['notion_workspace_id'] | 
					
						
							|  |  |  |         notion_obj_id = data_source_info['notion_page_id'] | 
					
						
							|  |  |  |         notion_page_type = data_source_info['type'] | 
					
						
							|  |  |  |         notion_access_token = cls._get_access_token(document_model.tenant_id, notion_workspace_id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return cls( | 
					
						
							|  |  |  |             notion_access_token=notion_access_token, | 
					
						
							|  |  |  |             notion_workspace_id=notion_workspace_id, | 
					
						
							|  |  |  |             notion_obj_id=notion_obj_id, | 
					
						
							|  |  |  |             notion_page_type=notion_page_type, | 
					
						
							|  |  |  |             document_model=document_model | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def load(self) -> List[Document]: | 
					
						
							|  |  |  |         self.update_last_edited_time( | 
					
						
							|  |  |  |             self._document_model | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         text_docs = self._load_data_as_documents(self._notion_obj_id, self._notion_page_type) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return text_docs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _load_data_as_documents( | 
					
						
							|  |  |  |             self, notion_obj_id: str, notion_page_type: str | 
					
						
							|  |  |  |     ) -> List[Document]: | 
					
						
							|  |  |  |         docs = [] | 
					
						
							|  |  |  |         if notion_page_type == 'database': | 
					
						
							|  |  |  |             # get all the pages in the database | 
					
						
							| 
									
										
										
										
											2023-06-28 13:58:50 +08:00
										 |  |  |             page_text_documents = self._get_notion_database_data(notion_obj_id) | 
					
						
							|  |  |  |             docs.extend(page_text_documents) | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         elif notion_page_type == 'page': | 
					
						
							|  |  |  |             page_text_list = self._get_notion_block_data(notion_obj_id) | 
					
						
							|  |  |  |             for page_text in page_text_list: | 
					
						
							|  |  |  |                 docs.append(Document(page_content=page_text)) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise ValueError("notion page type not supported") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return docs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _get_notion_database_data( | 
					
						
							|  |  |  |             self, database_id: str, query_dict: Dict[str, Any] = {} | 
					
						
							| 
									
										
										
										
											2023-06-28 13:58:50 +08:00
										 |  |  |     ) -> List[Document]: | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         """Get all the pages from a Notion database.""" | 
					
						
							|  |  |  |         res = requests.post( | 
					
						
							|  |  |  |             DATABASE_URL_TMPL.format(database_id=database_id), | 
					
						
							|  |  |  |             headers={ | 
					
						
							|  |  |  |                 "Authorization": "Bearer " + self._notion_access_token, | 
					
						
							|  |  |  |                 "Content-Type": "application/json", | 
					
						
							|  |  |  |                 "Notion-Version": "2022-06-28", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             json=query_dict, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         data = res.json() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         database_content_list = [] | 
					
						
							|  |  |  |         if 'results' not in data or data["results"] is None: | 
					
						
							| 
									
										
										
										
											2023-06-28 13:58:50 +08:00
										 |  |  |             return [] | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         for result in data["results"]: | 
					
						
							|  |  |  |             properties = result['properties'] | 
					
						
							|  |  |  |             data = {} | 
					
						
							|  |  |  |             for property_name, property_value in properties.items(): | 
					
						
							|  |  |  |                 type = property_value['type'] | 
					
						
							|  |  |  |                 if type == 'multi_select': | 
					
						
							|  |  |  |                     value = [] | 
					
						
							|  |  |  |                     multi_select_list = property_value[type] | 
					
						
							|  |  |  |                     for multi_select in multi_select_list: | 
					
						
							|  |  |  |                         value.append(multi_select['name']) | 
					
						
							|  |  |  |                 elif type == 'rich_text' or type == 'title': | 
					
						
							|  |  |  |                     if len(property_value[type]) > 0: | 
					
						
							|  |  |  |                         value = property_value[type][0]['plain_text'] | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         value = '' | 
					
						
							|  |  |  |                 elif type == 'select' or type == 'status': | 
					
						
							|  |  |  |                     if property_value[type]: | 
					
						
							|  |  |  |                         value = property_value[type]['name'] | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         value = '' | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     value = property_value[type] | 
					
						
							|  |  |  |                 data[property_name] = value | 
					
						
							| 
									
										
										
										
											2023-06-27 17:15:03 +08:00
										 |  |  |             row_dict = {k: v for k, v in data.items() if v} | 
					
						
							|  |  |  |             row_content = '' | 
					
						
							|  |  |  |             for key, value in row_dict.items(): | 
					
						
							|  |  |  |                 if isinstance(value, dict): | 
					
						
							|  |  |  |                     value_dict = {k: v for k, v in value.items() if v} | 
					
						
							|  |  |  |                     value_content = ''.join(f'{k}:{v} ' for k, v in value_dict.items()) | 
					
						
							|  |  |  |                     row_content = row_content + f'{key}:{value_content}\n' | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     row_content = row_content + f'{key}:{value}\n' | 
					
						
							| 
									
										
										
										
											2023-06-28 13:58:50 +08:00
										 |  |  |             document = Document(page_content=row_content) | 
					
						
							|  |  |  |             database_content_list.append(document) | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-28 13:58:50 +08:00
										 |  |  |         return database_content_list | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _get_notion_block_data(self, page_id: str) -> List[str]: | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |         result_lines_arr = [] | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         cur_block_id = page_id | 
					
						
							|  |  |  |         while True: | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |             block_url = BLOCK_CHILD_URL_TMPL.format(block_id=cur_block_id) | 
					
						
							|  |  |  |             query_dict: Dict[str, Any] = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             res = requests.request( | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |                 "GET", | 
					
						
							|  |  |  |                 block_url, | 
					
						
							|  |  |  |                 headers={ | 
					
						
							|  |  |  |                     "Authorization": "Bearer " + self._notion_access_token, | 
					
						
							|  |  |  |                     "Content-Type": "application/json", | 
					
						
							|  |  |  |                     "Notion-Version": "2022-06-28", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 json=query_dict | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |             ) | 
					
						
							|  |  |  |             data = res.json() | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |             # current block's heading | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |             heading = '' | 
					
						
							|  |  |  |             for result in data["results"]: | 
					
						
							|  |  |  |                 result_type = result["type"] | 
					
						
							|  |  |  |                 result_obj = result[result_type] | 
					
						
							|  |  |  |                 cur_result_text_arr = [] | 
					
						
							|  |  |  |                 if result_type == 'table': | 
					
						
							|  |  |  |                     result_block_id = result["id"] | 
					
						
							|  |  |  |                     text = self._read_table_rows(result_block_id) | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |                     text += "\n\n" | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |                     result_lines_arr.append(text) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     if "rich_text" in result_obj: | 
					
						
							|  |  |  |                         for rich_text in result_obj["rich_text"]: | 
					
						
							|  |  |  |                             # skip if doesn't have text object | 
					
						
							|  |  |  |                             if "text" in rich_text: | 
					
						
							|  |  |  |                                 text = rich_text["text"]["content"] | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |                                 cur_result_text_arr.append(text) | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |                                 if result_type in HEADING_TYPE: | 
					
						
							|  |  |  |                                     heading = text | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |                     result_block_id = result["id"] | 
					
						
							|  |  |  |                     has_children = result["has_children"] | 
					
						
							| 
									
										
										
										
											2023-06-17 19:50:21 +08:00
										 |  |  |                     block_type = result["type"] | 
					
						
							|  |  |  |                     if has_children and block_type != 'child_page': | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |                         children_text = self._read_block( | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |                             result_block_id, num_tabs=1 | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |                         ) | 
					
						
							|  |  |  |                         cur_result_text_arr.append(children_text) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     cur_result_text = "\n".join(cur_result_text_arr) | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |                     cur_result_text += "\n\n" | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |                     if result_type in HEADING_TYPE: | 
					
						
							|  |  |  |                         result_lines_arr.append(cur_result_text) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         result_lines_arr.append(f'{heading}\n{cur_result_text}') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if data["next_cursor"] is None: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 cur_block_id = data["next_cursor"] | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         return result_lines_arr | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |     def _read_block(self, block_id: str, num_tabs: int = 0) -> str: | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |         """Read a block.""" | 
					
						
							|  |  |  |         result_lines_arr = [] | 
					
						
							|  |  |  |         cur_block_id = block_id | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         while True: | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |             block_url = BLOCK_CHILD_URL_TMPL.format(block_id=cur_block_id) | 
					
						
							|  |  |  |             query_dict: Dict[str, Any] = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             res = requests.request( | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |                 "GET", | 
					
						
							|  |  |  |                 block_url, | 
					
						
							|  |  |  |                 headers={ | 
					
						
							|  |  |  |                     "Authorization": "Bearer " + self._notion_access_token, | 
					
						
							|  |  |  |                     "Content-Type": "application/json", | 
					
						
							|  |  |  |                     "Notion-Version": "2022-06-28", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 json=query_dict | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |             ) | 
					
						
							|  |  |  |             data = res.json() | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |             if 'results' not in data or data["results"] is None: | 
					
						
							|  |  |  |                 break | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |             heading = '' | 
					
						
							|  |  |  |             for result in data["results"]: | 
					
						
							|  |  |  |                 result_type = result["type"] | 
					
						
							|  |  |  |                 result_obj = result[result_type] | 
					
						
							|  |  |  |                 cur_result_text_arr = [] | 
					
						
							|  |  |  |                 if result_type == 'table': | 
					
						
							|  |  |  |                     result_block_id = result["id"] | 
					
						
							|  |  |  |                     text = self._read_table_rows(result_block_id) | 
					
						
							|  |  |  |                     result_lines_arr.append(text) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     if "rich_text" in result_obj: | 
					
						
							|  |  |  |                         for rich_text in result_obj["rich_text"]: | 
					
						
							|  |  |  |                             # skip if doesn't have text object | 
					
						
							|  |  |  |                             if "text" in rich_text: | 
					
						
							|  |  |  |                                 text = rich_text["text"]["content"] | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |                                 prefix = "\t" * num_tabs | 
					
						
							|  |  |  |                                 cur_result_text_arr.append(prefix + text) | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |                                 if result_type in HEADING_TYPE: | 
					
						
							|  |  |  |                                     heading = text | 
					
						
							|  |  |  |                     result_block_id = result["id"] | 
					
						
							|  |  |  |                     has_children = result["has_children"] | 
					
						
							| 
									
										
										
										
											2023-06-17 19:50:21 +08:00
										 |  |  |                     block_type = result["type"] | 
					
						
							|  |  |  |                     if has_children and block_type != 'child_page': | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |                         children_text = self._read_block( | 
					
						
							|  |  |  |                             result_block_id, num_tabs=num_tabs + 1 | 
					
						
							|  |  |  |                         ) | 
					
						
							|  |  |  |                         cur_result_text_arr.append(children_text) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     cur_result_text = "\n".join(cur_result_text_arr) | 
					
						
							|  |  |  |                     if result_type in HEADING_TYPE: | 
					
						
							|  |  |  |                         result_lines_arr.append(cur_result_text) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         result_lines_arr.append(f'{heading}\n{cur_result_text}') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if data["next_cursor"] is None: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 cur_block_id = data["next_cursor"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         result_lines = "\n".join(result_lines_arr) | 
					
						
							|  |  |  |         return result_lines | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |     def _read_table_rows(self, block_id: str) -> str: | 
					
						
							|  |  |  |         """Read table rows.""" | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |         done = False | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         result_lines_arr = [] | 
					
						
							|  |  |  |         cur_block_id = block_id | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |         while not done: | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |             block_url = BLOCK_CHILD_URL_TMPL.format(block_id=cur_block_id) | 
					
						
							|  |  |  |             query_dict: Dict[str, Any] = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             res = requests.request( | 
					
						
							|  |  |  |                 "GET", | 
					
						
							|  |  |  |                 block_url, | 
					
						
							|  |  |  |                 headers={ | 
					
						
							|  |  |  |                     "Authorization": "Bearer " + self._notion_access_token, | 
					
						
							|  |  |  |                     "Content-Type": "application/json", | 
					
						
							|  |  |  |                     "Notion-Version": "2022-06-28", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 json=query_dict | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |             data = res.json() | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |             # get table headers text | 
					
						
							|  |  |  |             table_header_cell_texts = [] | 
					
						
							|  |  |  |             tabel_header_cells = data["results"][0]['table_row']['cells'] | 
					
						
							|  |  |  |             for tabel_header_cell in tabel_header_cells: | 
					
						
							|  |  |  |                 if tabel_header_cell: | 
					
						
							|  |  |  |                     for table_header_cell_text in tabel_header_cell: | 
					
						
							|  |  |  |                         text = table_header_cell_text["text"]["content"] | 
					
						
							|  |  |  |                         table_header_cell_texts.append(text) | 
					
						
							|  |  |  |             # get table columns text and format | 
					
						
							|  |  |  |             results = data["results"] | 
					
						
							|  |  |  |             for i in range(len(results) - 1): | 
					
						
							|  |  |  |                 column_texts = [] | 
					
						
							|  |  |  |                 tabel_column_cells = data["results"][i + 1]['table_row']['cells'] | 
					
						
							|  |  |  |                 for j in range(len(tabel_column_cells)): | 
					
						
							|  |  |  |                     if tabel_column_cells[j]: | 
					
						
							|  |  |  |                         for table_column_cell_text in tabel_column_cells[j]: | 
					
						
							|  |  |  |                             column_text = table_column_cell_text["text"]["content"] | 
					
						
							|  |  |  |                             column_texts.append(f'{table_header_cell_texts[j]}:{column_text}') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 cur_result_text = "\n".join(column_texts) | 
					
						
							|  |  |  |                 result_lines_arr.append(cur_result_text) | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if data["next_cursor"] is None: | 
					
						
							|  |  |  |                 done = True | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |                 cur_block_id = data["next_cursor"] | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         result_lines = "\n".join(result_lines_arr) | 
					
						
							|  |  |  |         return result_lines | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |     def update_last_edited_time(self, document_model: DocumentModel): | 
					
						
							|  |  |  |         if not document_model: | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         last_edited_time = self.get_notion_last_edited_time() | 
					
						
							|  |  |  |         data_source_info = document_model.data_source_info_dict | 
					
						
							|  |  |  |         data_source_info['last_edited_time'] = last_edited_time | 
					
						
							|  |  |  |         update_params = { | 
					
						
							|  |  |  |             DocumentModel.data_source_info: json.dumps(data_source_info) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         DocumentModel.query.filter_by(id=document_model.id).update(update_params) | 
					
						
							|  |  |  |         db.session.commit() | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |     def get_notion_last_edited_time(self) -> str: | 
					
						
							|  |  |  |         obj_id = self._notion_obj_id | 
					
						
							|  |  |  |         page_type = self._notion_page_type | 
					
						
							|  |  |  |         if page_type == 'database': | 
					
						
							|  |  |  |             retrieve_page_url = RETRIEVE_DATABASE_URL_TMPL.format(database_id=obj_id) | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |             retrieve_page_url = RETRIEVE_PAGE_URL_TMPL.format(page_id=obj_id) | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         query_dict: Dict[str, Any] = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         res = requests.request( | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |             "GET", | 
					
						
							|  |  |  |             retrieve_page_url, | 
					
						
							|  |  |  |             headers={ | 
					
						
							|  |  |  |                 "Authorization": "Bearer " + self._notion_access_token, | 
					
						
							|  |  |  |                 "Content-Type": "application/json", | 
					
						
							|  |  |  |                 "Notion-Version": "2022-06-28", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             json=query_dict | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         data = res.json() | 
					
						
							|  |  |  |         return data["last_edited_time"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def _get_access_token(cls, tenant_id: str, notion_workspace_id: str) -> str: | 
					
						
							|  |  |  |         data_source_binding = DataSourceBinding.query.filter( | 
					
						
							|  |  |  |             db.and_( | 
					
						
							|  |  |  |                 DataSourceBinding.tenant_id == tenant_id, | 
					
						
							|  |  |  |                 DataSourceBinding.provider == 'notion', | 
					
						
							|  |  |  |                 DataSourceBinding.disabled == False, | 
					
						
							|  |  |  |                 DataSourceBinding.source_info['workspace_id'] == f'"{notion_workspace_id}"' | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ).first() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not data_source_binding: | 
					
						
							|  |  |  |             raise Exception(f'No notion data source binding found for tenant {tenant_id} ' | 
					
						
							|  |  |  |                             f'and notion workspace {notion_workspace_id}') | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 16:49:14 +08:00
										 |  |  |         return data_source_binding.access_token |