Skip to content

Commit

Permalink
Merge pull request #91 from hey2022/feat/overlay-subject
Browse files Browse the repository at this point in the history
feat: overlay subject from dynamic score
  • Loading branch information
hey2022 authored Jan 20, 2025
2 parents c4ee3b5 + ba66729 commit dc59e53
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 10 deletions.
38 changes: 29 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ async fn main() {

println!(":: Fetching subjects...");
let score_mapping_lists = Arc::new(default_score_mapping_lists());

let shared_client = Arc::clone(&client);
let subject_dynamic_scores_handle =
tokio::spawn(async move { get_subject_dynamic_scores(&shared_client, semester.id).await });

let shared_client = Arc::clone(&client);
let elective_class_ids_handle =
tokio::spawn(
Expand All @@ -94,10 +99,12 @@ async fn main() {

let mut subjects = Vec::new();
let elective_class_ids = elective_class_ids_handle.await.unwrap();
let subject_dynamic_scores = subject_dynamic_scores_handle.await.unwrap();
let results = join_all(handles).await;
for result in results {
let mut subject = result.unwrap();
adjust_weights(&mut subject, &elective_class_ids);
overlay_subject(&mut subject, &subject_dynamic_scores, &score_mapping_lists);
subjects.push(subject);
}

Expand Down Expand Up @@ -147,13 +154,26 @@ fn select_semester(semesters: &[Semester]) -> Semester {
semesters[current_semester].clone()
}

fn round_score(value: f64, decimal_places: u32) -> f64 {
let multiplier = 10f64.powi(decimal_places as i32);
(value * multiplier).round() / multiplier
}

fn print_subject(subject: &Subject, cli: &Cli) {
if subject.total_score.is_nan() {
return;
}
let mut data = vec![(
colorize(&subject.subject_name, &subject.score_level),
format!("{}", (subject.total_score * 10.0).round() / 10.0),
format!(
"{}{}",
round_score(subject.total_score, 1),
if subject.extra_credit > 0.0 {
format!(" ({} Extra credit)", round_score(subject.extra_credit, 2))
} else {
String::new()
}
),
subject.score_level.to_string(),
subject.gpa.to_string(),
subject.score_mapping_list_id.to_string() + if subject.elective { " Elective" } else { "" },
Expand Down Expand Up @@ -208,13 +228,13 @@ fn get_evaluation_project_row(
&evaluation_project.evaluation_project_e_name,
&evaluation_project.score_level,
),
format!("{}", (evaluation_project.score * 10.0).round() / 10.0),
format!("{}", round_score(evaluation_project.score, 1)),
evaluation_project.score_level.to_string(),
evaluation_project.gpa.to_string(),
format!(
"{}% ({}%)",
(evaluation_project.adjusted_proportion * 100.0).round() / 100.0,
(evaluation_project.proportion * 100.0).round() / 100.0
round_score(evaluation_project.adjusted_proportion, 2),
round_score(evaluation_project.proportion, 2),
),
)
}
Expand All @@ -231,10 +251,10 @@ fn get_evaluation_project_task_list_row(
.collect();
for learning_task in &learning_tasks {
let weight = evaluation_project.adjusted_proportion / learning_tasks.len() as f64;
let score =
(learning_task.score.unwrap_or(f64::NAN) / learning_task.total_score * 100.0 * 100.0)
.round()
/ 100.0;
let score = round_score(
learning_task.score.unwrap_or(f64::NAN) / learning_task.total_score * 100.0,
2,
);
let row = (
format!(
"- {}",
Expand All @@ -250,7 +270,7 @@ fn get_evaluation_project_task_list_row(
),
format!("{score}%"),
String::new(),
format!("- {}%", (weight * 100.0).round() / 100.0),
format!("- {}%", round_score(weight, 2)),
);
task_rows.push(row);
}
Expand Down
62 changes: 61 additions & 1 deletion src/subject.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::gpa::*;
use crate::{gpa::*, round_score};
use chrono::{DateTime, Duration, FixedOffset};
use itertools::Itertools;
use serde::Deserialize;
Expand Down Expand Up @@ -27,6 +27,8 @@ pub struct Subject {
pub subject_id: u64,
pub class_id: u64,
pub total_score: f64,
pub extra_credit: f64,
pub in_gpa: bool, // Unreliable method of determining whether subject counts into gpa
pub evaluation_projects: Vec<EvaluationProject>,
pub score_mapping_list_id: ScoreMappingId,
pub score_mapping_list: Vec<ScoreMappingConfig>,
Expand Down Expand Up @@ -64,6 +66,8 @@ pub async fn get_subject(
subject_id,
class_id: subject_detail.class_id,
total_score,
extra_credit: 0.0,
in_gpa: true,
evaluation_projects,
score_mapping_list_id,
score_mapping_list,
Expand Down Expand Up @@ -223,3 +227,59 @@ pub fn adjust_weights(subject: &mut Subject, elective_class_ids: &[u64]) {
subject.weight = 0.5;
}
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
#[allow(dead_code)]
pub struct SubjectDynamicScore {
class_id: u64,
class_name: String,
subject_id: u64,
subject_name: String,
is_in_grade: bool,
subject_score: Option<f64>,
score_mapping_id: u64,
subject_total_score: f64,
}

pub async fn get_subject_dynamic_scores(
client: &reqwest::Client,
semester_id: u64,
) -> Vec<SubjectDynamicScore> {
let response: serde_json::Value = client
.get(format!("https://tsinglanstudent.schoolis.cn/api/DynamicScore/GetStuSemesterDynamicScore?semesterId={semester_id}"))
.send()
.await.unwrap()
.json()
.await.unwrap();
serde_json::from_value(response["data"]["studentSemesterDynamicScoreBasicDtos"].clone())
.expect("Failed to get semester dynamic score")
}

pub fn overlay_subject(
subject: &mut Subject,
subject_dynamic_scores: &[SubjectDynamicScore],
score_mapping_lists: &HashMap<ScoreMappingId, Vec<ScoreMappingConfig>>,
) {
for dynamic_score in subject_dynamic_scores {
if subject.class_id == dynamic_score.class_id {
subject.in_gpa = dynamic_score.is_in_grade;
let new_score = dynamic_score.subject_score.unwrap_or(f64::NAN)
/ dynamic_score.subject_total_score
* 100.0;
subject.extra_credit = new_score - round_score(subject.total_score, 1);
subject.total_score = new_score;
// Definitely need to refactor this spaghetti
subject.gpa = gpa_from_score(subject.total_score, &subject.score_mapping_list);
subject.unweighted_gpa = gpa_from_score(
subject.total_score,
&score_mapping_lists[&ScoreMappingId::NonWeighted],
);
subject.score_level =
score_level_from_score(subject.total_score, &subject.score_mapping_list);

// There should be only one match
return;
}
}
}

0 comments on commit dc59e53

Please sign in to comment.