Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/jobs/backfill_telegram_user_ids_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,15 @@ def _execute(
members_with_telegram = [
m
for m in team_members
if m.telegram and m.telegram.strip() and m.telegram != "#N/A"
if m.telegram
and m.telegram.strip()
and m.telegram != "#N/A"
and not m.telegram_id
]

send(f"Found {len(members_with_telegram)} team members with Telegram usernames")
send(
f"Found {len(members_with_telegram)} team members with unresolved Telegram usernames"
)

resolved_count = 0
created_count = 0
Expand Down
42 changes: 10 additions & 32 deletions src/jobs/create_folders_for_illustrators_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from ..app_context import AppContext
from ..consts import (
BoardCardColor,
TrelloCardColor,
TrelloCustomFieldTypeAlias,
BoardListAlias,
Expand Down Expand Up @@ -64,15 +63,9 @@ def _create_folders(
app_context: AppContext,
list_aliases: List[BoardListAlias],
) -> List[Tuple[IllustratorFolderState, str]]:
logger.info("Started counting:")
if app_context.trello_client.deprecated:
list_ids = app_context.focalboard_client.get_list_id_from_aliases(
list_aliases
)
cards = app_context.focalboard_client.get_cards(list_ids)
else:
list_ids = app_context.trello_client.get_list_id_from_aliases(list_aliases)
cards = app_context.trello_client.get_cards(list_ids)
logger.info("Started creating illustrator folders")
list_ids = app_context.planka_client.get_list_id_from_aliases(list_aliases)
cards = app_context.planka_client.get_cards(list_ids)

parse_failure_counter = 0
result = []
Expand All @@ -81,15 +74,11 @@ def _create_folders(
parse_failure_counter += 1
continue

if app_context.trello_client.deprecated:
card_fields = app_context.focalboard_client.get_custom_fields(card.id)
else:
card_fields = app_context.trello_client.get_custom_fields(card.id)

card_fields = app_context.planka_client.get_custom_fields(card.id)
label_names = [
label.name
for label in card.labels
if label.color not in [TrelloCardColor.BLACK, BoardCardColor.BLACK]
if label.color != TrelloCardColor.BLACK
]
is_archive_card = load("common_trello_label__archive") in label_names

Expand All @@ -98,9 +87,7 @@ def _create_folders(

folder_state = IllustratorFolderState.INCORRECT_URL
if card_fields.cover:
# filled cover field
if urlparse(card_fields.cover).scheme:
# existing folder path is correct
cover = load(
"create_folders_for_illustrators_job__cover",
url=card_fields.cover,
Expand All @@ -113,7 +100,6 @@ def _create_folders(
)
folder_state = IllustratorFolderState.INCORRECT_URL
else:
# create folder for cover
card_fields.cover = app_context.drive_client.create_folder_for_card(
card
)
Expand All @@ -125,22 +111,14 @@ def _create_folders(
folder_state = IllustratorFolderState.INCORRECT_URL
logger.error(f"The folder for card {card.url} was not created")
else:
# save path to folder into trello card
logger.info(
f"Trying to put {card_fields.cover} as cover field for {card.url}"
)
if app_context.trello_client.deprecated:
app_context.focalboard_client.set_card_custom_field(
card,
TrelloCustomFieldTypeAlias.COVER,
card_fields.cover,
)
else:
app_context.trello_client.set_card_custom_field(
card.id,
TrelloCustomFieldTypeAlias.COVER,
card_fields.cover,
)
app_context.planka_client.set_card_custom_field(
card,
TrelloCustomFieldTypeAlias.COVER,
card_fields.cover,
)
cover = load(
"create_folders_for_illustrators_job__cover",
url=card_fields.cover,
Expand Down
122 changes: 120 additions & 2 deletions src/planka/planka_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
import requests
from cachetools import TTLCache

from ..consts import TrelloCardColor
from ..consts import TrelloCardColor, TrelloCustomFieldTypeAlias
from ..db import db_client
from ..strings import load
from ..trello import trello_objects as objects
from ..trello.trello_objects import TIME_FORMAT
from ..utils.singleton import Singleton
Expand Down Expand Up @@ -160,6 +161,110 @@ def get_cards(self, list_ids=None, board_id=None):
logger.debug(f"get_cards: {cards}")
return cards

def get_list_id_from_aliases(self, list_aliases) -> list:
lists = self.get_lists()
result = []
for alias in list_aliases:
alias_name = load(alias.value)
matching = [lst for lst in lists if lst.name.startswith(alias_name)]
if matching:
result.append(matching[0].id)
else:
logger.error(
f"List not found for alias {alias}: expected name starting with '{alias_name}'"
)
return result

def get_custom_fields(self, card_id: str) -> objects.CardCustomFields:
data = self._get_board_data(self.board_id)
included = data.get("included", {})

name_to_id = {
cf["name"]: cf["id"]
for cf in included.get("customFields", [])
if "name" in cf and "id" in cf
}
card_items = {
item["customFieldId"]: item.get("content")
for item in included.get("customFieldValues", [])
if item.get("cardId") == card_id and "customFieldId" in item
}

def _get(alias):
return card_items.get(name_to_id.get(load(alias.value)))

card_fields = objects.CardCustomFields(card_id)
card_fields.title = _get(TrelloCustomFieldTypeAlias.TITLE)

author_val = _get(TrelloCustomFieldTypeAlias.AUTHOR)
card_fields.authors = (
[a.strip() for a in author_val.split(",")] if author_val else []
)

editor_val = _get(TrelloCustomFieldTypeAlias.EDITOR)
card_fields.editors = (
[e.strip() for e in editor_val.split(",")] if editor_val else []
)

illustrator_val = _get(TrelloCustomFieldTypeAlias.ILLUSTRATOR)
card_fields.illustrators = (
[i.strip() for i in illustrator_val.split(",")] if illustrator_val else []
)

card_fields.cover = _get(TrelloCustomFieldTypeAlias.COVER)
card_fields.google_doc = _get(TrelloCustomFieldTypeAlias.GOOGLE_DOC)
return card_fields

def set_card_custom_field(self, card, field_alias, value: str):
data = self._get_board_data(self.board_id)
included = data.get("included", {})

field_name = load(field_alias.value)
custom_field = next(
(
cf
for cf in included.get("customFields", [])
if cf.get("name") == field_name
),
None,
)
if not custom_field:
logger.error(
f"Custom field '{field_name}' not found on board {self.board_id}"
)
return

custom_field_id = custom_field["id"]

# customFieldGroupId comes from the field definition; fall back to
# scanning existing values for any card that already has this field.
group_id = custom_field.get("customFieldGroupId")
if not group_id:
existing = next(
(
item
for item in included.get("customFieldValues", [])
if item.get("customFieldId") == custom_field_id
),
None,
)
if existing:
group_id = existing.get("customFieldGroupId")
if not group_id:
logger.error(
f"Cannot determine customFieldGroupId for field '{field_name}' "
f"on board {self.board_id}"
)
return

# Single PATCH — Planka creates or updates in one call.
uri = (
f"cards/{card.id}/custom-field-values"
f"/customFieldGroupId:{group_id}:customFieldId:{custom_field_id}"
)
self._make_patch_request(uri, payload={"content": value})
self._board_cache.pop(self.board_id, None)

def update_config(self, new_planka_config):
"""To be called after config automatic update."""
self._planka_config = new_planka_config or {}
Expand Down Expand Up @@ -187,6 +292,15 @@ def _make_request(self, uri, payload=None):
logger.debug(f"{response.url}")
return response.status_code, response.json()

def _make_patch_request(self, uri, payload=None):
response = requests.patch(
urljoin(self.api_url, uri.lstrip("/")),
json=payload or {},
headers=self.headers,
)
logger.debug(f"{response.url}")
return response.status_code, response.json()

def _get_board_data(self, board_id):
if board_id not in self._board_cache:
_, data = self._make_request(f"boards/{board_id}")
Expand Down Expand Up @@ -234,7 +348,11 @@ def _label_from_planka_dict(data):
try:
label.id = data["id"]
label.name = html.escape(data.get("name") or "")
label.color = TrelloCardColor.UNKNOWN
label.color = (
TrelloCardColor.BLACK
if data.get("color") == "grey-stone"
else TrelloCardColor.UNKNOWN
)
except Exception as e:
label._ok = False
logger.error(f"Bad Planka label json {data}", exc_info=e)
Expand Down
Loading