import requests import dataclasses from typing import Any import functools from collections.abc import Iterator PREFIX = 'PAR-' # TODO: Make configurable # Types @dataclasses.dataclass(frozen=True) class SeqId: raw_id: int @dataclasses.dataclass(frozen=True) class CardId: raw_id: str @dataclasses.dataclass(frozen=True) class Card: card_id: CardId seq_id: SeqId seq_id_with_prefix: str detailed_description: str @staticmethod def from_json(json: dict[str, Any]) -> 'Card': print(json) return Card( card_id = CardId(json['cardId']), seq_id = SeqId(json['cardSequentialId']), seq_id_with_prefix = PREFIX + json['cardSequentialId'], detailed_description = json['detailedDescription'], ) # Endpoints URL_API_ROOT = 'https://favro.com/api/v1' URL_GET_ALL_CARDS = URL_API_ROOT+'/cards' URL_UPDATE_CARD = URL_API_ROOT+'/cards/{card_id}' class FavroClient: def __init__(self, *, favro_org_id: str, favro_username: str, favro_password: str, session: requests.Session | None = None): # Setup session self.session = session or requests.Session() self.session.auth = (favro_username, favro_username) self.session.headers.update({ 'organizationId': favro_org_id, 'content-type': 'application/json', }) def get_todo_list_cards(self) -> Iterator[Card]: yield from self.get_cards(todo_list=True) def get_cards(self, *, seqid: SeqId | None = None, todo_list=True) -> Iterator[Card]: # Determine params for get_cards params = {} if seqid: params['cardSequentialId']= seqid.raw_id if todo_list: params['todoList'] = True # Run query response = self.session.get(URL_GET_ALL_CARDS, params = params) response.raise_for_status() json = response.json() # TODO: Pageination for entity_json in json['entities']: yield Card.from_json(entity_json) del entity_json def get_card(self, seqid: SeqId) -> Card: return next(self.get_cards(seqid=seqid)) @functools.cache def get_card_id(self, seqid: SeqId) -> CardId: json = self.get_card_json(seqid) return CardId(json['cardId']) def update_card_description(self, card_id: CardId, description: str) -> Card: """Returns updated Card.""" json_body = { 'detailedDescription': description, 'descriptionFormat': 'markdown', } response = self.session.put(URL_UPDATE_CARD.format(card_id=card_id.raw_id), json=json_body) response.raise_for_status() return Card.from_json(response.json())