Added real-only support for tags and assignments
This commit is contained in:
parent
d4cfe4da22
commit
9fb19e39a5
|
@ -6,7 +6,7 @@ import requests_cache
|
|||
|
||||
from .favro_client import FavroClient, OrganizationId
|
||||
from .favro_fuse import start_favro_fuse
|
||||
import secrets
|
||||
from . import secrets
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
@ -4,7 +4,8 @@ from logging import getLogger
|
|||
import requests
|
||||
import dataclasses
|
||||
|
||||
from .favro_data_model import Card, CardId, OrganizationId, SeqId
|
||||
from .favro_data_model import (Card, CardId, OrganizationId, SeqId, UserInfo,
|
||||
UserId, UserInfo, TagId, TagInfo)
|
||||
from .favro_markdown import CardContents
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
@ -13,6 +14,8 @@ logger = getLogger(__name__)
|
|||
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}'
|
||||
URL_GET_USER = URL_API_ROOT + '/users/{user_id}'
|
||||
URL_GET_TAG = URL_API_ROOT + '/tags/{tag_id}'
|
||||
|
||||
class CardCache:
|
||||
|
||||
|
@ -27,16 +30,19 @@ class CardCache:
|
|||
for card in reversed(self.cards):
|
||||
if card.card_id == card_id:
|
||||
return card
|
||||
return None
|
||||
|
||||
def get_card_by_seq_id(self, seq_id: SeqId) -> Card | None:
|
||||
for card in reversed(self.cards):
|
||||
if card.seq_id == seq_id:
|
||||
return card
|
||||
return None
|
||||
|
||||
def remove(self, card_id: CardId) -> Card | None:
|
||||
while card := self.get_card_by_card_id(card_id):
|
||||
self.cards.remove(card)
|
||||
return card
|
||||
return None
|
||||
|
||||
class FavroClient:
|
||||
def __init__(
|
||||
|
@ -85,7 +91,6 @@ class FavroClient:
|
|||
|
||||
# TODO: Add support for pageination
|
||||
for entity_json in json['entities']:
|
||||
print(entity_json)
|
||||
card = Card.from_json(entity_json)
|
||||
self.cache.add_card(card)
|
||||
yield card
|
||||
|
@ -108,6 +113,14 @@ class FavroClient:
|
|||
return card
|
||||
return next(self.get_cards(seq_id=seq_id))
|
||||
|
||||
def get_user(self, user_id: UserId) -> UserInfo:
|
||||
response = self.session.get(URL_GET_USER.format(user_id=user_id.raw_id))
|
||||
return UserInfo.from_json(response.json())
|
||||
|
||||
def get_tag(self, tag_id: TagId) -> TagInfo:
|
||||
response = self.session.get(URL_GET_TAG.format(tag_id=tag_id.raw_id))
|
||||
return TagInfo.from_json(response.json())
|
||||
|
||||
def _invalidate_cache(self, card_id: CardId) -> None:
|
||||
card = self.cache.remove(card_id)
|
||||
if card:
|
||||
|
@ -125,12 +138,12 @@ class FavroClient:
|
|||
"""Returns updated Card."""
|
||||
if self.read_only == 'silent':
|
||||
logger.warning(
|
||||
'FavroClient is silent read only: Discarding card description update of length %d',
|
||||
len(description),
|
||||
'FavroClient is silent read only: Discarding card description update',
|
||||
)
|
||||
return None # TODO
|
||||
elif self.read_only is True:
|
||||
raise Exception('FavroClient is read only')
|
||||
if self.read_only is True:
|
||||
msg = 'FavroClient is read only'
|
||||
raise Exception(msg)
|
||||
|
||||
json_body = {
|
||||
'name': card_contents.name,
|
||||
|
|
|
@ -40,10 +40,42 @@ class CardAssignment:
|
|||
json['completed'],
|
||||
)
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class UserInfo:
|
||||
user_id: UserId
|
||||
name: str
|
||||
email: str
|
||||
organization_role: str
|
||||
|
||||
@staticmethod
|
||||
def from_json(json: dict[str, Any]) -> 'UserInfo':
|
||||
return UserInfo(
|
||||
UserId(json['userId']),
|
||||
json['name'],
|
||||
json['email'],
|
||||
json['organizationRole'],
|
||||
)
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class TagId:
|
||||
raw_id: str
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class TagInfo:
|
||||
tag_id: TagId
|
||||
organization_id: OrganizationId
|
||||
name: str
|
||||
color: str | None
|
||||
|
||||
@staticmethod
|
||||
def from_json(json: dict[str, Any]) -> 'TagInfo':
|
||||
return TagInfo(
|
||||
TagId(json['tagId']),
|
||||
OrganizationId(json['organizationId']),
|
||||
json['name'],
|
||||
json.get('color'),
|
||||
)
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class CardDependency:
|
||||
card_id: CardId
|
||||
|
|
|
@ -73,7 +73,7 @@ class FavroFuse(fuse.Fuse):
|
|||
|
||||
st.st_mode = stat.S_IFREG | 0o666
|
||||
st.st_nlink = 1
|
||||
st.st_size = len(self.formatter.format_card(card))
|
||||
st.st_size = len(self._format_card_file(card))
|
||||
st.st_ctime = int(card.creation_date.timestamp())
|
||||
st.st_mtime = st.st_ctime # TODO
|
||||
else:
|
||||
|
@ -88,7 +88,7 @@ class FavroFuse(fuse.Fuse):
|
|||
for card in self.favro_client.get_todo_list_cards():
|
||||
yield fuse.Direntry(CARD_FILENAME_FORMAT.format(seq_id=card.seq_id.raw_id))
|
||||
|
||||
def open(self, path: str, flags) -> int | None:
|
||||
def open(self, path: str, flags: int) -> int | None:
|
||||
thing = Thing.from_path(path)
|
||||
if not isinstance(thing, CardThing):
|
||||
return -errno.ENOENT
|
||||
|
@ -102,7 +102,7 @@ class FavroFuse(fuse.Fuse):
|
|||
|
||||
card = self.favro_client.get_card(thing.seq_id)
|
||||
|
||||
contents_str = self.formatter.format_card(card)
|
||||
contents_str = self._format_card_file(card)
|
||||
contents = bytes(contents_str, 'utf8')
|
||||
|
||||
slen = len(contents)
|
||||
|
@ -123,7 +123,7 @@ class FavroFuse(fuse.Fuse):
|
|||
card = self.favro_client.get_card(thing.seq_id)
|
||||
|
||||
# Splice contents
|
||||
contents_str = self.formatter.format_card(card)
|
||||
contents_str = self._format_card_file(card)
|
||||
contents = bytes(contents_str, 'utf8')
|
||||
contents = splice(contents, written_buffer, offset)
|
||||
contents_str = contents.decode('utf8')
|
||||
|
@ -144,7 +144,7 @@ class FavroFuse(fuse.Fuse):
|
|||
card = self.favro_client.get_card(thing.seq_id)
|
||||
|
||||
# Splice contents
|
||||
contents_str = self.formatter.format_card(card)
|
||||
contents_str = self._format_card_file(card)
|
||||
contents = bytes(contents_str, 'utf8')
|
||||
old_size = len(contents)
|
||||
contents = contents[0:new_size] + b' ' * (old_size - new_size)
|
||||
|
@ -158,6 +158,16 @@ class FavroFuse(fuse.Fuse):
|
|||
# Return amount written
|
||||
return 0
|
||||
|
||||
def _format_card_file(self, card: Card) -> str:
|
||||
tags = [self.favro_client.get_tag(tag_id).name for tag_id in card.tags]
|
||||
assignments = [self.favro_client.get_user(assignment.user).name for assignment in card.assignments]
|
||||
card_contents = CardContents(
|
||||
card.name,
|
||||
card.detailed_description,
|
||||
tags,
|
||||
assignments,
|
||||
)
|
||||
return self.formatter.format_card_contents(card_contents)
|
||||
|
||||
def splice(original_buffer: bytes, input_buffer: bytes, offset: int) -> bytes:
|
||||
return (
|
||||
|
|
|
@ -19,7 +19,7 @@ class CardContents:
|
|||
assignments: list[str]
|
||||
|
||||
class CardFileFormatter:
|
||||
"""Component for formatting and parsing card files """
|
||||
"""Component for formatting and parsing card files."""
|
||||
|
||||
def __init__(self, obsidian_mode = True):
|
||||
self.obsidian_mode = obsidian_mode
|
||||
|
@ -90,5 +90,3 @@ class CardFileFormatter:
|
|||
assignments = [],
|
||||
)
|
||||
|
||||
def format_card(self, card: Card) -> str:
|
||||
return self.format_card_contents(CardContents(card.name, card.detailed_description))
|
||||
|
|
Loading…
Reference in New Issue
Block a user