99 lines
2.9 KiB
Python
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, [])
|