package controllers import ( "fmt" "log" "net/http" "net/mail" "officeHours/config" "officeHours/models" "officeHours/templating" "strconv" "strings" ) type maskData struct { Courses []models.Course Rooms []models.Room MinuteGranularity int MaxDuration int EarliestStartTime struct { Hour int Minute int } LatestStartTime struct { Hour int Minute int } SelectedCourse int SelectedRoom int Date models.Date Duration int Roomname string Name string Email string Info string Errors []string Config config.Config } // Offer a form to add office hours and validate its input on receiving. func (b *BaseHandler) AddOfficeHourHandler(w http.ResponseWriter, req *http.Request) { SendSecurityHeaders(w, req) var errors []string courses, err := b.courseRepo.GetAll() if err != nil { errors = append(errors, err.Error()) } rooms, err := b.roomRepo.GetAll() if err != nil { errors = append(errors, err.Error()) } //Parse course courseid, err := strconv.Atoi(req.FormValue("veranstaltung")) if err != nil { errors = append(errors, "Die Veranstaltung muss eine ganze Zahl sein.") } course, err := b.courseRepo.FindById(courseid) if err != nil { errors = append(errors, "Die Veranstaltung muss existieren.") } //Parse room roomid, err := strconv.Atoi(req.FormValue("raum")) if err != nil { errors = append(errors, "Der Raum muss eine ganze Zahl sein.") } room, err := b.roomRepo.FindById(roomid) if err != nil { errors = append(errors, "Der Raum muss existieren.") } //Parse date week, err := strconv.Atoi(req.FormValue("woche")) if err != nil { errors = append(errors, "Die Vorlesungswoche muss eine ganze Zahl sein.") } if !(week >= 0 && week <= 2) { errors = append(errors, "Sprechstunden müssen jede, jede gerade oder jede ungerade Vorlesungswoche stattfinden.") } day, err := strconv.Atoi(req.FormValue("tag")) if err != nil { errors = append(errors, "Der Tag muss eine ganze Zahl sein.") } if !(day >= 0 && day <= 4) { errors = append(errors, "Sprechstunden müssen von Montag bis Freitag stattfinden.") } time := strings.SplitN(req.FormValue("startzeit"), ":", 2) var hour, minute int if len(time) != 2 { errors = append(errors, "Die Zeit muss im Format HH:MM sein.") } else { hour, err = strconv.Atoi(time[0]) if err != nil { errors = append(errors, "Die Stunde muss eine ganze Zahl sein.") } if !(hour > b.config.Date.EarliestStartTime.Hour || (hour == b.config.Date.EarliestStartTime.Hour && minute >= b.config.Date.EarliestStartTime.Minute)) { errors = append(errors, fmt.Sprintf("Sprechstunden müssen nach %02d:%02d Uhr starten.", b.config.Date.EarliestStartTime.Hour, b.config.Date.EarliestStartTime.Minute)) } if !(hour < b.config.Date.LatestStartTime.Hour || (hour == b.config.Date.LatestStartTime.Hour && minute <= b.config.Date.LatestStartTime.Minute)) { errors = append(errors, fmt.Sprintf("Sprechstunden müssen vor %02d:%02d Uhr starten.", b.config.Date.LatestStartTime.Hour, b.config.Date.LatestStartTime.Minute)) } minute, err = strconv.Atoi(time[1]) if err != nil { errors = append(errors, "Die Minute muss eine ganze Zahl sein.") } if !(minute >= 0 && minute <= 60-b.config.Date.MinuteGranularity && minute%b.config.Date.MinuteGranularity == 0) { errors = append(errors, fmt.Sprintf("Sprechstunden dürfen nur alle %d Minuten starten.", b.config.Date.MinuteGranularity)) } } date := models.Date{Week: week, Day: day, Hour: hour, Minute: minute} duration, err := strconv.Atoi(req.FormValue("dauer")) if err != nil { errors = append(errors, "Die Dauer muss eine ganze Zahl sein.") } if !(duration >= b.config.Date.MinuteGranularity && duration <= b.config.Date.MaxDuration && duration%b.config.Date.MinuteGranularity == 0) { errors = append(errors, fmt.Sprintf("Sprechstunden müssen zwischen %d und %d Minuten lang sein.", b.config.Date.MinuteGranularity, b.config.Date.MaxDuration)) } roomname := req.FormValue("raumname") if roomname != "" && room.Name != "Sonstige" { errors = append(errors, "Sonderraumnamen können nur für den Raum \"Sonstige\" angegeben werden.") } name := req.FormValue("name") if name == "" { errors = append(errors, "Der Name darf nicht leer sein.") } email, err := mail.ParseAddress(req.FormValue("email")) if err != nil { email = &mail.Address{Name: "", Address: req.FormValue("email")} errors = append(errors, "Mailaddresse konnte nicht geparst werden.") } else if !(b.config.Tutor.MailSuffix == "" || strings.HasSuffix(email.Address, "@"+b.config.Tutor.MailSuffix) || strings.HasSuffix(email.Address, "."+b.config.Tutor.MailSuffix)) { errors = append(errors, fmt.Sprintf("Mailaddresse muss auf „%s“ enden.", b.config.Tutor.MailSuffix)) } info := req.FormValue("info") allowed, err := b.officeHourRepo.AllowedAt(date, duration, room, true) if err != nil { errors = append(errors, fmt.Sprintf("Fehler beim Abfragen der Raumkapazität: %s", err.Error())) } else if !allowed { errors = append(errors, "In dem Raum muss noch Platz für weitere Sprechstunden sein.") } // If there were errors in the data for the new office hour, // answer with the form prefilled with the sent data. if len(errors) != 0 { var data maskData = maskData{ courses, rooms, b.config.Date.MinuteGranularity, b.config.Date.MaxDuration, b.config.Date.EarliestStartTime, b.config.Date.LatestStartTime, courseid, roomid, date, duration, roomname, name, email.Address, info, errors, b.config, } b.writeAddOfficeHourMask(w, req, data) } else { // if the data for a new office hour was sent correctly, save it. officeHour := models.OfficeHour{Id: 0, Tutor: models.Tutor{Id: 0, Name: name, Email: email.Address}, Date: date, Room: room, RoomName: roomname, Course: course, Info: info, Active: false, Duration: duration, } id, err := b.officeHourRepo.Add(officeHour) if err != nil { w.WriteHeader(http.StatusInternalServerError) templating.ServeTemplate(w, "addFailure", err) return } officeHour, err = b.officeHourRepo.FindById(id) if err != nil { log.Printf("Error finding new office hour by id %d: %s", id, err.Error()) } _, err = b.requestRepo.Add(officeHour, models.RequestActivate) if err != nil { log.Printf("Error adding request: %s", err.Error()) } templating.ServeTemplate(w, "addSuccess", nil) } } func (b *BaseHandler) writeAddOfficeHourMask(w http.ResponseWriter, req *http.Request, data maskData) { if req.Method == http.MethodGet { // if the current request is GET, we assume no office hour addition was tried so far and reset the errors. data.Errors = []string{} } if len(data.Errors) != 0 { w.WriteHeader(http.StatusBadRequest) } templating.ServeTemplate(w, "addMask", data) }