Erstelle Maske, um Sprechstunden hinzuzufügen
This commit is contained in:
parent
c7a9522c2c
commit
369f4ebcec
15 changed files with 357 additions and 50 deletions
174
controllers/addOfficeHourHandlers.go
Normal file
174
controllers/addOfficeHourHandlers.go
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
"net/mail"
|
||||||
|
"sprechstundentool/models"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type maskData struct {
|
||||||
|
Courses []models.Course
|
||||||
|
Rooms []models.Room
|
||||||
|
MinuteGranularity int
|
||||||
|
SelectedCourse int
|
||||||
|
SelectedRoom int
|
||||||
|
Week int
|
||||||
|
Day int
|
||||||
|
Hour int
|
||||||
|
Minute int
|
||||||
|
Duration int
|
||||||
|
Roomname string
|
||||||
|
Name string
|
||||||
|
Email string
|
||||||
|
Info string
|
||||||
|
Errors []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseHandler) AddOfficeHourHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
|
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 Woche muss eine ganze Zahl sein.")
|
||||||
|
}
|
||||||
|
if !(week >= 0 && week <= 2) {
|
||||||
|
errors = append(errors, "Sprechstunden müssen jede, jede gerade oder jede ungerade Woche 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 >= 8 && hour <= 17) {
|
||||||
|
errors = append(errors, fmt.Sprintf("Sprechstunden müssen zwischen 08:00 Uhr und 17:%d starten.", 60-models.MinuteGranularity))
|
||||||
|
}
|
||||||
|
minute, err = strconv.Atoi(time[1])
|
||||||
|
if err != nil {
|
||||||
|
errors = append(errors, "Die Minute muss eine ganze Zahl sein.")
|
||||||
|
}
|
||||||
|
if !(minute >= 0 && minute <= 60-models.MinuteGranularity && minute%models.MinuteGranularity == 0) {
|
||||||
|
errors = append(errors, fmt.Sprintf("Sprechstunden dürfen nur alle %d Minuten starten.", models.MinuteGranularity))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
duration, err := strconv.Atoi(req.FormValue("dauer"))
|
||||||
|
if err != nil {
|
||||||
|
errors = append(errors, "Die Dauer muss eine ganze Zahl sein.")
|
||||||
|
}
|
||||||
|
if !(duration >= models.MinuteGranularity && duration <= 120 && duration%models.MinuteGranularity == 0) {
|
||||||
|
errors = append(errors, fmt.Sprintf("Sprechstunden müssen zwischen %d und 120 Minuten lang sein.", models.MinuteGranularity))
|
||||||
|
}
|
||||||
|
|
||||||
|
roomname := req.FormValue("raumname")
|
||||||
|
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{"", req.FormValue("email")}
|
||||||
|
errors = append(errors, "Mailaddresse konnte nicht geparst werden.")
|
||||||
|
} else if !strings.HasSuffix(email.Address, "tu-darmstadt.de") {
|
||||||
|
errors = append(errors, "Mailaddresse muss auf „tu-darmstadt.de“ enden.")
|
||||||
|
}
|
||||||
|
info := req.FormValue("info")
|
||||||
|
|
||||||
|
if len(errors) != 0 {
|
||||||
|
var data maskData = maskData{
|
||||||
|
courses,
|
||||||
|
rooms,
|
||||||
|
models.MinuteGranularity,
|
||||||
|
courseid,
|
||||||
|
roomid,
|
||||||
|
week,
|
||||||
|
day,
|
||||||
|
hour,
|
||||||
|
minute,
|
||||||
|
duration,
|
||||||
|
roomname,
|
||||||
|
name,
|
||||||
|
email.Address,
|
||||||
|
info,
|
||||||
|
errors,
|
||||||
|
}
|
||||||
|
b.writeAddOfficeHourMask(w, req, data)
|
||||||
|
} else {
|
||||||
|
officeHour := models.OfficeHour{0,
|
||||||
|
models.Tutor{0, name, email.Address},
|
||||||
|
models.Date{week, day, hour, minute},
|
||||||
|
room,
|
||||||
|
course,
|
||||||
|
info,
|
||||||
|
false,
|
||||||
|
duration,
|
||||||
|
}
|
||||||
|
err := b.officeHourRepo.Add(officeHour)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
failureTemplate, parseErr := template.ParseFiles("templates/addFailure.html")
|
||||||
|
if parseErr != nil {
|
||||||
|
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error()))))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
failureTemplate.Execute(w, err)
|
||||||
|
}
|
||||||
|
http.Redirect(w, req, "/", http.StatusTemporaryRedirect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseHandler) writeAddOfficeHourMask(w http.ResponseWriter, req *http.Request, data maskData) {
|
||||||
|
tmpl, err := template.ParseFiles("templates/addMask.html")
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error()))))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(data.Errors) != 0 {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
err = tmpl.Execute(w, data)
|
||||||
|
if err != nil {
|
||||||
|
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error()))))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
16
controllers/baseHandler.go
Normal file
16
controllers/baseHandler.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import "sprechstundentool/models"
|
||||||
|
|
||||||
|
// BaseHandler will hold everything that controller needs
|
||||||
|
type BaseHandler struct {
|
||||||
|
roomRepo models.RoomRepository
|
||||||
|
officeHourRepo models.OfficeHourRepository
|
||||||
|
courseRepo models.CourseRepository
|
||||||
|
tutorRepo models.TutorRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBaseHandler returns a new BaseHandler
|
||||||
|
func NewBaseHandler(roomRepo models.RoomRepository, officeHourRepo models.OfficeHourRepository, courseRepo models.CourseRepository, tutorRepo models.TutorRepository) *BaseHandler {
|
||||||
|
return &BaseHandler{roomRepo, officeHourRepo, courseRepo, tutorRepo}
|
||||||
|
}
|
|
@ -8,19 +8,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BaseHandler will hold everything that controller needs
|
|
||||||
type BaseHandler struct {
|
|
||||||
roomRepo models.RoomRepository
|
|
||||||
officeHourRepo models.OfficeHourRepository
|
|
||||||
courseRepo models.CourseRepository
|
|
||||||
tutorRepo models.TutorRepository
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBaseHandler returns a new BaseHandler
|
|
||||||
func NewBaseHandler(roomRepo models.RoomRepository, officeHourRepo models.OfficeHourRepository, courseRepo models.CourseRepository, tutorRepo models.TutorRepository) *BaseHandler {
|
|
||||||
return &BaseHandler{roomRepo, officeHourRepo, courseRepo, tutorRepo}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BaseHandler) RootHandler(w http.ResponseWriter, req *http.Request) {
|
func (b *BaseHandler) RootHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
b.writeTimetablePage(w, req, template.HTML(""))
|
b.writeTimetablePage(w, req, template.HTML(""))
|
||||||
}
|
}
|
||||||
|
@ -33,7 +20,7 @@ func (b *BaseHandler) GetByRoomHandler(w http.ResponseWriter, req *http.Request)
|
||||||
b.RootHandler(w, req)
|
b.RootHandler(w, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
officeHours, _ := b.officeHourRepo.FindByRoom(room)
|
officeHours, _ := b.officeHourRepo.FindByRoom(room, true)
|
||||||
b.writeTimetablePage(w, req, printTimetable(GetTimetable(officeHours)))
|
b.writeTimetablePage(w, req, printTimetable(GetTimetable(officeHours)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +34,7 @@ func (b *BaseHandler) GetByCourseHandler(w http.ResponseWriter, req *http.Reques
|
||||||
b.RootHandler(w, req)
|
b.RootHandler(w, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
officeHours, _ := b.officeHourRepo.FindByCourse(course)
|
officeHours, _ := b.officeHourRepo.FindByCourse(course, true)
|
||||||
b.writeTimetablePage(w, req, printTimetable(GetTimetable(officeHours)))
|
b.writeTimetablePage(w, req, printTimetable(GetTimetable(officeHours)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,20 +13,20 @@ func GetTimetable(officeHours []models.OfficeHour) (timetable map[models.Date]ma
|
||||||
for _, officeHour := range officeHours {
|
for _, officeHour := range officeHours {
|
||||||
var slot int = 0
|
var slot int = 0
|
||||||
for minute := 0; minute < officeHour.Duration; minute += models.MinuteGranularity { // find slot id
|
for minute := 0; minute < officeHour.Duration; minute += models.MinuteGranularity { // find slot id
|
||||||
_, exists := fullTimetable[models.Date{officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}]
|
_, exists := fullTimetable[models.Date{0, officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}]
|
||||||
if exists {
|
if exists {
|
||||||
_, exists := fullTimetable[models.Date{officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}][slot]
|
_, exists := fullTimetable[models.Date{0, officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}][slot]
|
||||||
if exists {
|
if exists {
|
||||||
slot += 1
|
slot += 1
|
||||||
minute = 0
|
minute = 0
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fullTimetable[models.Date{officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}] = make(map[int]models.OfficeHour)
|
fullTimetable[models.Date{0, officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}] = make(map[int]models.OfficeHour)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for minute := 0; minute < officeHour.Duration; minute += models.MinuteGranularity { // write officeHour id to timetable
|
for minute := 0; minute < officeHour.Duration; minute += models.MinuteGranularity { // write officeHour id to timetable
|
||||||
fullTimetable[models.Date{officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}][slot] = officeHour
|
fullTimetable[models.Date{0, officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}][slot] = officeHour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
slots = []int{1, 1, 1, 1, 1}
|
slots = []int{1, 1, 1, 1, 1}
|
||||||
|
@ -61,16 +61,16 @@ func printTimetable(timetable map[models.Date]map[int]models.OfficeHour, slots [
|
||||||
}
|
}
|
||||||
for day := 0; day < 5; day += 1 {
|
for day := 0; day < 5; day += 1 {
|
||||||
for slot := 0; slot < slots[day]; slot += 1 {
|
for slot := 0; slot < slots[day]; slot += 1 {
|
||||||
current, currentExists := timetable[models.Date{day, hour, minute}][slot]
|
current, currentExists := timetable[models.Date{0, day, hour, minute}][slot]
|
||||||
|
|
||||||
if currentExists { // This slot is taken by some office hour
|
if currentExists { // This slot is taken by some office hour
|
||||||
var continued bool = false // is this slot occupied by the same office hour the previous minute?
|
var continued bool = false // is this slot occupied by the same office hour the previous minute?
|
||||||
var predecessorExists bool
|
var predecessorExists bool
|
||||||
var predecessor models.OfficeHour
|
var predecessor models.OfficeHour
|
||||||
if hour > 0 && minute < models.MinuteGranularity {
|
if hour > 0 && minute < models.MinuteGranularity {
|
||||||
predecessor, predecessorExists = timetable[models.Date{day, hour - 1, 60 - models.MinuteGranularity}][slot]
|
predecessor, predecessorExists = timetable[models.Date{0, day, hour - 1, 60 - models.MinuteGranularity}][slot]
|
||||||
} else {
|
} else {
|
||||||
predecessor, predecessorExists = timetable[models.Date{day, hour, minute - models.MinuteGranularity}][slot]
|
predecessor, predecessorExists = timetable[models.Date{0, day, hour, minute - models.MinuteGranularity}][slot]
|
||||||
}
|
}
|
||||||
if predecessorExists {
|
if predecessorExists {
|
||||||
continued = (predecessor == current)
|
continued = (predecessor == current)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
INSERT INTO `room` (name, max_occupy) VALUES ('S2 15 345',2),('S2 15 415',1),('S2 15 336',2),('S2 15 444',1),('S2 15 333',1),('S2 14 420',1),('Sonstige',1024);
|
INSERT INTO `room` (name, max_occupy) VALUES ('S2 15 345',2),('S2 15 415',1),('S2 15 336',2),('S2 15 444',1),('S2 15 333',1),('S2 14 420',1),('Sonstige',1024);
|
||||||
INSERT INTO `officeHour` VALUES (0,1,1,12,0,1,1,0,'',true,60),(1,1,1,12,15,2,1,0,'',true,60),(2,1,1,12,30,1,2,0,'',true,60);
|
INSERT INTO `officeHour` (tutor, day, hour, minute, room, course, week, info, active, duration) VALUES (1,1,12,0,1,1,0,'',true,60),(1,1,12,15,2,1,0,'',true,60),(1,1,12,30,1,2,0,'',true,60);
|
||||||
INSERT INTO `tutor` (name, email) VALUES ('Dummyname','dummy@example.com');
|
INSERT INTO `tutor` (name, email) VALUES ('Dummyname','dummy@example.com');
|
||||||
INSERT INTO `course` (name) VALUES ('Integrationstheorie'),('Analysis II (engl.)'),('Analysis II'),('Mathe II für Informatik'),('Mathe II für Bauwesen'),('Diskrete Optimierung'),('Lineare Algebra II'),('Einführung in die Algebra'),('FGdI I&II'),('Algorithmic Discrete Mathematics'),('Einführung in die Stochastik'),('Mathe II für ET'),('Mathe II für Maschinenbau'),('Mathe IV für Maschinenbau'),('Num Mathe für MB (IV)'),('Höhere Mathematik II'),('Elementare PDE'),('LA für Physik und Lehramt'),('Analysis I'),('Mathe III ET'),('Mathe I für Informatik'),('Complex Analysis'),('Mathe & Statistik für Biologen'),('Mathe I für Maschinenbau'),('Mathe I für Bau'),('Nichtlineare Optimierung'),('Einführung in die Numerische Mathematik'),('Differentialgeometrie'),('Mathe I für ET'),('Mathe III (Bau)'),('W. Theorie'),('Gewöhnliche Differentialgleichungen'),('Geometrie für Lehramt'),('Mathe III MB'),('Statistik I für Humanwissenschaftler'),('Einführung in die Optimierung'),('Algebra'),('Lineare Algebra I'),('Höhere Mathematik 1'),('Darstellende Geometrie'),('Statistik 1 für WI'),('Diskrete Mathematik'),('Linear Algebra I (engl.)'),('Introduction to mathematical logic'),('Statistik I für WI'),('Weihnachtsknobelstraße'),('Numerische Lineare Algebra'),('Mathe IV (ET) / Mathe III (Inf) / Praktische Mathe (MEd)'),('Topologie'),('Linear Algebra II (engl.)'),('Einführung in die Finanzmathematik'),('Einführung in die mathematische Software'),('Mathematische Statistik'),('Algebraische Kurven'),('Analysis I (engl.)'),('Funktionalanalysis'),('Lebensversicherungsmathematik'),('Automaten, Formale Sprachen und Entscheidbarkeit (FGdI)'),('Mathematik für Chemiker'),('Numerik gewöhnlicher Differentialgleichungen'),('Darstellungstheorie'),('Aussagen- und Prädikatenlogik'),('Riemannsche Flächen'),('Mathematische Grundlagen der Quantenmechanik'),('Elementare Zahlentheorie'),('Einführung in die mathematische Modellierung'),('Stochastische Prozesse I'),('Mathematik im Kontext'),('Funktionalanalysis II'),('Mathematik IV (für ET) /Mathematik III (für Inf) /PraktischeMathematik (für M.Ed.Math)'),('Differentialgeometrie fuer VI'),('Probability Theory'),('Mathe für MINT'),('Mathematik als gemeinsame Sprache der Naturwissenschaften'),('Lineare Algebra I für Physiker'),('Manifolds'),('Kurvenschätzung'),('Spieltheorie'),('Einführung in die Programmierung'),('Algebraische Topologie'),('Schadenversicherungsmathematik'),('Partial Differential Equations I');
|
INSERT INTO `course` (name) VALUES ('Integrationstheorie'),('Analysis II (engl.)'),('Analysis II'),('Mathe II für Informatik'),('Mathe II für Bauwesen'),('Diskrete Optimierung'),('Lineare Algebra II'),('Einführung in die Algebra'),('FGdI I&II'),('Algorithmic Discrete Mathematics'),('Einführung in die Stochastik'),('Mathe II für ET'),('Mathe II für Maschinenbau'),('Mathe IV für Maschinenbau'),('Num Mathe für MB (IV)'),('Höhere Mathematik II'),('Elementare PDE'),('LA für Physik und Lehramt'),('Analysis I'),('Mathe III ET'),('Mathe I für Informatik'),('Complex Analysis'),('Mathe & Statistik für Biologen'),('Mathe I für Maschinenbau'),('Mathe I für Bau'),('Nichtlineare Optimierung'),('Einführung in die Numerische Mathematik'),('Differentialgeometrie'),('Mathe I für ET'),('Mathe III (Bau)'),('W. Theorie'),('Gewöhnliche Differentialgleichungen'),('Geometrie für Lehramt'),('Mathe III MB'),('Statistik I für Humanwissenschaftler'),('Einführung in die Optimierung'),('Algebra'),('Lineare Algebra I'),('Höhere Mathematik 1'),('Darstellende Geometrie'),('Statistik 1 für WI'),('Diskrete Mathematik'),('Linear Algebra I (engl.)'),('Introduction to mathematical logic'),('Statistik I für WI'),('Weihnachtsknobelstraße'),('Numerische Lineare Algebra'),('Mathe IV (ET) / Mathe III (Inf) / Praktische Mathe (MEd)'),('Topologie'),('Linear Algebra II (engl.)'),('Einführung in die Finanzmathematik'),('Einführung in die mathematische Software'),('Mathematische Statistik'),('Algebraische Kurven'),('Analysis I (engl.)'),('Funktionalanalysis'),('Lebensversicherungsmathematik'),('Automaten, Formale Sprachen und Entscheidbarkeit (FGdI)'),('Mathematik für Chemiker'),('Numerik gewöhnlicher Differentialgleichungen'),('Darstellungstheorie'),('Aussagen- und Prädikatenlogik'),('Riemannsche Flächen'),('Mathematische Grundlagen der Quantenmechanik'),('Elementare Zahlentheorie'),('Einführung in die mathematische Modellierung'),('Stochastische Prozesse I'),('Mathematik im Kontext'),('Funktionalanalysis II'),('Mathematik IV (für ET) /Mathematik III (für Inf) /PraktischeMathematik (für M.Ed.Math)'),('Differentialgeometrie fuer VI'),('Probability Theory'),('Mathe für MINT'),('Mathematik als gemeinsame Sprache der Naturwissenschaften'),('Lineare Algebra I für Physiker'),('Manifolds'),('Kurvenschätzung'),('Spieltheorie'),('Einführung in die Programmierung'),('Algebraische Topologie'),('Schadenversicherungsmathematik'),('Partial Differential Equations I');
|
||||||
|
|
2
main.go
2
main.go
|
@ -20,7 +20,7 @@ func main() {
|
||||||
|
|
||||||
http.HandleFunc("/getByRoom", h.GetByRoomHandler)
|
http.HandleFunc("/getByRoom", h.GetByRoomHandler)
|
||||||
http.HandleFunc("/getByCourse", h.GetByCourseHandler)
|
http.HandleFunc("/getByCourse", h.GetByCourseHandler)
|
||||||
|
http.HandleFunc("/addOfficeHour", h.AddOfficeHourHandler)
|
||||||
http.HandleFunc("/", h.RootHandler)
|
http.HandleFunc("/", h.RootHandler)
|
||||||
|
|
||||||
http.ListenAndServe(":8080", nil)
|
http.ListenAndServe(":8080", nil)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
type Date struct {
|
type Date struct {
|
||||||
|
Week int
|
||||||
Day int
|
Day int
|
||||||
Hour int
|
Hour int
|
||||||
Minute int
|
Minute int
|
||||||
|
|
|
@ -4,7 +4,6 @@ package models
|
||||||
type OfficeHour struct {
|
type OfficeHour struct {
|
||||||
Id int
|
Id int
|
||||||
Tutor Tutor
|
Tutor Tutor
|
||||||
Week int
|
|
||||||
Date
|
Date
|
||||||
Room Room
|
Room Room
|
||||||
Course Course
|
Course Course
|
||||||
|
@ -15,9 +14,9 @@ type OfficeHour struct {
|
||||||
|
|
||||||
type OfficeHourRepository interface {
|
type OfficeHourRepository interface {
|
||||||
FindById(id int) (OfficeHour, error)
|
FindById(id int) (OfficeHour, error)
|
||||||
FindByCourse(course Course) ([]OfficeHour, error)
|
FindByCourse(course Course, activeOnly bool) ([]OfficeHour, error)
|
||||||
FindByRoom(room Room) ([]OfficeHour, error)
|
FindByRoom(room Room, activatedOnly bool) ([]OfficeHour, error)
|
||||||
GetAll() ([]OfficeHour, error)
|
GetAll(activatedOnly bool) ([]OfficeHour, error)
|
||||||
Delete(officeHour OfficeHour) error
|
Delete(officeHour OfficeHour) error
|
||||||
Add(officeHour OfficeHour) error
|
Add(officeHour OfficeHour) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ type Tutor struct {
|
||||||
|
|
||||||
type TutorRepository interface {
|
type TutorRepository interface {
|
||||||
FindByEmail(Email string) ([]Tutor, error)
|
FindByEmail(Email string) ([]Tutor, error)
|
||||||
|
FindByNameAndEmail(name string, email string) (Tutor, error)
|
||||||
FindById(Id int) (Tutor, error)
|
FindById(Id int) (Tutor, error)
|
||||||
GetAll() ([]Tutor, error)
|
GetAll() ([]Tutor, error)
|
||||||
Add(tutor Tutor) error
|
Add(tutor Tutor) error
|
||||||
|
|
|
@ -22,8 +22,14 @@ func NewOfficeHourRepo(db *sql.DB, roomRepo *RoomRepo, tutorRepo *TutorRepo, cou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OfficeHourRepo) GetAll() ([]models.OfficeHour, error) {
|
func (r *OfficeHourRepo) GetAll(activeOnly bool) ([]models.OfficeHour, error) {
|
||||||
rows, err := r.db.Query("SELECT * FROM officeHour")
|
var rows *sql.Rows
|
||||||
|
var err error
|
||||||
|
if activeOnly {
|
||||||
|
rows, err = r.db.Query("SELECT * FROM officeHour WHERE active")
|
||||||
|
} else {
|
||||||
|
rows, err = r.db.Query("SELECT * FROM officeHour")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -31,8 +37,14 @@ func (r *OfficeHourRepo) GetAll() ([]models.OfficeHour, error) {
|
||||||
return r.getFromRows(rows)
|
return r.getFromRows(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OfficeHourRepo) FindByCourse(course models.Course) ([]models.OfficeHour, error) {
|
func (r *OfficeHourRepo) FindByCourse(course models.Course, activeOnly bool) ([]models.OfficeHour, error) {
|
||||||
rows, err := r.db.Query("SELECT * FROM officeHour WHERE course=?", course.Id)
|
var rows *sql.Rows
|
||||||
|
var err error
|
||||||
|
if activeOnly {
|
||||||
|
rows, err = r.db.Query("SELECT * FROM officeHour WHERE course=? and active", course.Id)
|
||||||
|
} else {
|
||||||
|
rows, err = r.db.Query("SELECT * FROM officeHour WHERE course=?", course.Id)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -40,8 +52,14 @@ func (r *OfficeHourRepo) FindByCourse(course models.Course) ([]models.OfficeHour
|
||||||
return r.getFromRows(rows)
|
return r.getFromRows(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OfficeHourRepo) FindByRoom(room models.Room) ([]models.OfficeHour, error) {
|
func (r *OfficeHourRepo) FindByRoom(room models.Room, activeOnly bool) ([]models.OfficeHour, error) {
|
||||||
rows, err := r.db.Query("SELECT * FROM officeHour WHERE room=?", room.Id)
|
var rows *sql.Rows
|
||||||
|
var err error
|
||||||
|
if activeOnly {
|
||||||
|
rows, err = r.db.Query("SELECT * FROM officeHour WHERE room=? AND active", room.Id)
|
||||||
|
} else {
|
||||||
|
rows, err = r.db.Query("SELECT * FROM officeHour WHERE room=?", room.Id)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -55,8 +73,44 @@ func (r *OfficeHourRepo) FindById(id int) (models.OfficeHour, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) error {
|
func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) error {
|
||||||
|
// Find correct tutor or add if not existent
|
||||||
|
r.tutorRepo.Add(officeHour.Tutor)
|
||||||
|
var err error
|
||||||
|
officeHour.Tutor, err = r.tutorRepo.FindByNameAndEmail(officeHour.Tutor.Name, officeHour.Tutor.Email)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Don't add identical officeHours
|
||||||
|
officeHours, err := r.FindByCourse(officeHour.Course, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, oldOfficeHour := range officeHours {
|
||||||
|
if officeHour.Tutor == oldOfficeHour.Tutor &&
|
||||||
|
officeHour.Date == oldOfficeHour.Date &&
|
||||||
|
officeHour.Room == oldOfficeHour.Room &&
|
||||||
|
// officeHour.Course == oldOfficeHour.Course && already filtered above
|
||||||
|
officeHour.Info == oldOfficeHour.Info &&
|
||||||
|
officeHour.Active == oldOfficeHour.Active &&
|
||||||
|
officeHour.Duration == oldOfficeHour.Duration {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.Exec("INSERT INTO `officeHour` (tutor, day, hour, minute, room, course, week, info, active, duration) VALUES (?,?,?,?,?,?,?,?,?,?)",
|
||||||
|
officeHour.Tutor.Id,
|
||||||
|
officeHour.Date.Day,
|
||||||
|
officeHour.Date.Hour,
|
||||||
|
officeHour.Date.Minute,
|
||||||
|
officeHour.Room.Id,
|
||||||
|
officeHour.Course.Id,
|
||||||
|
officeHour.Date.Week,
|
||||||
|
officeHour.Info,
|
||||||
|
officeHour.Active,
|
||||||
|
officeHour.Duration)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (r *OfficeHourRepo) Delete(officeHour models.OfficeHour) error {
|
func (r *OfficeHourRepo) Delete(officeHour models.OfficeHour) error {
|
||||||
return nil
|
return nil
|
||||||
|
@ -64,13 +118,13 @@ func (r *OfficeHourRepo) Delete(officeHour models.OfficeHour) error {
|
||||||
|
|
||||||
func (r *OfficeHourRepo) getFromRow(row *sql.Row) (models.OfficeHour, error) {
|
func (r *OfficeHourRepo) getFromRow(row *sql.Row) (models.OfficeHour, error) {
|
||||||
var officeHour models.OfficeHour
|
var officeHour models.OfficeHour
|
||||||
var day, hour, minute, tutorid int
|
var week, day, hour, minute, tutorid int
|
||||||
var roomName, courseName string
|
var roomName, courseName string
|
||||||
err := row.Scan(&officeHour.Id, &tutorid, &day, &hour, &minute, &roomName, &courseName, &officeHour.Week, &officeHour.Info, &officeHour.Active, &officeHour.Duration)
|
err := row.Scan(&officeHour.Id, &tutorid, &day, &hour, &minute, &roomName, &courseName, &week, &officeHour.Info, &officeHour.Active, &officeHour.Duration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return models.OfficeHour{}, err
|
return models.OfficeHour{}, err
|
||||||
}
|
}
|
||||||
officeHour.Date = models.Date{day, hour, minute}
|
officeHour.Date = models.Date{week, day, hour, minute}
|
||||||
officeHour.Room, _ = r.roomRepo.FindByName(roomName)
|
officeHour.Room, _ = r.roomRepo.FindByName(roomName)
|
||||||
officeHour.Tutor, _ = r.tutorRepo.FindById(tutorid)
|
officeHour.Tutor, _ = r.tutorRepo.FindById(tutorid)
|
||||||
officeHour.Course, _ = r.courseRepo.FindByName(courseName)
|
officeHour.Course, _ = r.courseRepo.FindByName(courseName)
|
||||||
|
@ -81,11 +135,11 @@ func (r *OfficeHourRepo) getFromRows(rows *sql.Rows) ([]models.OfficeHour, error
|
||||||
var officeHours []models.OfficeHour
|
var officeHours []models.OfficeHour
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var officeHour models.OfficeHour
|
var officeHour models.OfficeHour
|
||||||
var day, hour, minute, tutorId, roomId, courseId int
|
var week, day, hour, minute, tutorId, roomId, courseId int
|
||||||
if err := rows.Scan(&officeHour.Id, &tutorId, &day, &hour, &minute, &roomId, &courseId, &officeHour.Week, &officeHour.Info, &officeHour.Active, &officeHour.Duration); err != nil {
|
if err := rows.Scan(&officeHour.Id, &tutorId, &day, &hour, &minute, &roomId, &courseId, &week, &officeHour.Info, &officeHour.Active, &officeHour.Duration); err != nil {
|
||||||
return officeHours, err
|
return officeHours, err
|
||||||
}
|
}
|
||||||
officeHour.Date = models.Date{day, hour, minute}
|
officeHour.Date = models.Date{week, day, hour, minute}
|
||||||
officeHour.Room, _ = r.roomRepo.FindById(roomId)
|
officeHour.Room, _ = r.roomRepo.FindById(roomId)
|
||||||
officeHour.Tutor, _ = r.tutorRepo.FindById(tutorId)
|
officeHour.Tutor, _ = r.tutorRepo.FindById(tutorId)
|
||||||
officeHour.Course, _ = r.courseRepo.FindById(courseId)
|
officeHour.Course, _ = r.courseRepo.FindById(courseId)
|
||||||
|
|
|
@ -43,6 +43,15 @@ func (r *TutorRepo) FindById(id int) (models.Tutor, error) {
|
||||||
return tutor, nil
|
return tutor, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *TutorRepo) FindByNameAndEmail(name string, email string) (models.Tutor, error) {
|
||||||
|
row := r.db.QueryRow("SELECT * FROM tutor WHERE email=? AND name=?", email, name)
|
||||||
|
var tutor models.Tutor
|
||||||
|
if err := row.Scan(&tutor.Id, &tutor.Name, &tutor.Email); err != nil {
|
||||||
|
return models.Tutor{}, err
|
||||||
|
}
|
||||||
|
return tutor, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *TutorRepo) GetAll() ([]models.Tutor, error) {
|
func (r *TutorRepo) GetAll() ([]models.Tutor, error) {
|
||||||
rows, err := r.db.Query("SELECT * FROM tutor")
|
rows, err := r.db.Query("SELECT * FROM tutor")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -64,5 +73,12 @@ func (r *TutorRepo) Save(tutor models.Tutor) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (r *TutorRepo) Add(tutor models.Tutor) error {
|
func (r *TutorRepo) Add(tutor models.Tutor) error {
|
||||||
return nil
|
//Don't add identical tutors
|
||||||
|
_, err := r.FindByNameAndEmail(tutor.Name, tutor.Email)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
_, err = r.db.Exec("INSERT INTO `tutor` (name, email) VALUES (?,?);", tutor.Name, tutor.Email)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
10
templates/addFailure.html
Normal file
10
templates/addFailure.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Sprechstunde anlegen</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Irgendetwas ist schief gegangen. Bitte sende folgende Daten an <a href="mailto:sprechstundentool@mathebau.de">sprechstundentool@mathebau.de</a> mit einer Beschreibung, was du tun wolltest.
|
||||||
|
<br />
|
||||||
|
{{.}}
|
||||||
|
</body>
|
||||||
|
</html>
|
49
templates/addMask.html
Normal file
49
templates/addMask.html
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Sprechstunde anlegen</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
{{range .Errors}}{{.}}<br />{{end}}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<form method="POST" action="addOfficeHour">
|
||||||
|
<label for="veranstaltung">Veranstaltung</label>:
|
||||||
|
<select name="veranstaltung">{{range $course := .Courses}}
|
||||||
|
<option value="{{$course.Id}}"{{if eq $course.Id $.SelectedCourse}} selected{{end}}>{{$course.Name}}</option>{{end}}
|
||||||
|
</select><br />
|
||||||
|
<label for="woche">Woche</label>:
|
||||||
|
<select name="woche">
|
||||||
|
<option value="0"{{if eq 0 $.Week}} selected{{end}}>Jede</option>
|
||||||
|
<option value="1"{{if eq 1 $.Week}} selected{{end}}>Gerade</option>
|
||||||
|
<option value="2"{{if eq 2 $.Week}} selected{{end}}>Ungerade</option>
|
||||||
|
</select><br />
|
||||||
|
<label for="tag">Tag</label>: <select name="tag">
|
||||||
|
<option value="0"{{if eq 0 $.Day}} selected{{end}}>Montag</option>
|
||||||
|
<option value="1"{{if eq 1 $.Day}} selected{{end}}>Dienstag</option>
|
||||||
|
<option value="2"{{if eq 2 $.Day}} selected{{end}}>Mittwoch</option>
|
||||||
|
<option value="3"{{if eq 3 $.Day}} selected{{end}}>Donnerstag</option>
|
||||||
|
<option value="4"{{if eq 4 $.Day}} selected{{end}}>Freitag</option>
|
||||||
|
</select><br />
|
||||||
|
<label for="startzeit">Startzeit</label>: <input type="time" name="startzeit" min="08:00" max="17:30" /><br />
|
||||||
|
<label for="dauer">Dauer in Minuten</label>: <input name="dauer" type="number" min="{{.MinuteGranularity}}" max="120" step="{{.MinuteGranularity}}" value="{{.Duration}}"/><br />
|
||||||
|
<label for="raum">Raum</label>:
|
||||||
|
<select name="raum">{{range $room := .Rooms}}
|
||||||
|
<option value="{{$room.Id}}"{{if eq $room.Id $.SelectedRoom}} selected{{end}}>{{$room.Name}}</option>{{end}}
|
||||||
|
</select><br />
|
||||||
|
<label for="raumname">Raumname (für Sonderräume)</label>: <input type="text" name="raumname" value="{{.Roomname}}"/><br />
|
||||||
|
<label for="name">Name</label>: <input name="name" type="text" size="50" value="{{.Name}}"/><br />
|
||||||
|
<label for="email">Email-Adresse</label>:
|
||||||
|
<input name="email" type="email" size="50" value="{{.Email}}"/><br />
|
||||||
|
<label for="info">Info</label>: <input name="info" type="text" size="50" value="{{.Info}}"/><br />
|
||||||
|
<input type="submit">
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
Du musst hier eine Email-Adresse angeben, die auf „tu-darmstadt.de“ endet.<br />
|
||||||
|
Außerdem dürfen in Räumen nur begrenzt viele Sprechstunden gleichzeitig stattfinden, nämlich
|
||||||
|
<dl>
|
||||||
|
{{range $room := .Rooms}}
|
||||||
|
<dt>{{$room.Name}}</dt><dl>{{$room.MaxOccupy}} Sprechstunde{{if gt $room.MaxOccupy 1}}n{{end}}</dl><br />{{end}}
|
||||||
|
</dl>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue