Corp/backend/tasks/presentation.py

99 lines
2.9 KiB
Python

"""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, [])