// AttainmentGroups produces a page with a summary of the // attainment of each subgroup func AttainmentGroups(e env.Env) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 1); redir { return } header(e, w, r, 1) defer footer(e, w, r) f := getFilter(e, r) g, err := e.GroupByFilter(f) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } data := struct { Query template.URL Groups []subGroup }{ template.URL(r.URL.RawQuery), subGroups(g), } err = e.Templates.ExecuteTemplate(w, "attainmentgroups.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) } } }
// Search returns a student search page func Search(e env.Env) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 0); redir { return } header(e, w, r, 0) defer footer(e, w, r) name := r.URL.Query().Get("name") f := getFilter(e, r) g, err := e.Search(name, f) data := struct { Query template.URL Name string Group group.Group }{ template.URL(r.URL.RawQuery), name, g, } err = e.Templates.ExecuteTemplate(w, "studentsearch.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) } } }
func SubjectSpreadsheet(e env.Env, f database.Filter, subj *subject.Subject, w io.Writer) error { file := xlsx.NewFile() g, err := e.GroupByFilteredClass(strconv.Itoa(subj.SubjID), "", f) if err != nil { return err } sheet, err := file.AddSheet("Progress Grid") if err != nil { return err } subjectGrid(sheet, g, subj, f.NatYear) sheet, err = file.AddSheet("Students") if err != nil { return err } subjectBroadsheet(e, subj, sheet, g) sheet, err = file.AddSheet("Export Details") if err != nil { return err } exportInfoSheet(sheet, e, f) file.Write(w) return nil }
// AttendanceExplorer provides a page for exploring the attendance figures // in more detail, and examine individual students. func AttendanceExplorer(e env.Env) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 2); redir { return } header(e, w, r, 2) defer footer(e, w, r) f := getFilter(e, r) g, err := e.GroupByFilter(f) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } week, _ := e.CurrentWeek() data := struct { Query template.URL Week string Group group.Group }{ template.URL(r.URL.RawQuery), week, g, } err = e.Templates.ExecuteTemplate(w, "attendance.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) } } }
// Index produces a landing page func Index(e env.Env) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 0); redir { return } header(e, w, r, 0) defer footer(e, w, r) news, err := e.News() if err != nil { fmt.Fprintf(w, "Error: %v", err) } data := struct { School string News []database.NewsItem }{ e.Config.School, news, } err = e.Templates.ExecuteTemplate(w, "index.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) } } }
// Student produces a page for an individual student with all of their // details/results/attendance etc. func Student(e env.Env) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 0); redir { return } header(e, w, r, 0) defer footer(e, w, r) path := strings.Split(r.URL.Path, "/") if len(path) < 3 { fmt.Fprintf(w, "Error: Invalid path") return } upn := path[2] f := getFilter(e, r) s, err := e.Student(upn, f) if err != nil { fmt.Fprintf(w, "Error: %v", err) } data := struct { Student student.Student }{ s, } err = e.Templates.ExecuteTemplate(w, "student.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) } } }
func subjectGroupPage(e env.Env, w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 2); redir { return } header(e, w, r, 2) defer footer(e, w, r) path := strings.Split(r.URL.Path, "/") subjID, err := strconv.Atoi(path[3]) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } subj := e.Subjects[subjID] f := getFilter(e, r) g, err := e.GroupByFilteredClass(path[3], "", f) if err != nil { fmt.Fprintf(w, "Error: %v", err) } classes, err := e.Classes(path[3], f.Date) if err != nil { fmt.Fprintf(w, "Error: %v", err) } sort.Sort(sort.StringSlice(classes)) clsGrps := []subGroup{} for _, c := range classes { grp := g.SubGroup(group.Class(subj.Subj, c)) if len(grp.Students) > 0 { clsGrps = append(clsGrps, subGroup{c, template.URL(c), grp}) } } data := struct { Query template.URL Year string Subj *subject.Subject SubGroups []subGroup Matrix subGroupMatrix Classes []subGroup }{ template.URL(r.URL.RawQuery), f.Year, subj, subGroups(g), groupMatrix(g), clsGrps, } err = e.Templates.ExecuteTemplate(w, "subjectgroups.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } }
// EnglishAndMaths produces a summary page with the number/percentage // of students achieving passes in English and/or Maths. func EnglishAndMaths(e env.Env) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 2); redir { return } header(e, w, r, 2) defer footer(e, w, r) f := getFilter(e, r) g, err := e.GroupByFilter(f) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } groups := []group.Group{{}, {}, {}, {}} for _, s := range g.Students { eng := s.EBaccArea("E").Achieved maths := s.EBaccArea("M").Achieved switch { case eng && maths: groups[2].Students = append(groups[2].Students, s) case eng: groups[0].Students = append(groups[0].Students, s) case maths: groups[1].Students = append(groups[1].Students, s) default: groups[3].Students = append(groups[3].Students, s) } } pcts := []float64{} for _, grp := range groups { pcts = append(pcts, float64(len(grp.Students))/float64(len(g.Students))) } data := struct { Query template.URL Names []string Groups []group.Group Pcts []float64 }{ template.URL(r.URL.RawQuery), []string{"English Only", "Mathematics Only", "English & Maths", "Neither"}, groups, pcts, } err = e.Templates.ExecuteTemplate(w, "em.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) } } }
// Performs analysis of the results func progressGridPage(e env.Env, w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 2); redir { return } header(e, w, r, 2) defer footer(e, w, r) path := strings.Split(r.URL.Path, "/") subjID, err := strconv.Atoi(path[3]) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } subject := e.Subjects[subjID] class := path[4] if strings.HasPrefix(path[4], "All") { class = "" } f := getFilter(e, r) g, err := e.GroupByFilteredClass(path[3], class, f) if err != nil { fmt.Fprintf(w, "Error: %v", err) } data := struct { Query template.URL Year string Subject string Level string SubjID string Class string KS2Prior string Group group.Group ProgressGrid group.ProgressGrid }{ template.URL(r.URL.RawQuery), f.Year, subject.Subj, subject.Lvl, path[3], path[4], subject.KS2Prior, g, g.ProgressGrid(subject, f.NatYear), } err = e.Templates.ExecuteTemplate(w, "progressgrid.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } }
// AttendanceGroups produces a page with attendance summaries for the // various student groups. func AttendanceGroups(e env.Env) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 0); redir { return } header(e, w, r, 0) defer footer(e, w, r) f := getFilter(e, r) g, err := e.GroupByFilter(f) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } type YearGroup struct { Name string Query template.URL Groups []subGroup Matrix subGroupMatrix } // Ignore error - will appear as blank string anyway week, _ := e.CurrentWeek() data := struct { Week string Query template.URL YearGroups []YearGroup }{ week, template.URL(r.URL.RawQuery), []YearGroup{{"All Years", template.URL(""), subGroups(g), groupMatrix(g)}}, } for year := 7; year < 15; year++ { y := g.SubGroup(group.Year(year)) if len(y.Students) == 0 { continue } yeargroup := YearGroup{fmt.Sprintf("Year %v", year), template.URL(fmt.Sprintf("&year=%v", year)), subGroups(y), groupMatrix(y)} data.YearGroups = append(data.YearGroups, yeargroup) } err = e.Templates.ExecuteTemplate(w, "attendancegroups.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) } } }
// KS3Groups produces a group breakdown page for func KS3Groups(e env.Env) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 1); redir { return } header(e, w, r, 1) defer footer(e, w, r) f := getFilter(e, r) g, err := e.GroupByFilter(f) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } ks3Subjects := subject.List{} for _, s := range e.Subjects { if s.Lvl == "KS3" { ks3Subjects = append(ks3Subjects, *s) } } sort.Sort(ks3Subjects) data := struct { Query template.URL Year string Subjects subject.List Groups []subGroup Matrix subGroupMatrix }{ template.URL(r.URL.RawQuery), f.Year, ks3Subjects, subGroups(g), groupMatrix(g), } err = e.Templates.ExecuteTemplate(w, "ks3groups.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) } } }
// KS3Summary produces a page with the student func KS3Summary(e env.Env) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 2); redir { return } header(e, w, r, 2) defer footer(e, w, r) f := getFilter(e, r) g, err := e.GroupByFilter(f) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } ks3Subjects := subject.List{} var lvl subject.Level for _, s := range e.Subjects { if s.Lvl == "KS3" { lvl = s.Level ks3Subjects = append(ks3Subjects, *s) } } sort.Sort(ks3Subjects) data := struct { Query template.URL Subjects subject.List KS3 subject.Level Group group.Group }{ template.URL(r.URL.RawQuery), ks3Subjects, lvl, g, } err = e.Templates.ExecuteTemplate(w, "ks3summary.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) } } }
// FilterLabels generates the labels for the filter page func filterLabels(e env.Env, f database.Filter) []label { labels := []label{} // Lookup date and resultset names // Lookup date and resultset names date, _ := e.LookupDate(f.Date) rs, _ := e.LookupResultset(f.Resultset) nat, _ := e.LookupNatYear(f.NatYear) labels = append(labels, label{nat, "default"}) labels = append(labels, label{date, "primary"}) labels = append(labels, label{rs, "primary"}) if f.Year != "" { labels = append(labels, label{"Yeargroup: " + f.Year, "success"}) } switch f.Gender { case "1": labels = append(labels, label{"Boys", "warning"}) case "0": labels = append(labels, label{"Girls", "warning"}) } switch f.PP { case "1": labels = append(labels, label{"Disadvantaged", "warning"}) case "0": labels = append(labels, label{"Non-Disadvantaged", "warning"}) } switch f.EAL { case "1": labels = append(labels, label{"EAL", "warning"}) case "0": labels = append(labels, label{"Non-EAL", "warning"}) } if len(f.SEN) >= 1 && len(f.SEN) < 4 { labels = append(labels, label{"SEN: " + strings.Join(f.SEN, ", "), "warning"}) } if len(f.KS2Bands) >= 1 && len(f.SEN) < 4 { labels = append(labels, label{"KS2: " + strings.Join(f.KS2Bands, ", "), "warning"}) } if len(f.Ethnicities) >= 1 && len(f.Ethnicities) <= len(e.Ethnicities) { eths := []string{} for _, eth := range f.Ethnicities { if !e.OtherEths[eth] { eths = append(eths, eth) } } labels = append(labels, label{"Ethnicity: " + strings.Join(eths, ", "), "warning"}) } return labels }
func subjectBroadsheet(e env.Env, subj *subject.Subject, sheet *xlsx.Sheet, g group.Group) error { // Get a list of all resultsets for historical data resultsets := e.Resultsets // Create set of maps, keyed by resultsetID, then UPN historical := map[string](map[string]string){} for _, rs := range resultsets { historical[rs.ID] = map[string]string{} } // Load all historical data from the database for _, s := range g.Students { grds, err := e.HistoricalResults(s.UPN, subj.SubjID) switch err { case nil: for rs, grd := range grds { historical[rs][s.UPN] = grd } case sql.ErrNoRows: continue default: return err } } // Create set of empty resultsets empty := map[string]bool{} for rs, results := range historical { if len(results) == 0 { empty[rs] = true } } // Write headers to the sheet row := sheet.AddRow() row.SetHeightCM(4.5) newCell(row, "Name", newStyle("Bold", "None", "Bottom", "Left")) newCell(row, "Class", newStyle("Bold", "None", "Bottom", "Left")) headers := []string{"Gender", "PP", "KS2", "SEN", "Grade", "Effort", "VA", "Attendance"} for _, h := range headers { newCell(row, h, newStyle("Bold", "None", "Bottom", "Center")) } // Add historical resultsets to the headers for _, rs := range resultsets { if !empty[rs.ID] { newCell(row, rs.Name, newStyle("Bold", "None", "Bottom", "Vertical")) } } for _, h := range []string{"Barriers to Learning", "Intervention"} { newCell(row, h, newStyle("Bold", "None", "Bottom", "Center")) } // Add Student data for _, s := range g.Students { row := sheet.AddRow() newCell(row, s.Name(), newStyle("Default", "None", "None", "Left")) newCell(row, s.Class(subj.Subj), newStyle("Default", "None", "None", "Left")) newCell(row, s.Gender.String(), newStyle("Default", "None", "None", "Center")) newBool(row, s.PP, newStyle("Default", "None", "None", "Center")) newCell(row, s.KS2.Score(subj.KS2Prior), newStyle("Default", "None", "None", "Center")) newCell(row, s.SEN.Status, newStyle("Default", "None", "None", "Center")) newCell(row, s.SubjectGrade(subj.Subj), newStyle("Default", "None", "None", "Center")) newCell(row, s.SubjectEffort(subj.Subj), newStyle("Default", "None", "None", "Center")) newFloat(row, s.SubjectVA(subj.Subj).Score(), "+0.00;-0.00;0.00", newStyle("Default", "None", "None", "Center")) newFloat(row, s.Attendance.Latest(), "0.0%", newStyle("Default", "None", "None", "Center")) for _, rs := range resultsets { if !empty[rs.ID] { grd, _ := historical[rs.ID][s.UPN] newCell(row, grd, newStyle("Default", "None", "None", "Center")) } } } return nil }
// Progress8 returns a handler to produce the Progress 8 page. func Progress8(e env.Env) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if redir := checkRedirect(e, w, r, 2); redir { return } header(e, w, r, 2) defer footer(e, w, r) f := getFilter(e, r) g, err := e.GroupByFilter(f) if err != nil { fmt.Fprintf(w, "Error: %v", err) return } nat, exists := e.Attainment8[f.NatYear] if !exists { fmt.Fprintf(w, "Error: %v", err) } natLine := points{} for ks2, att8 := range nat { n, err := strconv.ParseFloat(ks2, 64) if err != nil { fmt.Fprintf(w, "Error: %v", err) } natLine = append(natLine, point{X: n, Y: att8.Overall}) } sort.Sort(natLine) pupilData := [4]points{} for _, s := range g.Students { p8 := s.Basket().Overall() var key int switch { case s.PP && s.Gender == 1: key = 0 case s.Gender == 1: key = 1 case s.PP && s.Gender == 0: key = 2 case s.Gender == 0: key = 3 } pupilData[key] = append(pupilData[key], point{X: s.KS2.APS / 6, Y: p8.Attainment, Name: s.Name(), P8: p8}) } data := struct { Query template.URL Group group.Group NatLine points PupilData [4]points }{ template.URL(r.URL.RawQuery), g, natLine, pupilData, } err = e.Templates.ExecuteTemplate(w, "progress8.tmpl", data) if err != nil { fmt.Fprintf(w, "Error: %v", err) } } }