-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsummary_handler.py
110 lines (80 loc) · 3.28 KB
/
summary_handler.py
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
101
102
103
104
105
106
107
108
109
110
from collections import Counter, defaultdict
from datetime import date, datetime
from typing import Iterable
from zoneinfo import ZoneInfo
from pydantic import BaseModel, TypeAdapter, ValidationError
from models.user_record import ApplicantStatus, Role
from services import mongodb_handler
from services.mongodb_handler import Collection
LOCAL_TIMEZONE = ZoneInfo("America/Los_Angeles")
class ApplicantSummaryRecord(BaseModel):
status: ApplicantStatus
async def applicant_summary() -> Counter[ApplicantStatus]:
"""Get summary of applicants by status."""
records = await mongodb_handler.retrieve(
Collection.USERS,
{"roles": Role.APPLICANT},
["status"],
)
applicants = TypeAdapter(list[ApplicantSummaryRecord]).validate_python(records)
return Counter(applicant.status for applicant in applicants)
class ApplicationSubmissionTime(BaseModel):
submission_time: datetime
class ApplicationSchoolAndTime(ApplicationSubmissionTime):
school: str
class ApplicantSchoolStats(BaseModel):
application_data: ApplicationSchoolAndTime
async def applications_by_school() -> dict[str, dict[date, int]]:
"""Get daily number of applications by school."""
records = await mongodb_handler.retrieve(
Collection.USERS,
{"roles": Role.APPLICANT},
["application_data.school", "application_data.submission_time"],
)
try:
applicant_stats_adapter = TypeAdapter(list[ApplicantSchoolStats])
applicants = applicant_stats_adapter.validate_python(records)
except ValidationError:
raise RuntimeError("Could not parse applicant data.")
grouped_applications: dict[str, dict[date, int]] = defaultdict(
lambda: defaultdict(int)
)
for applicant in applicants:
school = applicant.application_data.school
day = applicant.application_data.submission_time.astimezone(
LOCAL_TIMEZONE
).date()
grouped_applications[school][day] += 1
return grouped_applications
class ApplicantRoleStats(BaseModel):
roles: tuple[Role, ...]
application_data: ApplicationSubmissionTime
async def applications_by_role() -> dict[str, dict[date, int]]:
"""Get daily number of applications by role."""
records: list[dict[str, object]] = await mongodb_handler.retrieve(
Collection.USERS,
{"roles": Role.APPLICANT},
["roles", "application_data.submission_time"],
)
try:
applicant_stats_adapter = TypeAdapter(list[ApplicantRoleStats])
applicants = applicant_stats_adapter.validate_python(records)
except ValidationError:
raise RuntimeError("Could not parse applicant data.")
return {
role.value: _count_applications_by_day(
applicant.application_data
for applicant in applicants
if role in applicant.roles
)
for role in [Role.HACKER, Role.MENTOR, Role.VOLUNTEER]
}
def _count_applications_by_day(
application_data: Iterable[ApplicationSubmissionTime],
) -> dict[date, int]:
"""Group the applications by the date of submission."""
daily_applications = defaultdict[date, int](int)
for data in application_data:
day = data.submission_time.astimezone(LOCAL_TIMEZONE).date()
daily_applications[day] += 1
return daily_applications