1
0

[client]: Pagination and additional card info

This commit is contained in:
Jon Michael Aanes 2024-10-01 13:15:49 +02:00
parent 7cd847ce64
commit c98946cacb
5 changed files with 78 additions and 24 deletions

View File

@ -102,32 +102,47 @@ class FavroClient:
seq_id: SeqId | None = None, seq_id: SeqId | None = None,
todo_list=False, todo_list=False,
) -> Iterator[Card]: ) -> Iterator[Card]:
# Determine params for get_cards page = 0
request = self._get_cards_request(seq_id, todo_list) request_id = None
num_pages = 1
# Run query while page < num_pages:
logger.warning('Sending request: %s', request.url) # Determine params for get_cards
response = self.session.send(request) request = self._get_cards_request(seq_id, todo_list, page=page, request_id=request_id)
response.raise_for_status()
json = response.json()
# TODO: Add support for pageination # Run query
for entity_json in json['entities']: logger.warning('Sending request: %s', request.url)
card = Card.from_json(entity_json) response = self.session.send(request)
self.cache.add_card(card) response.raise_for_status()
yield card json = response.json()
del entity_json
for entity_json in json['entities']:
card = Card.from_json(entity_json)
self.cache.add_card(card)
yield card
del entity_json
# Pagination bookkeeping
page = json['page'] + 1
request_id = json['requestId']
num_pages = json['pages']
def _get_cards_request( def _get_cards_request(
self, self,
seq_id: SeqId | None = None, seq_id: SeqId | None = None,
todo_list=False, todo_list: bool=False,
request_id: None | str = None,
page: None | int = None,
) -> requests.PreparedRequest: ) -> requests.PreparedRequest:
params = {'descriptionFormat': 'markdown'} params = {'descriptionFormat': 'markdown'}
if seq_id is not None: if seq_id is not None:
params['cardSequentialId'] = str(seq_id.raw_id) params['cardSequentialId'] = str(seq_id.raw_id)
if todo_list is True: if todo_list is True:
params['todoList'] = 'true' params['todoList'] = 'true'
if request_id:
params['requestId'] = request_id
if page:
params['page'] = page
request = requests.Request('GET', URL_GET_ALL_CARDS, params=params) request = requests.Request('GET', URL_GET_ALL_CARDS, params=params)
return self.session.prepare_request(request) return self.session.prepare_request(request)
@ -192,6 +207,7 @@ class FavroClient:
'name': card_contents.name, 'name': card_contents.name,
'detailedDescription': card_contents.description, 'detailedDescription': card_contents.description,
'descriptionFormat': 'markdown', 'descriptionFormat': 'markdown',
'archived': card_contents.archived,
} }
url = URL_UPDATE_CARD.format(card_id=card_id.raw_id) url = URL_UPDATE_CARD.format(card_id=card_id.raw_id)

View File

@ -94,13 +94,13 @@ class TagInfo:
@dataclasses.dataclass(frozen=True) @dataclasses.dataclass(frozen=True)
class CustomField: class CustomField:
custom_field_id: CustomFieldId custom_field_id: CustomFieldId
value: list[str] # TODO value: list[str] | str
@staticmethod @staticmethod
def from_json(json: dict[str, Any]) -> 'CustomField': def from_json(json: dict[str, Any]) -> 'CustomField':
return CustomField( return CustomField(
CustomFieldId(json['customFieldId']), CustomFieldId(json['customFieldId']),
json['value'], # TODO json.get('value'),
) )
@ -137,14 +137,14 @@ class Card:
todo_list_completed: bool | None todo_list_completed: bool | None
creator_user_id: UserId creator_user_id: UserId
creation_date: datetime.datetime creation_date: datetime.datetime
start_date: datetime.date | None
due_date: datetime.date | None
attachments: list[dict] attachments: list[dict]
detailed_description: str | None detailed_description: str | None
archived: bool
@staticmethod @staticmethod
def from_json(json: dict[str, Any]) -> 'Card': def from_json(json: dict[str, Any]) -> 'Card':
todo_list_user_id = (
UserId(json['todoListUserId']) if 'todoListUserId' in json else None
)
return Card( return Card(
card_id=CardId(json['cardId']), card_id=CardId(json['cardId']),
seq_id=SeqId(json['sequentialId']), seq_id=SeqId(json['sequentialId']),
@ -153,17 +153,25 @@ class Card:
is_archived=json['archived'], is_archived=json['archived'],
organization_id=OrganizationId(json['organizationId']), organization_id=OrganizationId(json['organizationId']),
name=json['name'], name=json['name'],
todo_list_user_id=todo_list_user_id, todo_list_user_id=map_opt(UserId, json.get('todoListUserId')),
todo_list_completed=json.get('todoListCompleted'), todo_list_completed=json.get('todoListCompleted'),
dependencies=[ dependencies=[
CardDependency.from_json(dep) for dep in json['dependencies'] CardDependency.from_json(dep) for dep in json['dependencies']
], ],
tags=[TagId(tag) for tag in json['tags']], tags=[TagId(tag) for tag in json['tags']],
creator_user_id=UserId(json['createdByUserId']), creator_user_id=UserId(json['createdByUserId']),
creation_date=datetime.datetime.fromisoformat(json['createdAt']), creation_date=map_opt(datetime.datetime.fromisoformat,json.get('createdAt')),
start_date=map_opt(datetime.datetime.fromisoformat,json.get('startDate')),
due_date=map_opt(datetime.datetime.fromisoformat,json.get('dueDate')),
assignments=[CardAssignment.from_json(ass) for ass in json['assignments']], assignments=[CardAssignment.from_json(ass) for ass in json['assignments']],
custom_fields=[ custom_fields=[
CustomField.from_json(field) for field in json['customFields'] CustomField.from_json(field) for field in json['customFields']
], ],
archived=json['archived'],
attachments=json['attachments'], # TODO attachments=json['attachments'], # TODO
) )
def map_opt(mapper, value):
if value is not None:
return mapper(value)
return None

