diff --git a/main.cpp b/main.cpp index 7df3183..f4ebd26 100644 --- a/main.cpp +++ b/main.cpp @@ -1387,7 +1387,13 @@ void load_student_grades(std::vector &students) { event = "Open"; s->set_event_grade_inquiry(true); } - s->setGradeableItemGrade_border(g,which,score,event,late_days_charged,other_note,status); + int late_day_exceptions = itr2->value("late_day_exceptions",0); + std::string reason_for_exception = itr2->value("reason_for_exception",""); + if (late_day_exceptions > 0) { + event = "Extension"; + s->set_event_extension(true); + } + s->setGradeableItemGrade_border(g,which,score,event,late_days_charged,other_note,status,late_day_exceptions,reason_for_exception); } } @@ -1736,6 +1742,35 @@ void loadAllowedLateDays(std::vector &students) { } } +void SaveExtensionReports(const std::vector &students) { + system ("mkdir -p student_extension_reports"); + for (size_t i=0;i > > gradeablesWithExtensions = students[i]->getItemsWithExceptions(); + std::string username = students[i]->getUserName(); + std::ofstream student_ostr("student_extension_reports/"+username+".html"); + assert (student_ostr.good()); + if (gradeablesWithExtensions.size() == 0) { + continue; + } + student_ostr << "

Excused Absence Extensions for: " << username << "

" << std::endl; + student_ostr << "" << std::endl; + student_ostr << "" << std::endl; + for (size_t i2=0;i2(gradeablesWithExtensions[i2]); + GRADEABLE_ENUM g = std::get<0>(std::get<1>(gradeablesWithExtensions[i2])); + int index = std::get<1>(std::get<1>(gradeablesWithExtensions[i2])); + std::string gradeable_id = GRADEABLES[g].getID(index); + std::string gradeable_name = ""; + if (GRADEABLES[g].hasCorrespondence(gradeable_id)) { + gradeable_name = GRADEABLES[g].getCorrespondence(gradeable_id).second; + } + student_ostr << "" << std::endl; + } + student_ostr << "
GradeableDays ExtendedReason
" << gradeable_name << "" + << item.getLateDayExceptions() << "" + << item.getReasonForException() << "
" << std::endl; + } +} int main(int argc, char* argv[]) { @@ -1757,6 +1792,8 @@ int main(int argc, char* argv[]) { LoadPolls(students); SavePollReports(students); + SaveExtensionReports(students); + loadAllowedLateDays(students); // ====================================================================== diff --git a/output.cpp b/output.cpp index c181863..deb3ef5 100644 --- a/output.cpp +++ b/output.cpp @@ -677,6 +677,7 @@ void start_table_output( bool /*for_instructor*/, //Late days headers student_data.push_back(counter); table.set(0,counter++,TableCell("ffffff","ALLOWED LATE DAYS")); student_data.push_back(counter); table.set(0,counter++,TableCell("ffffff","USED LATE DAYS")); + student_data.push_back(counter); table.set(0,counter++,TableCell("ffffff","EXCUSED EXTENSIONS")); student_data.push_back(counter); table.set(0,counter++,TableCell(grey_divider)); } } @@ -1033,12 +1034,17 @@ void start_table_output( bool /*for_instructor*/, std::string status = this_student->getGradeableItemGrade(g,j).getStatus(); std::string event = this_student->getGradeableItemGrade(g,j).getEvent(); bool Academic_integrity = this_student->getGradeableItemGrade(g,j).getAcademicIntegrity(); + std::string reason = this_student->getGradeableItemGrade(g,j).getReasonForException(); + std::string gID = GRADEABLES[g].getID(j); + std::string userName = this_student->getUserName(); if (status.find("Bad") != std::string::npos) { details += " " + status; } int late_days_used = this_student->getGradeableItemGrade(g,j).getLateDaysUsed(); + int daysExtended = this_student->getGradeableItemGrade(g,j).getLateDayExceptions(); assert (color.size()==6); - table.set(myrow,counter++,TableCell(grade,color,1,details,late_days_used,visible,event,Academic_integrity)); + std::string a = "right"; + table.set(myrow,counter++,TableCell(grade,color,1,details,late_days_used,visible,event,Academic_integrity,a,1,0,reason,gID,userName,daysExtended)); } table.set(myrow,counter++,TableCell(grey_divider)); @@ -1081,6 +1087,9 @@ void start_table_output( bool /*for_instructor*/, int used = this_student->getUsedLateDays(); color = coloritcolor(allowed-used+2, 5+2, 3+2, 2+2, 1+2, 0+2); table.set(myrow,counter++,TableCell(color,used,"",0,CELL_CONTENTS_VISIBLE,"right")); + int exceptions = this_student->getLateDayExceptions(); + color = coloritcolor(exceptions,5,4,3,2,2); + table.set(myrow,counter++,TableCell(color,exceptions,"",0,CELL_CONTENTS_VISIBLE,"right")); } else { color="ffffff"; // default_color; table.set(myrow,counter++,TableCell(color,"")); @@ -1089,6 +1098,7 @@ void start_table_output( bool /*for_instructor*/, table.set(myrow,counter++,TableCell(color,"")); table.set(myrow,counter++,TableCell(color,"")); table.set(myrow,counter++,TableCell(color,"")); + table.set(myrow,counter++,TableCell(color,"")); } table.set(myrow,counter++,TableCell(grey_divider)); } @@ -1188,7 +1198,7 @@ void end_table(std::ofstream &ostr, bool for_instructor, Student *s) { // Description of border outline that are in effect if (for_instructor || s != NULL) { - if (for_instructor || (s != NULL && (s->get_event_bad_status() || s->get_event_grade_inquiry() || s->get_event_overridden() || s->get_event_academic_integrity()))) + if (for_instructor || (s != NULL && (s->get_event_bad_status() || s->get_event_grade_inquiry() || s->get_event_overridden() || s->get_event_academic_integrity() || s->get_event_extension()))) { ostr << "\n"; ostr << "\n"; @@ -1210,7 +1220,18 @@ void end_table(std::ofstream &ostr, bool for_instructor, Student *s) { ostr << ""; ostr << ""; ostr << ""; + ostr << "\n"; + } + if (for_instructor || (s != NULL && s->get_event_extension())) + { + ostr << "\n"; + ostr << ""; + ostr << ""; ostr << "\n"; } @@ -1221,7 +1242,7 @@ void end_table(std::ofstream &ostr, bool for_instructor, Student *s) { ostr << ""; ostr << ""; ostr << ""; ostr << "\n"; } @@ -1243,6 +1264,13 @@ void end_table(std::ofstream &ostr, bool for_instructor, Student *s) { if (s != NULL) { + std::ifstream istr2("student_extension_reports/"+s->getUserName()+".html"); + if (istr2.good()) { + std::string tmp_s; + while (getline(istr2,tmp_s)) { + ostr << tmp_s; + } + } std::ifstream istr("student_poll_reports/"+s->getUserName()+".html"); if (istr.good()) { std::string tmp_s; diff --git a/student.cpp b/student.cpp index 8f4a529..05e6ed0 100644 --- a/student.cpp +++ b/student.cpp @@ -106,13 +106,15 @@ void Student::setGradeableItemGrade_AcademicIntegrity(GRADEABLE_ENUM g, int i, f itr->second[i] = ItemGrade(value,late_days_used,note,status,temp,academic_integrity); } -void Student::setGradeableItemGrade_border(GRADEABLE_ENUM g, int i, float value, const std::string &event, int late_days_used, const std::string ¬e, const std::string &status) { +void Student::setGradeableItemGrade_border(GRADEABLE_ENUM g, int i, float value, const std::string &event, + int late_days_used, const std::string ¬e, const std::string &status, int exceptions, const std::string &reason) { assert (i >= 0 && i < GRADEABLES[g].getCount()); std::map >::iterator itr = all_item_grades.find(g); assert (itr != all_item_grades.end()); assert (int(itr->second.size()) > i); + bool academic_integrity = false; - itr->second[i] = ItemGrade(value,late_days_used,note,status,event); + itr->second[i] = ItemGrade(value,late_days_used,note,status,event,academic_integrity,exceptions,reason); } @@ -211,7 +213,7 @@ float Student::GradeablePercent(GRADEABLE_ENUM g) const { //if(!id.empty() && GRADEABLES[g].isReleased(id)){ if(!id.empty()){ m = GRADEABLES[g].getItemMaximum(id); - std::cout << "m" << m << std::endl; + // std::cout << "m" << m << std::endl; } float p = GRADEABLES[g].getItemPercentage(id); float sm = GRADEABLES[g].getScaleMaximum(id); @@ -429,6 +431,30 @@ int Student::getUsedLateDays() const { return answer; } + int Student::getLateDayExceptions() const { + int answer = 0; + for (std::map >::const_iterator itr = all_item_grades.begin(); itr != all_item_grades.end(); itr++) { + for (std::size_t i = 0; i < itr->second.size(); i++) { + answer += itr->second[i].getLateDayExceptions(); + } + } + return answer; + } + + std::vector > > Student::getItemsWithExceptions() const { + std::vector > > result; + for (std::map >::const_iterator itr = all_item_grades.begin(); itr != all_item_grades.end(); itr++) { + for (std::size_t i = 0; i < itr->second.size(); i++) { + if (itr->second[i].getLateDayExceptions()>0) { + std::tuple indexes{itr->first,i}; + std::tuple > itemInfo{itr->second[i],indexes}; + result.push_back(itemInfo); + } + } + } + return result; + } + // ============================================================================================= float Student::overall_b4_academic_sanction() const { diff --git a/student.h b/student.h index afa0e77..e34f42e 100644 --- a/student.h +++ b/student.h @@ -21,12 +21,14 @@ extern std::vector GLOBAL_earned_late_days; class ItemGrade { public: - ItemGrade(float v, int ldu=0, const std::string& n="", const std::string &s="", const std::string &e="", bool ai=false) { + ItemGrade(float v, int ldu=0, const std::string& n="", const std::string &s="", const std::string &e="", bool ai=false, int de=0, const std::string& r="") { value = v; late_days_used = ldu; note = n; event = e; academic_integrity = ai; + late_day_exceptions = de; + reason_for_exception = r; if (s != "UNKONWN") { status = s; @@ -55,6 +57,8 @@ class ItemGrade { return adjusted_value; } int getLateDaysUsed() const { return late_days_used; } + int getLateDayExceptions() const { return late_day_exceptions; } + const std::string& getReasonForException() const { return reason_for_exception; } const std::string& getNote() const { return note; } const std::string& getStatus() const { return status; } const std::string& getEvent() const { return event; } @@ -63,10 +67,12 @@ class ItemGrade { private: float value; int late_days_used; + int late_day_exceptions; bool academic_integrity; std::string note; std::string status; std::string event; + std::string reason_for_exception; }; //==================================================================== @@ -108,6 +114,8 @@ class Student { int getPollsIncorrect() const; float getPollPoints() const; int getUsedLateDays() const; + int getLateDayExceptions() const; + std::vector > > getItemsWithExceptions() const; float getAcademicSanctionPenalty() const { return academic_sanction_penalty; } void setCurrentAllowedLateDays(int d) { current_allowed_late_days = d; } @@ -174,7 +182,7 @@ class Student { void setTestZone(int which_test, const std::string &zone) { zones[which_test] = zone; } void setGradeableItemGrade(GRADEABLE_ENUM g, int i, float value, int late_days_used=0, const std::string ¬e="",const std::string &status=""); void setGradeableItemGrade_AcademicIntegrity(GRADEABLE_ENUM g, int i, float value, bool academic_integrity, int late_days_used=0, const std::string ¬e="",const std::string &status=""); - void setGradeableItemGrade_border(GRADEABLE_ENUM g, int i, float value, const std::string &event="", int late_days_used=0, const std::string ¬e="",const std::string &status=""); + void setGradeableItemGrade_border(GRADEABLE_ENUM g, int i, float value, const std::string &event="", int late_days_used=0, const std::string ¬e="",const std::string &status="",int exceptions=0, const std::string &reason=""); void academic_sanction(const std::string &gradeable, float penalty); @@ -182,10 +190,12 @@ class Student { void set_event_grade_inquiry(bool value) {grade_inquiry = value;} void set_event_overridden(bool value) {overridden = value;} void set_event_bad_status(bool value) {bad_status = value;} + void set_event_extension(bool value) {extension = value;} bool get_event_academic_integrity() {return academic_integrity;} bool get_event_grade_inquiry() {return grade_inquiry;} bool get_event_overridden() {return overridden;} bool get_event_bad_status() {return bad_status;} + bool get_event_extension() {return extension;} // other grade-like data void setNumericID(const std::string& r_id) { numeric_id = r_id; } @@ -247,6 +257,7 @@ class Student { bool grade_inquiry = false; bool overridden = false; bool bad_status = false; + bool extension = false; // registration status std::string section; diff --git a/table.cpp b/table.cpp index 09e2e74..23926f4 100644 --- a/table.cpp +++ b/table.cpp @@ -74,7 +74,8 @@ TableCell::TableCell(const std::string& c, float d, int precision, const std::st TableCell::TableCell(float d, const std::string& c, int precision, const std::string& n, int ldu, - CELL_CONTENTS_STATUS v,const std::string& e,bool ai, const std::string& a, int s, int /*r*/) { + CELL_CONTENTS_STATUS v,const std::string& e,bool ai, const std::string& a, + int s, int /*r*/,const std::string& reason,const std::string& gID,const std::string& userName, int daysExtended) { assert (c.size() == 6); assert (precision >= 0); color=c; @@ -93,17 +94,24 @@ TableCell::TableCell(float d, const std::string& c, int precision, const std::st rotate = 0; academic_integrity = ai; event = e; + if (reason != "") { + hoverText = "class=\"hoverable-cell\" data-hover-text=\""+userName+" received a "+std::to_string(daysExtended)+" day extension due to "+reason+" on "+gID+"\" "; + } + else hoverText = ""; if (event == "Bad"){ bad_status = true; - override = inquiry = false; + override = inquiry = extension = false; } else if ( event == "Overridden"){ override = true; - bad_status = inquiry = false; + bad_status = inquiry = extension = false; } else if (event == "Open"){ inquiry = true; - bad_status = override = false; + bad_status = override = extension = false; + } else if (event == "Extension"){ + extension = true; + inquiry = bad_status = override = false; } else { - inquiry = bad_status = override = false; + inquiry = bad_status = override = extension = false; } } @@ -120,15 +128,15 @@ std::ostream& operator<<(std::ostream &ostr, const TableCell &c) { mark = "@"; } else if (c.override){ outline = "outline:4px solid #fcca03; outline-offset: -4px;"; + } else if (c.extension){ + outline = "outline:4px solid #0066e0; outline-offset: -4px;"; } else if (c.inquiry){ outline = "outline:4px dashed #1cfc03; outline-offset: -4px;"; } else if (c.bad_status){ outline = "outline:4px solid #fc0303; outline-offset: -4px;"; } - // ostr << "
"; - ostr << " Grade override "; + ostr << " Grade Override "; + ostr << "
"; + ostr << ""; + ostr << ""; + ostr << " Excused Absence Extension "; ostr << "
"; - ostr << " Grade inquiry in progress "; + ostr << " Grade Inquiry in Progress "; ostr << "
"; - ostr << ""; - + ostr << ""; if (0) { //rotate == 90) { ostr << "

