File size: 3,476 Bytes
02a8414
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
from __future__ import annotations

from datetime import datetime

from sqlalchemy.orm import Session, joinedload

from app.models import Activity, Submission, Task, User


def get_activity_with_group_context(db: Session, activity_id: int) -> Activity | None:
    return (
        db.query(Activity)
        .options(
            joinedload(Activity.tasks)
            .joinedload(Task.submissions)
            .joinedload(Submission.user)
            .joinedload(User.group),
            joinedload(Activity.tasks)
            .joinedload(Task.submissions)
            .joinedload(Submission.group),
            joinedload(Activity.tasks)
            .joinedload(Task.submissions)
            .joinedload(Submission.reviewed_by),
            joinedload(Activity.tasks)
            .joinedload(Task.submissions)
            .joinedload(Submission.assigned_admin),
        )
        .filter(Activity.id == activity_id)
        .first()
    )


def pick_primary_submission(submissions: list[Submission]) -> Submission | None:
    if not submissions:
        return None

    approved = [submission for submission in submissions if submission.status == "approved"]
    if approved:
        return min(
            approved,
            key=lambda item: ((item.approved_at or item.created_at or datetime.min), item.id),
        )

    pending = [submission for submission in submissions if submission.status == "pending"]
    if pending:
        return max(
            pending,
            key=lambda item: ((item.created_at or datetime.min), item.id),
        )

    rejected = [submission for submission in submissions if submission.status == "rejected"]
    if rejected:
        return max(
            rejected,
            key=lambda item: ((item.created_at or datetime.min), item.id),
        )

    return max(
        submissions,
        key=lambda item: ((item.created_at or datetime.min), item.id),
    )


def build_group_submission_map(activity: Activity, group_id: int | None) -> dict[int, Submission]:
    if not activity or not group_id:
        return {}

    group_submissions: dict[int, Submission] = {}
    for task in activity.tasks:
        task_submissions = [submission for submission in task.submissions if submission.group_id == group_id]
        primary_submission = pick_primary_submission(task_submissions)
        if primary_submission:
            group_submissions[task.id] = primary_submission
    return group_submissions


def build_group_progress(activity: Activity, group_id: int | None) -> dict:
    total_tasks = len(activity.tasks) if activity else 0
    if not activity or not group_id:
        return {
            "total_tasks": total_tasks,
            "approved_count": 0,
            "pending_count": 0,
            "rejected_count": 0,
            "completion_ratio": 0,
        }

    submission_map = build_group_submission_map(activity, group_id)
    approved_count = sum(1 for submission in submission_map.values() if submission.status == "approved")
    pending_count = sum(1 for submission in submission_map.values() if submission.status == "pending")
    rejected_count = sum(1 for submission in submission_map.values() if submission.status == "rejected")

    return {
        "total_tasks": total_tasks,
        "approved_count": approved_count,
        "pending_count": pending_count,
        "rejected_count": rejected_count,
        "completion_ratio": 0 if total_tasks == 0 else approved_count / total_tasks,
    }