Skip to content

Commit 18d5420

Browse files
authored
Add API for expected attendance counts (#47)
1 parent 226f68e commit 18d5420

File tree

4 files changed

+66
-10
lines changed

4 files changed

+66
-10
lines changed

src/bin/trainee-tracker.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ async fn main() {
111111
"/api/attendance",
112112
get(trainee_tracker::endpoints::fetch_attendance),
113113
)
114+
.route(
115+
"/api/expected-attendance",
116+
get(trainee_tracker::endpoints::expected_attendance),
117+
)
114118
.layer(session_layer)
115119
.with_state(server_state);
116120

src/course.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ use crate::{
1616
sheets::SheetsClient,
1717
};
1818
use anyhow::Context;
19-
use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
20-
use chrono_tz::Tz;
19+
use chrono::{NaiveDate, Utc};
2120
use email_address::EmailAddress;
2221
use futures::future::join_all;
2322
use indexmap::{IndexMap, IndexSet};
@@ -800,14 +799,7 @@ fn get_trainee_module_attendance(
800799
.collect::<Vec<chrono::NaiveDate>>();
801800
let attendance = match dates.as_slice() {
802801
[date] => {
803-
let start_time = DateTime::<Tz>::from_naive_utc_and_offset(
804-
NaiveDateTime::new(
805-
date.clone(),
806-
NaiveTime::from_hms_opt(10, 00, 00).expect("TODO"),
807-
),
808-
region.timezone().offset_from_utc_date(date),
809-
)
810-
.to_utc();
802+
let start_time = region.class_start_time(date);
811803
let attendance = module_attendance
812804
.attendance
813805
.get(sprint_index)

src/endpoints.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
use std::{collections::BTreeMap, ops::AddAssign};
2+
13
use ::octocrab::models::{Author, teams::RequestedTeam};
24
use anyhow::Context;
35
use axum::{
46
Json,
57
extract::{OriginalUri, Path, State},
68
response::IntoResponse,
79
};
10+
use chrono::Utc;
811
use futures::future::join_all;
912
use http::HeaderMap;
1013
use indexmap::IndexMap;
@@ -284,3 +287,47 @@ pub async fn fetch_attendance(
284287
}
285288
Ok(Json(registered_attendance))
286289
}
290+
291+
#[derive(Serialize)]
292+
pub struct ExpectedAttendance {
293+
course: String,
294+
cohort: String,
295+
region: crate::newtypes::Region,
296+
expected_classes: usize,
297+
}
298+
299+
pub async fn expected_attendance(
300+
State(server_state): State<ServerState>,
301+
) -> Json<Vec<ExpectedAttendance>> {
302+
let now = Utc::now();
303+
304+
let mut expected_attendance = Vec::new();
305+
for (course, course_info) in server_state.config.courses {
306+
for (cohort, schedule) in course_info.batches {
307+
let mut region_to_expected_classes: BTreeMap<crate::newtypes::Region, usize> =
308+
BTreeMap::new();
309+
for (_module_name, sprints) in schedule.sprints {
310+
for sprint in sprints {
311+
for (region, date) in sprint {
312+
let start_time = region.class_start_time(&date);
313+
if start_time < now {
314+
region_to_expected_classes
315+
.entry(region)
316+
.or_default()
317+
.add_assign(1);
318+
}
319+
}
320+
}
321+
}
322+
for (region, expected_classes) in region_to_expected_classes {
323+
expected_attendance.push(ExpectedAttendance {
324+
course: course.clone(),
325+
cohort: cohort.clone(),
326+
region,
327+
expected_classes,
328+
})
329+
}
330+
}
331+
}
332+
Json(expected_attendance)
333+
}

src/newtypes.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{fmt::Display, str::FromStr};
22

33
use case_insensitive_string::CaseInsensitiveString;
4+
use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
45
use email_address::EmailAddress;
56
use serde::{Deserialize, Serialize};
67

@@ -52,4 +53,16 @@ impl Region {
5253
pub fn as_str(&self) -> &str {
5354
self.0.as_str()
5455
}
56+
57+
pub fn class_start_time(&self, date: &NaiveDate) -> DateTime<Utc> {
58+
let offset = self.timezone().offset_from_utc_date(date);
59+
DateTime::<chrono_tz::Tz>::from_naive_utc_and_offset(
60+
NaiveDateTime::new(
61+
*date,
62+
NaiveTime::from_hms_opt(10, 00, 00).expect("Known time failed to parse"),
63+
),
64+
offset,
65+
)
66+
.to_utc()
67+
}
5568
}

0 commit comments

Comments
 (0)