"; } @@ -236,10 +244,37 @@ void Table::output(std::ostream& ostr, if (last_update != "") { ostr << "Information last updated: " << last_update << "
\n"; } + + ostr << ""; + + ostr << " 
\n"; ostr << "\n"; } - + + + if (transpose) { for (std::vector::iterator c = which_data.begin(); c != which_data.end(); c++) { ostr << "\n"; diff --git a/table.h b/table.h index e81e6b2..ad07ac4 100644 --- a/table.h +++ b/table.h @@ -24,7 +24,8 @@ class TableCell { TableCell(const std::string& c , float d , int precision, const std::string& n="", int ldu=0, CELL_CONTENTS_STATUS v=CELL_CONTENTS_VISIBLE, const std::string& a="right", int s=1, int r=0); TableCell(float d ,const std::string& c , int precision, const std::string& n="", int ldu=0, - CELL_CONTENTS_STATUS v=CELL_CONTENTS_VISIBLE, const std::string& e="", bool ai = false, const std::string& a="right", int s=1, int r=0); + CELL_CONTENTS_STATUS v=CELL_CONTENTS_VISIBLE, const std::string& e="", bool ai = false, const std::string& a="right", + int s=1, int r=0, const std::string& reason="",const std::string& gID="",const std::string& userName="",int daysExtended=0); std::string make_cell_string(bool csv_mode) const; std::string color; @@ -35,6 +36,8 @@ class TableCell { bool inquiry = false; bool bad_status = false; bool override = false; + bool extension = false; + std::string hoverText = ""; std::string align; enum CELL_CONTENTS_STATUS visible; int span;