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,8 +102,13 @@ class FavroClient:
seq_id: SeqId | None = None,
todo_list=False,
) -> Iterator[Card]:
page = 0
request_id = None
num_pages = 1
while page < num_pages:
# Determine params for get_cards
request = self._get_cards_request(seq_id, todo_list)
request = self._get_cards_request(seq_id, todo_list, page=page, request_id=request_id)
# Run query
logger.warning('Sending request: %s', request.url)
@ -111,23 +116,33 @@ class FavroClient:
response.raise_for_status()
json = response.json()
# TODO: Add support for pageination
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(
self,
seq_id: SeqId | None = None,
todo_list=False,
todo_list: bool=False,
request_id: None | str = None,
page: None | int = None,
) -> requests.PreparedRequest:
params = {'descriptionFormat': 'markdown'}
if seq_id is not None:
params['cardSequentialId'] = str(seq_id.raw_id)
if todo_list is 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)
return self.session.prepare_request(request)
@ -192,6 +207,7 @@ class FavroClient:
'name': card_contents.name,
'detailedDescription': card_contents.description,
'descriptionFormat': 'markdown',
'archived': card_contents.archived,
}
url = URL_UPDATE_CARD.format(card_id=card_id.raw_id)

View File

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

View File

@ -1,5 +1,6 @@
import dataclasses
import re
import datetime
import frontmatter
import marko
@ -14,6 +15,9 @@ FM_KEY_ASSIGNMENTS = 'assignments'
FM_KEY_DEPENDENCIES = 'dependencies'
FM_KEY_URL = 'url'
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]
url: str
todo_list_completed: bool | None
archived: bool
start_date: datetime.date | None
due_date: datetime.date | None
def format_obsidian_link(text: str) -> str:
@ -87,6 +94,12 @@ class CardFileFormatter:
]
if 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
ls = []
@ -134,6 +147,10 @@ class CardFileFormatter:
url: list[str] = fm.metadata.get(FM_KEY_URL)
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()
return CardContents(
@ -145,4 +162,7 @@ class CardFileFormatter:
card_dependencies=card_dependencies,
url=url,
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():
client = create_client()
card = client.get_card(SeqId(11368))
print(card)
assert card is not None
assert card.name is not None
assert_valid_card(card)
assert card.detailed_description is not None
assert len(card.dependencies) == 1
assert len(card.attachments) == 0
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():
return FavroClient(
@ -37,3 +41,7 @@ def create_client():
favro_password=secrets.favro_password(),
read_only=True,
)
def assert_valid_card(card):
assert card is not None
assert card.name is not None