"""Safe compact task badges shown on resources linked to tasks.""" from collections.abc import Iterable from django.contrib.contenttypes.models import ContentType from tasks.access import task_board_access_q from tasks.models import TaskBoard, TaskLinkedObject def accessible_task_board_ids(user) -> set[int]: if not user or not getattr(user, "is_authenticated", False): return set() return set( TaskBoard.objects.filter(is_archived=False) .filter(task_board_access_q(user)) .values_list("id", flat=True) .distinct() ) def linked_task_badge_payload( link: TaskLinkedObject, *, accessible_board_ids: set[int], include_task_card_fields: bool = False, ) -> dict: task = link.task can_open = task.board_id in accessible_board_ids payload = { "link_id": link.id, "id": task.id, "title": task.title, "board_id": task.board_id, "board_name": task.board.name, "column_id": task.column_id, "column_name": task.column.name, "column_color": task.column.color, "priority": task.priority, "priority_display": task.get_priority_display(), "can_open": can_open, } if include_task_card_fields: # Linked-task management screens historically consume a TaskCard-like # shape. Keep these aliases without exposing the full task serializer. payload.update(board=task.board_id, column=task.column_id) return payload def linked_task_badges_by_object( *, model, kind: str, object_ids: Iterable[int], user, include_task_card_fields: bool = False, ) -> dict[int, list[dict]]: ids = list(dict.fromkeys(object_ids)) mapping = {object_id: [] for object_id in ids} if not ids or not user or not getattr(user, "is_authenticated", False): return mapping content_type = ContentType.objects.get_for_model(model) board_ids = accessible_task_board_ids(user) links = ( TaskLinkedObject.objects.filter( kind=kind, content_type=content_type, object_id__in=ids, ) .select_related("task", "task__board", "task__column") .order_by("object_id", "task__title", "task_id") ) for link in links: mapping.setdefault(link.object_id, []).append( linked_task_badge_payload( link, accessible_board_ids=board_ids, include_task_card_fields=include_task_card_fields, ) ) return mapping def linked_task_badges_for_object( *, obj, kind: str, user, include_task_card_fields: bool = False, ) -> list[dict]: return linked_task_badges_by_object( model=obj.__class__, kind=kind, object_ids=[obj.id], user=user, include_task_card_fields=include_task_card_fields, ).get(obj.id, [])