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, }