| 107 | |
| 108 | |
| 109 | class BookstackDataSource(BaseDataSource): |
| 110 | @staticmethod |
| 111 | def get_config_fields() -> List[ConfigField]: |
| 112 | return [ |
| 113 | ConfigField(label="BookStack instance URL", name="url"), |
| 114 | ConfigField(label="Token ID", name="token_id", input_type=HTMLInputType.PASSWORD), |
| 115 | ConfigField(label="Token Secret", name="token_secret", input_type=HTMLInputType.PASSWORD) |
| 116 | ] |
| 117 | |
| 118 | @classmethod |
| 119 | def get_display_name(cls) -> str: |
| 120 | return "BookStack" |
| 121 | |
| 122 | @staticmethod |
| 123 | def list_books(book_stack: BookStack) -> List[Dict]: |
| 124 | # Usually the book_stack connection fails, so we retry a few times |
| 125 | retries = 3 |
| 126 | for i in range(retries): |
| 127 | try: |
| 128 | return book_stack.get_all_books() |
| 129 | except Exception as e: |
| 130 | logging.error(f"BookStack connection failed: {e}") |
| 131 | if i == retries - 1: |
| 132 | raise e |
| 133 | |
| 134 | @staticmethod |
| 135 | async def validate_config(config: Dict) -> None: |
| 136 | try: |
| 137 | parsed_config = BookStackConfig(**config) |
| 138 | book_stack = BookStack(url=parsed_config.url, token_id=parsed_config.token_id, |
| 139 | token_secret=parsed_config.token_secret) |
| 140 | BookstackDataSource.list_books(book_stack=book_stack) |
| 141 | except Exception as e: |
| 142 | raise InvalidDataSourceConfig from e |
| 143 | |
| 144 | def __init__(self, *args, **kwargs): |
| 145 | super().__init__(*args, **kwargs) |
| 146 | book_stack_config = BookStackConfig(**self._raw_config) |
| 147 | self._book_stack = BookStack(url=book_stack_config.url, token_id=book_stack_config.token_id, |
| 148 | token_secret=book_stack_config.token_secret) |
| 149 | |
| 150 | def _list_books(self) -> List[Dict]: |
| 151 | logger.info("Listing books with BookStack") |
| 152 | return BookstackDataSource.list_books(book_stack=self._book_stack) |
| 153 | |
| 154 | def _feed_new_documents(self) -> None: |
| 155 | logger.info("Feeding new documents with BookStack") |
| 156 | |
| 157 | books = self._list_books() |
| 158 | for book in books: |
| 159 | self.add_task_to_queue(self._feed_book, book=book) |
| 160 | |
| 161 | def _feed_book(self, book: Dict): |
| 162 | logger.info(f"Getting documents from book {book['name']} ({book['id']})") |
| 163 | pages = self._book_stack.get_all_pages_from_book(book) |
| 164 | for page in pages: |
| 165 | self.add_task_to_queue(self._feed_page, raw_page=page) |
| 166 |
nothing calls this directly
no outgoing calls
no test coverage detected