-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add cmd get_board_state for focalboard state
- Loading branch information
Showing
6 changed files
with
249 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import datetime | ||
import logging | ||
from typing import Callable, List | ||
|
||
from ..app_context import AppContext | ||
from ..consts import TrelloCardColor | ||
from ..strings import load | ||
from ..tg.sender import pretty_send | ||
from ..trello.trello_objects import TrelloCard | ||
from ..utils import card_checks_focalboard | ||
from .base_job import BaseJob | ||
from .utils import get_cards_by_curator, retrieve_usernames | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class BoardStateJob(BaseJob): | ||
@staticmethod | ||
def _execute( | ||
app_context: AppContext, send: Callable[[str], None], called_from_handler=False | ||
): | ||
paragraphs = [ | ||
load("trello_board_state_job__intro") | ||
] # list of paragraph strings | ||
curator_cards = get_cards_by_curator(app_context, focalboard=True) | ||
for curator, curator_cards in curator_cards.items(): | ||
curator_name, _ = curator | ||
card_paragraphs = [] | ||
curator_cards.sort(key=lambda c: c.due if c.due else datetime.datetime.min) | ||
for card in curator_cards: | ||
card_paragraph = BoardStateJob._format_card( | ||
card, | ||
card_checks_focalboard.make_card_failure_reasons(card, app_context), | ||
app_context, | ||
) | ||
if card_paragraph: | ||
card_paragraphs.append(card_paragraph) | ||
if card_paragraphs: | ||
paragraphs.append(f"⭐️ <b>Куратор</b>: {curator_name}") | ||
paragraphs += card_paragraphs | ||
pretty_send(paragraphs, send) | ||
|
||
@staticmethod | ||
def _format_card( | ||
card: TrelloCard, failure_reasons: List[str], app_context: AppContext | ||
) -> str: | ||
if not failure_reasons: | ||
return None | ||
|
||
failure_reasons_formatted = ", ".join(failure_reasons) | ||
labels = ( | ||
load( | ||
"trello_board_state_job__card_labels", | ||
names=", ".join( | ||
# We filter BLACK cards as this is an auxiliary label | ||
label.name | ||
for label in card.labels | ||
if label.color != TrelloCardColor.BLACK | ||
), | ||
) | ||
if card.labels | ||
else "" | ||
) | ||
|
||
# Avoiding message overflow, strip explanations in () | ||
list_name = card.lst.name + "(" | ||
list_name = list_name[: list_name.find("(")].strip() | ||
|
||
members = ( | ||
load( | ||
"trello_board_state_job__card_members", | ||
members=", ".join( | ||
retrieve_usernames(card.members, app_context.db_client) | ||
), | ||
curators="", | ||
) | ||
if card.members | ||
else "" | ||
) | ||
|
||
return load( | ||
"trello_board_state_job__card_2", | ||
failure_reasons=failure_reasons_formatted, | ||
url=card.url, | ||
name=card.name, | ||
labels=labels, | ||
list_name=list_name, | ||
members=members, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import datetime | ||
from typing import Tuple | ||
|
||
from ..app_context import AppContext | ||
from ..consts import TrelloCardColor, TrelloListAlias | ||
from ..strings import load | ||
from ..trello.trello_objects import TrelloCard | ||
|
||
|
||
def make_card_failure_reasons(card: TrelloCard, app_context: AppContext): | ||
""" | ||
Returns card description with failure reasons, if any. | ||
If card does not match any of FILTER_TO_FAILURE_REASON, returns None. | ||
""" | ||
failure_reasons = [] | ||
for filter_func, reason_alias in FILTER_TO_FAILURE_REASON.items(): | ||
is_failed, kwargs = filter_func(card, app_context) | ||
if is_failed: | ||
reason = load(reason_alias, **kwargs) | ||
if reason and len(failure_reasons) > 0: | ||
reason = reason[0].lower() + reason[1:] | ||
failure_reasons.append(reason) | ||
return failure_reasons | ||
|
||
|
||
def is_deadline_missed(card: TrelloCard, app_context: AppContext) -> Tuple[bool, dict]: | ||
list_ids = app_context.focalboard_client.get_list_id_from_aliases( | ||
[TrelloListAlias.IN_PROGRESS] | ||
) | ||
is_missed = ( | ||
card.lst.id in list_ids | ||
and card.due is not None | ||
and card.due.date() < datetime.datetime.now().date() | ||
) | ||
return is_missed, {"date": card.due.strftime("%d.%m")} if is_missed else {} | ||
|
||
|
||
def is_due_date_missing(card: TrelloCard, app_context: AppContext) -> Tuple[bool, dict]: | ||
if card.due: | ||
return False, {} | ||
list_ids = app_context.focalboard_client.get_list_id_from_aliases( | ||
[TrelloListAlias.IN_PROGRESS] | ||
) | ||
return card.lst.id in list_ids, {} | ||
|
||
|
||
def is_author_missing(card: TrelloCard, app_context: AppContext) -> Tuple[bool, dict]: | ||
if card.members: | ||
return False, {} | ||
|
||
list_aliases = ( | ||
TrelloListAlias.IN_PROGRESS, | ||
TrelloListAlias.TO_EDITOR, | ||
TrelloListAlias.EDITED_NEXT_WEEK, | ||
TrelloListAlias.TO_SEO_EDITOR, | ||
TrelloListAlias.EDITED_SOMETIMES, | ||
TrelloListAlias.TO_CHIEF_EDITOR, | ||
TrelloListAlias.PROOFREADING, | ||
TrelloListAlias.DONE, | ||
) | ||
list_ids = app_context.focalboard_client.get_list_id_from_aliases(list_aliases) | ||
return card.lst.id in list_ids, {} | ||
|
||
|
||
def is_tag_missing(card: TrelloCard, app_context: AppContext) -> Tuple[bool, dict]: | ||
if card.labels: | ||
return False, {} | ||
|
||
list_aliases = ( | ||
TrelloListAlias.IN_PROGRESS, | ||
TrelloListAlias.TO_EDITOR, | ||
TrelloListAlias.EDITED_NEXT_WEEK, | ||
TrelloListAlias.TO_SEO_EDITOR, | ||
TrelloListAlias.EDITED_SOMETIMES, | ||
TrelloListAlias.TO_CHIEF_EDITOR, | ||
TrelloListAlias.PROOFREADING, | ||
TrelloListAlias.DONE, | ||
) | ||
list_ids = app_context.focalboard_client.get_list_id_from_aliases(list_aliases) | ||
return card.lst.id in list_ids, {} | ||
|
||
|
||
def is_doc_missing(card: TrelloCard, app_context: AppContext) -> Tuple[bool, dict]: | ||
list_aliases = ( | ||
TrelloListAlias.TO_EDITOR, | ||
TrelloListAlias.EDITED_NEXT_WEEK, | ||
TrelloListAlias.TO_SEO_EDITOR, | ||
TrelloListAlias.EDITED_SOMETIMES, | ||
TrelloListAlias.TO_CHIEF_EDITOR, | ||
TrelloListAlias.PROOFREADING, | ||
TrelloListAlias.DONE, | ||
) | ||
list_ids = app_context.focalboard_client.get_list_id_from_aliases(list_aliases) | ||
if card.lst.id not in list_ids: | ||
return False, {} | ||
|
||
doc_url = app_context.focalboard_client.get_custom_fields(card.id).google_doc | ||
return not doc_url, {} | ||
|
||
|
||
def has_no_doc_access(card: TrelloCard, app_context: AppContext) -> Tuple[bool, dict]: | ||
list_aliases = ( | ||
TrelloListAlias.TO_EDITOR, | ||
TrelloListAlias.EDITED_NEXT_WEEK, | ||
TrelloListAlias.TO_SEO_EDITOR, | ||
TrelloListAlias.EDITED_SOMETIMES, | ||
TrelloListAlias.TO_CHIEF_EDITOR, | ||
TrelloListAlias.PROOFREADING, | ||
TrelloListAlias.DONE, | ||
) | ||
list_ids = app_context.focalboard_client.get_list_id_from_aliases(list_aliases) | ||
if card.lst.id not in list_ids: | ||
return False, {} | ||
|
||
doc_url = app_context.focalboard_client.get_custom_fields(card.id).google_doc | ||
if not doc_url: | ||
# should be handled by is_doc_missing | ||
return False, {} | ||
|
||
is_open_for_edit = app_context.drive_client.is_open_for_edit(doc_url) | ||
return not is_open_for_edit, {} | ||
|
||
|
||
FILTER_TO_FAILURE_REASON = { | ||
is_author_missing: "trello_board_state_job__title_author_missing", | ||
is_due_date_missing: "trello_board_state_job__title_due_date_missing", | ||
is_deadline_missed: "trello_board_state_job__title_due_date_expired", | ||
is_tag_missing: "trello_board_state_job__title_tag_missing", | ||
is_doc_missing: "trello_board_state_job__title_no_doc", | ||
has_no_doc_access: "trello_board_state_job__title_no_doc_access", | ||
} |