|
19 | 19 | from todo.dto.team_dto import TeamDTO
|
20 | 20 | from todo.services.user_service import UserService
|
21 | 21 | from todo.repositories.team_repository import TeamRepository
|
| 22 | +from todo.repositories.audit_log_repository import AuditLogRepository |
| 23 | +from todo.repositories.user_repository import UserRepository |
| 24 | +from todo.repositories.task_repository import TaskRepository |
22 | 25 |
|
23 | 26 |
|
24 | 27 | class TeamListView(APIView):
|
@@ -367,3 +370,85 @@ def get(self, request: Request, team_id: str):
|
367 | 370 | {"detail": "You are not authorized to view the invite code for this team."},
|
368 | 371 | status=status.HTTP_403_FORBIDDEN,
|
369 | 372 | )
|
| 373 | + |
| 374 | + |
| 375 | +class TeamActivityTimelineView(APIView): |
| 376 | + @extend_schema( |
| 377 | + operation_id="get_team_activity_timeline", |
| 378 | + summary="Get team activity timeline", |
| 379 | + description="Return a timeline of all activities related to tasks assigned to the team, including assignment, unassignment, executor changes, and status changes. All IDs are replaced with names.", |
| 380 | + tags=["teams"], |
| 381 | + parameters=[ |
| 382 | + OpenApiParameter( |
| 383 | + name="team_id", |
| 384 | + type=OpenApiTypes.STR, |
| 385 | + location=OpenApiParameter.PATH, |
| 386 | + description="Unique identifier of the team", |
| 387 | + required=True, |
| 388 | + ), |
| 389 | + ], |
| 390 | + responses={ |
| 391 | + 200: OpenApiResponse( |
| 392 | + response={ |
| 393 | + "type": "object", |
| 394 | + "properties": { |
| 395 | + "timeline": { |
| 396 | + "type": "array", |
| 397 | + "items": {"type": "object"}, |
| 398 | + } |
| 399 | + }, |
| 400 | + }, |
| 401 | + description="Team activity timeline returned successfully", |
| 402 | + ), |
| 403 | + 404: OpenApiResponse(description="Team not found"), |
| 404 | + }, |
| 405 | + ) |
| 406 | + def get(self, request: Request, team_id: str): |
| 407 | + team = TeamRepository.get_by_id(team_id) |
| 408 | + if not team: |
| 409 | + return Response({"detail": "Team not found."}, status=status.HTTP_404_NOT_FOUND) |
| 410 | + logs = AuditLogRepository.get_by_team_id(team_id) |
| 411 | + # Pre-fetch team name |
| 412 | + team_name = team.name |
| 413 | + # Pre-fetch all user and task names needed |
| 414 | + user_ids = set() |
| 415 | + task_ids = set() |
| 416 | + for log in logs: |
| 417 | + if log.performed_by: |
| 418 | + user_ids.add(str(log.performed_by)) |
| 419 | + if log.spoc_id: |
| 420 | + user_ids.add(str(log.spoc_id)) |
| 421 | + if log.previous_executor_id: |
| 422 | + user_ids.add(str(log.previous_executor_id)) |
| 423 | + if log.new_executor_id: |
| 424 | + user_ids.add(str(log.new_executor_id)) |
| 425 | + if log.task_id: |
| 426 | + task_ids.add(str(log.task_id)) |
| 427 | + user_map = {str(u.id): u.name for u in UserRepository.get_by_ids(list(user_ids))} |
| 428 | + task_map = {str(t.id): t.title for t in TaskRepository.get_by_ids(list(task_ids))} |
| 429 | + timeline = [] |
| 430 | + for log in logs: |
| 431 | + entry = { |
| 432 | + "action": log.action, |
| 433 | + "timestamp": log.timestamp, |
| 434 | + } |
| 435 | + if log.task_id: |
| 436 | + entry["task_title"] = task_map.get(str(log.task_id), str(log.task_id)) |
| 437 | + if log.team_id: |
| 438 | + entry["team_name"] = team_name |
| 439 | + if log.performed_by: |
| 440 | + entry["performed_by_name"] = user_map.get(str(log.performed_by), str(log.performed_by)) |
| 441 | + if log.spoc_id: |
| 442 | + entry["spoc_name"] = user_map.get(str(log.spoc_id), str(log.spoc_id)) |
| 443 | + if log.previous_executor_id: |
| 444 | + entry["previous_executor_name"] = user_map.get( |
| 445 | + str(log.previous_executor_id), str(log.previous_executor_id) |
| 446 | + ) |
| 447 | + if log.new_executor_id: |
| 448 | + entry["new_executor_name"] = user_map.get(str(log.new_executor_id), str(log.new_executor_id)) |
| 449 | + if log.status_from: |
| 450 | + entry["status_from"] = log.status_from |
| 451 | + if log.status_to: |
| 452 | + entry["status_to"] = log.status_to |
| 453 | + timeline.append(entry) |
| 454 | + return Response({"timeline": timeline}, status=status.HTTP_200_OK) |
0 commit comments