|
9 | 9 | from requests.adapters import HTTPAdapter
|
10 | 10 | from requests.packages.urllib3.util.retry import Retry
|
11 | 11 | from getpass import getpass
|
| 12 | +from time import sleep |
12 | 13 |
|
13 | 14 | from .block import Block, BLOCK_TYPES
|
14 | 15 | from .collection import (
|
@@ -178,6 +179,29 @@ def get_block(self, url_or_id, force_refresh=False):
|
178 | 179 | block_class = BLOCK_TYPES.get(block.get("type", ""), Block)
|
179 | 180 | return block_class(self, block_id)
|
180 | 181 |
|
| 182 | + def duplicate_block(self, source_block_id, target_block_id, wait_interval=1, wait_tries=10): |
| 183 | + """ |
| 184 | + Duplicate a block |
| 185 | + """ |
| 186 | + |
| 187 | + data = { |
| 188 | + "task": { |
| 189 | + "eventName": "duplicateBlock", |
| 190 | + "request": { |
| 191 | + "sourceBlockId": source_block_id, |
| 192 | + "targetBlockId": target_block_id, |
| 193 | + "appendContentOnly": True, |
| 194 | + }, |
| 195 | + } |
| 196 | + } |
| 197 | + response = self.post("enqueueTask", data).json() |
| 198 | + task_id = response.get("taskId") |
| 199 | + |
| 200 | + if task_id: |
| 201 | + self.wait_for_task(task_id, interval=wait_interval, tries=wait_tries) |
| 202 | + |
| 203 | + return True |
| 204 | + |
181 | 205 | def get_collection(self, collection_id, force_refresh=False):
|
182 | 206 | """
|
183 | 207 | Retrieve an instance of Collection that maps to the collection identified by the ID passed in.
|
@@ -403,6 +427,42 @@ def create_record(self, table, parent, **kwargs):
|
403 | 427 |
|
404 | 428 | return record_id
|
405 | 429 |
|
| 430 | + def get_task_status(self, task_id): |
| 431 | + """ |
| 432 | + Get a status of a single task |
| 433 | + """ |
| 434 | + data = self.post("getTasks", dict(taskIds=[task_id])).json() |
| 435 | + |
| 436 | + results = data.get("results") |
| 437 | + if results is None: |
| 438 | + return None |
| 439 | + |
| 440 | + if not results: |
| 441 | + # Notion does not know about such a task |
| 442 | + print("Invalid task ID.") |
| 443 | + return None |
| 444 | + |
| 445 | + try: |
| 446 | + task = results.pop() |
| 447 | + return task.get("state", None) |
| 448 | + except IndexError: |
| 449 | + logger.error("There is no task {}".format(results)) |
| 450 | + return None |
| 451 | + |
| 452 | + def wait_for_task(self, task_id, interval=1, tries=10): |
| 453 | + """ |
| 454 | + Wait for a task by looping 'tries' times ever 'interval' seconds. |
| 455 | + The 'interval' parameter can be used to specify milliseconds using double (e.g 0.75). |
| 456 | + """ |
| 457 | + for i in range(tries): |
| 458 | + state = self.get_task_status(task_id) |
| 459 | + if state in ["not_started", "in_progress"]: |
| 460 | + sleep(interval) |
| 461 | + elif state == "success": |
| 462 | + return state |
| 463 | + |
| 464 | + logger.debug("Task takes more time than expected. Specify 'interval' or 'tries' to wait more.") |
| 465 | + |
406 | 466 |
|
407 | 467 | class Transaction(object):
|
408 | 468 |
|
|
0 commit comments