View File

@ -201,6 +201,8 @@ class FavroFuse(fuse.Fuse):
seq_id=card.seq_id.raw_id, seq_id=card.seq_id.raw_id,
), ),
todo_list_completed = card.todo_list_completed, todo_list_completed = card.todo_list_completed,
start_date= card.start_date,
due_date= card.due_date,
) )
return self.formatter.format_card_contents(card_contents) return self.formatter.format_card_contents(card_contents)

View File

@ -1,5 +1,6 @@
import dataclasses import dataclasses
import re import re
import datetime
import frontmatter import frontmatter
import marko import marko
@ -14,6 +15,9 @@ FM_KEY_ASSIGNMENTS = 'assignments'
FM_KEY_DEPENDENCIES = 'dependencies' FM_KEY_DEPENDENCIES = 'dependencies'
FM_KEY_URL = 'url' FM_KEY_URL = 'url'
FM_KEY_ALIASES = 'aliases' FM_KEY_ALIASES = 'aliases'
FM_KEY_ARCHIVED = 'archived'
FM_KEY_DUE_DATE = 'due'
FM_KEY_START_DATE = 'start-date'
################################################################################ ################################################################################
@ -27,6 +31,9 @@ class CardContents:
card_dependencies: list[str] card_dependencies: list[str]
url: str url: str
todo_list_completed: bool | None todo_list_completed: bool | None
archived: bool
start_date: datetime.date | None
due_date: datetime.date | None
def format_obsidian_link(text: str) -> str: def format_obsidian_link(text: str) -> str:
@ -87,6 +94,12 @@ class CardFileFormatter:
] ]
if card.todo_list_completed: if card.todo_list_completed:
frontmatter_data[FM_KEY_TODO_LIST_COMPLETED] = card.todo_list_completed frontmatter_data[FM_KEY_TODO_LIST_COMPLETED] = card.todo_list_completed
if card.archived:
frontmatter_data[FM_KEY_ARCHIVED] = card.archived
if card.due_date:
frontmatter_data[FM_KEY_DUE_DATE] = card.due_date
if card.start_date:
frontmatter_data[FM_KEY_DUE_DATE] = card.start_date
# Card name # Card name
ls = [] ls = []
@ -134,6 +147,10 @@ class CardFileFormatter:
url: list[str] = fm.metadata.get(FM_KEY_URL) url: list[str] = fm.metadata.get(FM_KEY_URL)
todo_list_completed: bool | None = fm.metadata.get(FM_KEY_TODO_LIST_COMPLETED) todo_list_completed: bool | None = fm.metadata.get(FM_KEY_TODO_LIST_COMPLETED)
archived: bool = fm.metadata.get(FM_KEY_ARCHIVED)
start_date: datetime.date = fm.metadata.get(FM_KEY_START_DATE)
due_date: datetime.date = fm.metadata.get(FM_KEY_DUE_DATE)
description = self.renderer.render_children(document).strip() description = self.renderer.render_children(document).strip()
return CardContents( return CardContents(
@ -145,4 +162,7 @@ class CardFileFormatter:
card_dependencies=card_dependencies, card_dependencies=card_dependencies,
url=url, url=url,
todo_list_completed=todo_list_completed, todo_list_completed=todo_list_completed,
archived=archived,
start_date=start_date,
due_date=due_date,
) )

View File

@ -20,15 +20,19 @@ def test_create_client():
def test_get_card(): def test_get_card():
client = create_client() client = create_client()
card = client.get_card(SeqId(11368)) card = client.get_card(SeqId(11368))
print(card)
assert card is not None assert_valid_card(card)
assert card.name is not None
assert card.detailed_description is not None assert card.detailed_description is not None
assert len(card.dependencies) == 1 assert len(card.dependencies) == 1
assert len(card.attachments) == 0 assert len(card.attachments) == 0
assert len(card.custom_fields) == 2 assert len(card.custom_fields) == 2
@needs_secrets
def test_get_cards():
client = create_client()
for card in client.get_cards(todo_list=True):
assert_valid_card(card)
def create_client(): def create_client():
return FavroClient( return FavroClient(
@ -37,3 +41,7 @@ def create_client():
favro_password=secrets.favro_password(), favro_password=secrets.favro_password(),
read_only=True, read_only=True,
) )
def assert_valid_card(card):
assert card is not None
assert card.name is not None