Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add in progress computation #125

Merged
merged 19 commits into from
Apr 1, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions packages/server/src/api/students.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
resources::{
catalog::DisplayCatalog,
course,
user::{User, UserDetails},
user::{User, UserDetails, UserSettings},
},
};

Expand Down Expand Up @@ -142,17 +142,25 @@ pub async fn compute_degree_status(
.malag_list
.clone(); // The collection malags contain one item with the list of all malags

let mut course_list = Vec::new();
if user.settings.compute_in_progress {
course_list = user_details.degree_status.set_in_progress_to_complete();
}

user_details
.degree_status
.compute(catalog, course::vec_to_map(vec_courses), malag_courses);

if user.settings.compute_in_progress {
user_details.degree_status.set_to_in_progress(course_list);
}
let user_id = user.sub.clone();
let document = doc! {"$set" : user.clone().into_document()};
db::services::find_and_update_user(&user_id, document, &client).await?;
Ok(HttpResponse::Ok().json(user))
}

// here "modified" becomes true
// here "modified" is true
#[put("/students/details")]
pub async fn update_details(
mut user: User,
Expand All @@ -165,3 +173,16 @@ pub async fn update_details(
db::services::find_and_update_user(&user_id, document, &client).await?;
Ok(HttpResponse::Ok().finish())
}

#[put("/students/settings")]
pub async fn update_settings(
mut user: User,
settings: Json<UserSettings>,
client: Data<mongodb::Client>,
) -> Result<HttpResponse, AppError> {
let user_id = user.sub.clone();
user.settings = settings.into_inner();
let document = doc! {"$set" : user.into_document()};
db::services::find_and_update_user(&user_id, document, &client).await?;
Ok(HttpResponse::Ok().finish())
}
60 changes: 60 additions & 0 deletions packages/server/src/api/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,66 @@ async fn test_students_api_full_flow() {
.await;
assert!(res.status().is_success());
}
#[test]
async fn test_compute_in_progress() {
dotenv().ok();

// Init env and app
let client = init_mongodb_client!();
let app = test::init_service(
App::new()
.app_data(Data::new(client.clone()))
.service(students::compute_degree_status)
.service(students::update_settings),
)
.await;

let get_degree_status_before = test::TestRequest::get()
.uri("/students/degree-status")
.to_request();
get_degree_status_before
.extensions_mut()
.insert::<auth::Sub>("bugo-the-debugo-senior".to_string());

let res = test::call_service(&app, get_degree_status_before).await;
let mut user: User = test::read_body_json(res).await;
assert_eq!(user.details.unwrap().degree_status.total_credit, 0.0);

user.settings.compute_in_progress = true;
let put_user_settings = test::TestRequest::put()
.uri("/students/settings")
.insert_header(("content-type", "application/json"))
.set_payload(serde_json::to_string(&user.settings).expect("Fail to deserialize user"))
.to_request();
put_user_settings
.extensions_mut()
.insert::<auth::Sub>("bugo-the-debugo-senior".to_string());
let res = test::call_service(&app, put_user_settings).await;
assert_eq!(res.status(), StatusCode::OK);

let get_degree_status_after = test::TestRequest::get()
.uri("/students/degree-status")
.to_request();
get_degree_status_after
.extensions_mut()
.insert::<auth::Sub>("bugo-the-debugo-senior".to_string());

let res = test::call_service(&app, get_degree_status_after).await;
let mut user: User = test::read_body_json(res).await;
assert_eq!(user.details.unwrap().degree_status.total_credit, 2.5);

user.settings.compute_in_progress = false;
let put_user_settings = test::TestRequest::put()
.uri("/students/settings")
.insert_header(("content-type", "application/json"))
.set_payload(serde_json::to_string(&user.settings).expect("Fail to deserialize user"))
.to_request();
put_user_settings
.extensions_mut()
.insert::<auth::Sub>("bugo-the-debugo-senior".to_string());
let res = test::call_service(&app, put_user_settings).await;
assert_eq!(res.status(), StatusCode::OK);
}

#[test]
async fn test_bo_api_courses() {
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/core/bank_rule/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl<'a> BankRuleHandler<'a> {
for course_status in self.degree_status.course_statuses.iter() {
if course_status.r#type == Some(self.bank_name.clone()) {
*sum_credit_requirement += course_status.course.credit;
if !course_status.passed() {
if !course_status.completed() {
*completed = false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/core/bank_rule/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ impl<'a> BankRuleHandler<'a> {
for course_id in chain {
if let Some(course_id) = credit_info.handled_courses.get(course_id) {
if let Some(course_status) = self.degree_status.get_course_status(course_id) {
if course_status.passed() {
if course_status.completed() {
chain_done.push(course_status.course.name.clone());
} else {
completed_chain = false;
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/core/bank_rule/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl<'a> BankRuleHandler<'a> {
sum_credit: &mut f32,
) -> bool {
course_status.set_type(bank_name);
if course_status.passed() {
if course_status.completed() {
*sum_credit += course_status.course.credit;
true
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ impl<'a> BankRuleHandler<'a> {
.degree_status
.get_course_status(&course_id_done_by_user)
{
if course_status.passed() {
if course_status.completed() {
completed_courses.push(course_id_in_list);
}
}
Expand Down
31 changes: 30 additions & 1 deletion packages/server/src/core/degree_status/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::collections::HashMap;
use crate::core::types::Requirement;
use crate::resources::{
catalog::Catalog,
course::{Course, CourseBank, CourseId, CourseStatus},
course::{Course, CourseBank, CourseId, CourseState, CourseStatus},
};
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -42,6 +42,35 @@ impl DegreeStatus {
}
None
}

// This function sets the state for all courses where their state is "in progress" to "complete"
// and returns a list of all courses which were changed, (CourseId, Semester) is a key for each courseStatus.
pub fn set_in_progress_to_complete(&mut self) -> Vec<(CourseId, Option<String>)> {
let mut changed_course_statuses = Vec::new();
for course_status in self.course_statuses.iter_mut() {
if course_status.state == Some(CourseState::InProgress) {
changed_course_statuses.push((
course_status.course.id.clone(),
course_status.semester.clone(),
));
course_status.state = Some(CourseState::Complete);
}
}
changed_course_statuses
}

// This function gets a list of courses and sets their state to "in progress"
pub fn set_to_in_progress(&mut self, course_list: Vec<(CourseId, Option<String>)>) {
for course_status in self.course_statuses.iter_mut() {
if course_list.contains(&(
course_status.course.id.clone(),
course_status.semester.clone(),
)) && course_status.state == Some(CourseState::Complete)
{
course_status.state = Some(CourseState::InProgress);
}
}
}
}

pub struct DegreeStatusHandler<'a> {
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/core/degree_status/preprocessing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl DegreeStatus {
if let Some(r#type) = &course_status.r#type {
course_status.semester.is_some()
|| course_status.modified
|| course_status.passed()
|| course_status.completed()
|| !bank_names.contains(r#type)
} else {
true
Expand Down
1 change: 1 addition & 0 deletions packages/server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ async fn main() -> std::io::Result<()> {
.service(api::students::add_courses)
.service(api::students::compute_degree_status)
.service(api::students::update_details)
.service(api::students::update_settings)
.service(api::bo::get_all_courses)
.service(api::bo::get_course_by_id)
.service(api::bo::create_or_update_course)
Expand Down
10 changes: 9 additions & 1 deletion packages/server/src/resources/course.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ impl CourseStatus {
}
}

pub fn completed(&self) -> bool {
self.state == Some(CourseState::Complete)
}

pub fn extract_semester(&self) -> f32 {
match self.semester.clone() {
Some(semester) => {
Expand All @@ -122,7 +126,11 @@ impl CourseStatus {
self.state = self
.passed()
.then(|| CourseState::Complete)
.or(Some(CourseState::NotComplete));
.or(if self.grade.is_none() {
Some(CourseState::InProgress)
} else {
Some(CourseState::NotComplete)
});
}
pub fn set_type(&mut self, r#type: String) -> &mut Self {
self.r#type = Some(r#type);
Expand Down
7 changes: 7 additions & 0 deletions packages/server/src/resources/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,25 @@ pub struct UserDetails {
pub modified: bool,
}

#[derive(Default, Clone, Debug, Deserialize, Serialize)]
pub struct UserSettings {
pub compute_in_progress: bool,
}

#[derive(Default, Clone, Debug, Deserialize, Serialize)]
pub struct User {
#[serde(rename(serialize = "_id", deserialize = "_id"))]
pub sub: String,
pub details: Option<UserDetails>,
pub settings: UserSettings,
}

impl User {
pub fn new_document(sub: &str) -> bson::Document {
let user = User {
sub: sub.into(),
details: Some(UserDetails::default()),
..Default::default()
};
// Should always unwrap successfully here..
bson::to_document(&user).unwrap_or(doc! {"sub" : sub, "details": null})
Expand Down
4 changes: 3 additions & 1 deletion packages/sogrim-app/src/components/App/UserApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const UserAppComp: React.FC = () => {
const { userAuthToken } = useAuth();
const { data, isLoading, isError, error } = useUserState(userAuthToken);
const {
dataStore: { updateStoreUserDetails },
dataStore: { updateStoreUserDetails, updateStoreUserSettings },
uiStore: { computeUserRegistrationState, userRegistrationState },
} = useStore();

Expand All @@ -29,10 +29,12 @@ const UserAppComp: React.FC = () => {
}
if (!isLoading && data) {
updateStoreUserDetails(data.details);
updateStoreUserSettings(data.settings);
}
}, [
data,
updateStoreUserDetails,
updateStoreUserSettings,
isLoading,
userRegistrationState,
computeUserRegistrationState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const DegreeMainStatsComp: React.FC = () => {
const totalBanks =
userDetails?.degree_status?.course_bank_requirements?.length;

return gpa && gpa > 0 ? (
return (
<Card sx={{ minWidth: 275, maxHeight: 150 }}>
<CardContent>
<Typography sx={{ fontSize: 18 }} color="text.secondary" gutterBottom>
Expand All @@ -51,7 +51,7 @@ const DegreeMainStatsComp: React.FC = () => {
</Button>
</CardContent>
</Card>
) : null;
);
};

export const DegreeMainStats = observer(DegreeMainStatsComp);
Loading