From 766aedf22d4a156409f537bfd603cc10d67f455f Mon Sep 17 00:00:00 2001 From: Gonne Date: Mon, 29 Aug 2022 22:58:19 +0200 Subject: [PATCH] Datenbanken, erster Versuch --- .gitignore | 5 + controllers/handlers.go | 77 +++++++++++++ controllers/timetable.go | 137 +++++++++++++++++++++++ course.go | 15 --- dummydatasqlite.sql | 4 + main.go | 73 +++---------- models/course.go | 14 +++ date.go => models/date.go | 4 +- models/officeHour.go | 23 ++++ models/room.go | 14 +++ models/tutor.go | 15 +++ officeHour.go | 217 ------------------------------------- repositories/course.go | 67 ++++++++++++ repositories/officeHour.go | 95 ++++++++++++++++ repositories/room.go | 59 ++++++++++ repositories/tutor.go | 68 ++++++++++++ room.go | 20 ---- sqldb/sqldb.go | 17 +++ sqlite.sql | 62 +++++++++++ templates/index.html | 4 +- tutor.go | 8 -- 21 files changed, 678 insertions(+), 320 deletions(-) create mode 100644 controllers/handlers.go create mode 100644 controllers/timetable.go delete mode 100644 course.go create mode 100644 dummydatasqlite.sql create mode 100644 models/course.go rename date.go => models/date.go (57%) create mode 100644 models/officeHour.go create mode 100644 models/room.go create mode 100644 models/tutor.go delete mode 100644 officeHour.go create mode 100644 repositories/course.go create mode 100644 repositories/officeHour.go create mode 100644 repositories/room.go create mode 100644 repositories/tutor.go delete mode 100644 room.go create mode 100644 sqldb/sqldb.go create mode 100644 sqlite.sql delete mode 100644 tutor.go diff --git a/.gitignore b/.gitignore index 2ca337e..9589158 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ *.dylib sprechstundentool +#Databases +*.db + # Test binary, built with `go test -c` *.test @@ -17,3 +20,5 @@ vendor/ # Go workspace file go.work +go.mod +go.sum diff --git a/controllers/handlers.go b/controllers/handlers.go new file mode 100644 index 0000000..5e613c8 --- /dev/null +++ b/controllers/handlers.go @@ -0,0 +1,77 @@ +package controllers + +import ( + "fmt" + "html/template" + "net/http" + "sprechstundentool/models" + "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) { + b.writeTimetablePage(w, req, template.HTML("")) +} + +func (b *BaseHandler) GetByRoomHandler(w http.ResponseWriter, req *http.Request) { + roomId, _ := strconv.Atoi(req.FormValue("raum")) + room, err := b.roomRepo.FindById(roomId) + if err != nil { + fmt.Println(err) + b.RootHandler(w, req) + return + } + officeHours, _ := b.officeHourRepo.FindByRoom(room) + b.writeTimetablePage(w, req, printTimetable(GetTimetable(officeHours))) +} + +func (b *BaseHandler) GetByCourseHandler(w http.ResponseWriter, req *http.Request) { + courseid, err := strconv.Atoi(req.FormValue("veranstaltung")) + if err != nil { + b.RootHandler(w, req) + } + course, err := b.courseRepo.FindById(courseid) + if err != nil { + b.RootHandler(w, req) + return + } + officeHours, _ := b.officeHourRepo.FindByCourse(course) + b.writeTimetablePage(w, req, printTimetable(GetTimetable(officeHours))) +} + +func (b *BaseHandler) writeTimetablePage(w http.ResponseWriter, req *http.Request, timetable template.HTML) { + courses, _ := b.courseRepo.GetAll() + rooms, _ := b.roomRepo.GetAll() + selectedRoom, _ := strconv.Atoi(req.FormValue("raum")) + selectedCourse, _ := strconv.Atoi(req.FormValue("veranstaltung")) + data := struct { + Courses []models.Course + Rooms []models.Room + Timetable template.HTML + SelectedRoom int + SelectedCourse int + }{courses, rooms, timetable, selectedRoom, selectedCourse} + tmpl, err := template.ParseFiles("templates/index.html") + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error())))) + return + } + err = tmpl.Execute(w, data) + if err != nil { + w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error())))) + return + } +} diff --git a/controllers/timetable.go b/controllers/timetable.go new file mode 100644 index 0000000..5a8cb9a --- /dev/null +++ b/controllers/timetable.go @@ -0,0 +1,137 @@ +// timetable.go +package controllers + +import ( + "bytes" + "fmt" + "html/template" + "sprechstundentool/models" +) + +func GetTimetable(officeHours []models.OfficeHour) (timetable map[models.Date]map[int]models.OfficeHour, slots []int) { + var fullTimetable = make(map[models.Date]map[int]models.OfficeHour) + for _, officeHour := range officeHours { + var slot int = 0 + 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}] + if exists { + _, exists := fullTimetable[models.Date{officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}][slot] + if exists { + slot += 1 + minute = 0 + continue + } + } else { + fullTimetable[models.Date{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 + fullTimetable[models.Date{officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}][slot] = officeHour + } + } + slots = []int{1, 1, 1, 1, 1} + for date, _ := range fullTimetable { + if slots[date.Day] < len(fullTimetable[date]) { + slots[date.Day] = len(fullTimetable[date]) + } + } + timetable = make(map[models.Date]map[int]models.OfficeHour) + for _, officeHour := range officeHours { + for slot := 0; slot < slots[officeHour.Date.Day]; slot += 1 { + if fullTimetable[officeHour.Date][slot] == officeHour { + timetable[officeHour.Date] = make(map[int]models.OfficeHour) + timetable[officeHour.Date][slot] = officeHour + } + } + } + return fullTimetable, slots +} + +func printTimetable(timetable map[models.Date]map[int]models.OfficeHour, slots []int) template.HTML { + var tableBody string + + tableCell, _ := template.ParseFiles("templates/td.html") + for hour := 8; hour < 19; hour += 1 { + for minute := 0; minute < 60; minute += models.MinuteGranularity { + tableBody += "" + if minute == 0 { + tableBody += fmt.Sprintf("%d Uhr\n", hour) + } else { + tableBody += "\n" + } + for day := 0; day < 5; day += 1 { + for slot := 0; slot < slots[day]; slot += 1 { + current, currentExists := timetable[models.Date{day, hour, minute}][slot] + + 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 predecessorExists bool + var predecessor models.OfficeHour + if hour > 0 && minute < models.MinuteGranularity { + predecessor, predecessorExists = timetable[models.Date{day, hour - 1, 60 - models.MinuteGranularity}][slot] + } else { + predecessor, predecessorExists = timetable[models.Date{day, hour, minute - models.MinuteGranularity}][slot] + } + if predecessorExists { + continued = (predecessor == current) + } else { + continued = false + } + if continued { + continue + } else { + var celldata bytes.Buffer + data := struct { + Rowspan int + StartHour int + StartMinute int + EndHour int + EndMinute int + CourseName string + TutorName string + RoomName string + }{current.Duration / models.MinuteGranularity, + current.Hour, + current.Minute, + current.Hour + ((current.Minute + current.Duration) / 60), + (current.Minute + current.Duration) % 60, + template.HTMLEscapeString(current.Course.Name), + current.Tutor.Name, + current.Room.Name, + } + tableCell.Execute(&celldata, data) + tableBody += celldata.String() + } + } else { + if slot+1 == slots[day] { + tableBody += "\n" + } else { + tableBody += "\n" + } + } + } + } + tableBody += "\n" + } + } + var table bytes.Buffer + tableTemplate, _ := template.ParseFiles("templates/officeHourTable.html") + + tableData := struct { + ColspanMon int + ColspanTue int + ColspanWed int + ColspanThu int + ColspanFri int + TableBody template.HTML + }{ + slots[0], + slots[1], + slots[2], + slots[3], + slots[4], + template.HTML(tableBody), + } + tableTemplate.Execute(&table, tableData) + return template.HTML(table.String()) +} diff --git a/course.go b/course.go deleted file mode 100644 index b6dccbf..0000000 --- a/course.go +++ /dev/null @@ -1,15 +0,0 @@ -// course -package main - -type Course struct { - Id int - Name string - Active bool -} - -func getCourses() []Course { - return []Course{ - Course{1, "Dummyveranstaltung", true}, - Course{2, "Dummyveranstaltung 2", true}, - } -} diff --git a/dummydatasqlite.sql b/dummydatasqlite.sql new file mode 100644 index 0000000..802af70 --- /dev/null +++ b/dummydatasqlite.sql @@ -0,0 +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 `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 `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'); diff --git a/main.go b/main.go index d2b00e4..30c6721 100644 --- a/main.go +++ b/main.go @@ -1,68 +1,27 @@ package main import ( - "fmt" - "html/template" "net/http" - "strconv" + "sprechstundentool/controllers" + "sprechstundentool/repositories" + "sprechstundentool/sqldb" ) -func root(w http.ResponseWriter, req *http.Request) { - writeTimetablePage(w, req, template.HTML("")) -} - -func getByRoom(w http.ResponseWriter, req *http.Request) { - room, err := strconv.Atoi(req.FormValue("raum")) - if err != nil || room == 0 { - root(w, req) - return - } - writeTimetablePage(w, req, printTimetable(getTimetable(getOfficeHoursByRoom(room)))) -} - -func getByCourse(w http.ResponseWriter, req *http.Request) { - course, err := strconv.Atoi(req.FormValue("veranstaltung")) - if err != nil || course == 0 { - root(w, req) - return - } - writeTimetablePage(w, req, printTimetable(getTimetable(getOfficeHoursByCourse(course)))) -} - -func writeTimetablePage(w http.ResponseWriter, req *http.Request, timetable template.HTML) { - room, err := strconv.Atoi(req.FormValue("raum")) - if err != nil { - room = 0 - } - course, err := strconv.Atoi(req.FormValue("veranstaltung")) - if err != nil { - course = 0 - } - data := struct { - Courses []Course - Rooms []Room - Timetable template.HTML - SelectedRoom int - SelectedCourse int - }{getCourses(), getRooms(), timetable, room, course} - tmpl, err := template.ParseFiles("templates/index.html") - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error())))) - return - } - err = tmpl.Execute(w, data) - if err != nil { - w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error())))) - return - } -} - func main() { - http.HandleFunc("/getByRoom", getByRoom) - http.HandleFunc("/getByCourse", getByCourse) + db := sqldb.ConnectDB() - http.HandleFunc("/", root) + // Create repos + roomRepo := repositories.NewRoomRepo(db) + courseRepo := repositories.NewCourseRepo(db) + tutorRepo := repositories.NewTutorRepo(db) + officeHourRepo := repositories.NewOfficeHourRepo(db, roomRepo, tutorRepo, courseRepo) + + h := controllers.NewBaseHandler(roomRepo, officeHourRepo, courseRepo, tutorRepo) + + http.HandleFunc("/getByRoom", h.GetByRoomHandler) + http.HandleFunc("/getByCourse", h.GetByCourseHandler) + + http.HandleFunc("/", h.RootHandler) http.ListenAndServe(":8080", nil) } diff --git a/models/course.go b/models/course.go new file mode 100644 index 0000000..42d80b5 --- /dev/null +++ b/models/course.go @@ -0,0 +1,14 @@ +// course +package models + +type Course struct { + Id int + Name string +} + +type CourseRepository interface { + FindByName(name string) (Course, error) + GetAll() ([]Course, error) + FindById(id int) (Course, error) + GetActive() ([]Course, error) +} diff --git a/date.go b/models/date.go similarity index 57% rename from date.go rename to models/date.go index be16b80..1b71272 100644 --- a/date.go +++ b/models/date.go @@ -1,8 +1,10 @@ // date -package main +package models type Date struct { Day int Hour int Minute int } + +const MinuteGranularity int = 5 diff --git a/models/officeHour.go b/models/officeHour.go new file mode 100644 index 0000000..aadf0ce --- /dev/null +++ b/models/officeHour.go @@ -0,0 +1,23 @@ +// officeHour +package models + +type OfficeHour struct { + Id int + Tutor Tutor + Week int + Date + Room Room + Course Course + Info string + Active bool + Duration int +} + +type OfficeHourRepository interface { + FindById(id int) (OfficeHour, error) + FindByCourse(course Course) ([]OfficeHour, error) + FindByRoom(room Room) ([]OfficeHour, error) + GetAll() ([]OfficeHour, error) + Delete(officeHour OfficeHour) error + Add(officeHour OfficeHour) error +} diff --git a/models/room.go b/models/room.go new file mode 100644 index 0000000..5bc2b6c --- /dev/null +++ b/models/room.go @@ -0,0 +1,14 @@ +// raum +package models + +type Room struct { + Id int + Name string + MaxOccupy int +} + +type RoomRepository interface { + FindByName(name string) (Room, error) + GetAll() ([]Room, error) + FindById(id int) (Room, error) +} diff --git a/models/tutor.go b/models/tutor.go new file mode 100644 index 0000000..2a317cd --- /dev/null +++ b/models/tutor.go @@ -0,0 +1,15 @@ +// tutor +package models + +type Tutor struct { + Id int + Name string + Email string +} + +type TutorRepository interface { + FindByEmail(Email string) ([]Tutor, error) + FindById(Id int) (Tutor, error) + GetAll() ([]Tutor, error) + Add(tutor Tutor) error +} diff --git a/officeHour.go b/officeHour.go deleted file mode 100644 index 08425f1..0000000 --- a/officeHour.go +++ /dev/null @@ -1,217 +0,0 @@ -// officeHour -package main - -import ( - "bytes" - "fmt" - "html/template" -) - -const minuteGranularity int = 5 - -type OfficeHour struct { - Id int - Tutor Tutor - Week int - Date - Room Room - Course Course - Info string - Active bool - Duration int -} - -func getOfficeHours() []OfficeHour { - return []OfficeHour{ - OfficeHour{ - Id: 1, - Tutor: Tutor{1, "Dummy", "dummy@mathebau.de"}, - Week: 0, - Date: Date{ - Day: 0, - Hour: 12, - Minute: 0}, - Room: getRooms()[0], - Course: getCourses()[0], - Info: "", - Active: true, - Duration: 60}, - OfficeHour{ - Id: 2, - Tutor: Tutor{1, "Dummy", "dummy@mathebau.de"}, - Week: 0, - Date: Date{ - Day: 0, - Hour: 13, - Minute: 30}, - Room: getRooms()[0], - Course: getCourses()[1], - Info: "", - Active: true, - Duration: 90}, - OfficeHour{ - Id: 3, - Tutor: Tutor{1, "Dummy", "dummy@mathebau.de"}, - Week: 0, - Date: Date{Day: 0, - Hour: 12, - Minute: 45}, - Room: getRooms()[1], - Course: getCourses()[1], - Info: "", - Active: true, - Duration: 60}} - -} - -func getOfficeHoursByCourse(courseId int) []OfficeHour { - var result []OfficeHour - for _, option := range getOfficeHours() { - if option.Course.Id == courseId { - result = append(result, option) - } - } - return result -} - -func getOfficeHoursByRoom(roomId int) []OfficeHour { - var result []OfficeHour - for _, option := range getOfficeHours() { - if option.Room.Id == roomId { - result = append(result, option) - } - } - return result -} - -func getOfficeHourById(id int) OfficeHour { - return OfficeHour{} -} - -func getTimetable(officeHours []OfficeHour) (timetable map[Date]map[int]OfficeHour, slots []int) { - var fullTimetable = make(map[Date]map[int]OfficeHour) - for _, officeHour := range officeHours { - var slot int = 0 - for minute := 0; minute < officeHour.Duration; minute += minuteGranularity { // find slot id - _, exists := fullTimetable[Date{officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}] - if exists { - _, exists := fullTimetable[Date{officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}][slot] - if exists { - slot += 1 - minute = 0 - continue - } - } else { - fullTimetable[Date{officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}] = make(map[int]OfficeHour) - } - } - for minute := 0; minute < officeHour.Duration; minute += minuteGranularity { // write officeHour id to timetable - fullTimetable[Date{officeHour.Day, officeHour.Hour + (officeHour.Minute+minute)/60, (officeHour.Minute + minute) % 60}][slot] = officeHour - } - } - slots = []int{1, 1, 1, 1, 1} - for date, _ := range fullTimetable { - if slots[date.Day] < len(fullTimetable[date]) { - slots[date.Day] = len(fullTimetable[date]) - } - } - timetable = make(map[Date]map[int]OfficeHour) - for _, officeHour := range officeHours { - for slot := 0; slot < slots[officeHour.Date.Day]; slot += 1 { - if fullTimetable[officeHour.Date][slot] == officeHour { - timetable[officeHour.Date] = make(map[int]OfficeHour) - timetable[officeHour.Date][slot] = officeHour - } - } - } - return fullTimetable, slots -} - -func printTimetable(timetable map[Date]map[int]OfficeHour, slots []int) template.HTML { - var tableBody string - - tableCell, _ := template.ParseFiles("templates/td.html") - for hour := 8; hour < 19; hour += 1 { - for minute := 0; minute < 60; minute += minuteGranularity { - tableBody += "" - if minute == 0 { - tableBody += fmt.Sprintf("%d Uhr\n", hour) - } else { - tableBody += "\n" - } - for day := 0; day < 5; day += 1 { - for slot := 0; slot < slots[day]; slot += 1 { - current, currentExists := timetable[Date{day, hour, minute}][slot] - - 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 predecessorExists bool - var predecessor OfficeHour - if hour > 0 && minute < minuteGranularity { - predecessor, predecessorExists = timetable[Date{day, hour - 1, 60 - minuteGranularity}][slot] - } else { - predecessor, predecessorExists = timetable[Date{day, hour, minute - minuteGranularity}][slot] - } - if predecessorExists { - continued = (predecessor == current) - } else { - continued = false - } - if continued { - continue - } else { - var celldata bytes.Buffer - data := struct { - Rowspan int - StartHour int - StartMinute int - EndHour int - EndMinute int - CourseName string - TutorName string - RoomName string - }{current.Duration / minuteGranularity, - current.Hour, - current.Minute, - current.Hour + ((current.Minute + current.Duration) / 60), - (current.Minute + current.Duration) % 60, - template.HTMLEscapeString(current.Course.Name), - current.Tutor.Name, - current.Room.Name, - } - tableCell.Execute(&celldata, data) - tableBody += celldata.String() - } - } else { - if slot+1 == slots[day] { - tableBody += "\n" - } else { - tableBody += "\n" - } - } - } - } - tableBody += "\n" - } - } - var table bytes.Buffer - tableTemplate, _ := template.ParseFiles("templates/officeHourTable.html") - - tableData := struct { - ColspanMon int - ColspanTue int - ColspanWed int - ColspanThu int - ColspanFri int - TableBody template.HTML - }{ - slots[0], - slots[1], - slots[2], - slots[3], - slots[4], - template.HTML(tableBody), - } - tableTemplate.Execute(&table, tableData) - return template.HTML(table.String()) -} diff --git a/repositories/course.go b/repositories/course.go new file mode 100644 index 0000000..afc02f2 --- /dev/null +++ b/repositories/course.go @@ -0,0 +1,67 @@ +// course +package repositories + +import ( + "database/sql" + "sprechstundentool/models" +) + +type CourseRepo struct { + db *sql.DB +} + +func NewCourseRepo(db *sql.DB) *CourseRepo { + return &CourseRepo{ + db: db, + } +} + +func (r *CourseRepo) FindByName(name string) (models.Course, error) { + row := r.db.QueryRow("SELECT * FROM course WHERE name=?", name) + var course models.Course + if err := row.Scan(&course.Id, &course.Name); err != nil { + return models.Course{}, err + } + return course, nil +} + +func (r *CourseRepo) FindById(id int) (models.Course, error) { + row := r.db.QueryRow("SELECT * FROM course WHERE id=?", id) + var course models.Course + if err := row.Scan(&course.Id, &course.Name); err != nil { + return models.Course{}, err + } + return course, nil +} + +func (r *CourseRepo) GetAll() ([]models.Course, error) { + rows, err := r.db.Query("SELECT * FROM course") + if err != nil { + return nil, err + } + defer rows.Close() + + return r.getFromRows(rows) +} + +func (r *CourseRepo) GetActive() ([]models.Course, error) { + rows, err := r.db.Query("SELECT * FROM course WHERE active") + if err != nil { + return nil, err + } + defer rows.Close() + + return r.getFromRows(rows) +} + +func (r *CourseRepo) getFromRows(rows *sql.Rows) ([]models.Course, error) { + var courses []models.Course + for rows.Next() { + var course models.Course + if err := rows.Scan(&course.Id, &course.Name); err != nil { + return courses, err + } + courses = append(courses, course) + } + return courses, nil +} diff --git a/repositories/officeHour.go b/repositories/officeHour.go new file mode 100644 index 0000000..5e142d1 --- /dev/null +++ b/repositories/officeHour.go @@ -0,0 +1,95 @@ +// officeHour +package repositories + +import ( + "database/sql" + "sprechstundentool/models" +) + +type OfficeHourRepo struct { + db *sql.DB + roomRepo *RoomRepo + tutorRepo *TutorRepo + courseRepo *CourseRepo +} + +func NewOfficeHourRepo(db *sql.DB, roomRepo *RoomRepo, tutorRepo *TutorRepo, courseRepo *CourseRepo) *OfficeHourRepo { + return &OfficeHourRepo{ + db: db, + roomRepo: roomRepo, + tutorRepo: tutorRepo, + courseRepo: courseRepo, + } +} + +func (r *OfficeHourRepo) GetAll() ([]models.OfficeHour, error) { + rows, err := r.db.Query("SELECT * FROM officeHour") + if err != nil { + return nil, err + } + defer rows.Close() + return r.getFromRows(rows) +} + +func (r *OfficeHourRepo) FindByCourse(course models.Course) ([]models.OfficeHour, error) { + rows, err := r.db.Query("SELECT * FROM officeHour WHERE course=?", course.Id) + if err != nil { + return nil, err + } + defer rows.Close() + return r.getFromRows(rows) +} + +func (r *OfficeHourRepo) FindByRoom(room models.Room) ([]models.OfficeHour, error) { + rows, err := r.db.Query("SELECT * FROM officeHour WHERE room=?", room.Id) + if err != nil { + return nil, err + } + defer rows.Close() + return r.getFromRows(rows) +} + +func (r *OfficeHourRepo) FindById(id int) (models.OfficeHour, error) { + return r.getFromRow(r.db.QueryRow("SELECT * FROM officeHour WHERE id=?", id)) + +} + +func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) error { + return nil +} + +func (r *OfficeHourRepo) Delete(officeHour models.OfficeHour) error { + return nil +} + +func (r *OfficeHourRepo) getFromRow(row *sql.Row) (models.OfficeHour, error) { + var officeHour models.OfficeHour + var day, hour, minute, tutorid int + var roomName, courseName string + err := row.Scan(&officeHour.Id, &tutorid, &day, &hour, &minute, &roomName, &courseName, &officeHour.Week, &officeHour.Info, &officeHour.Active, &officeHour.Duration) + if err != nil { + return models.OfficeHour{}, err + } + officeHour.Date = models.Date{day, hour, minute} + officeHour.Room, _ = r.roomRepo.FindByName(roomName) + officeHour.Tutor, _ = r.tutorRepo.FindById(tutorid) + officeHour.Course, _ = r.courseRepo.FindByName(courseName) + return officeHour, nil +} + +func (r *OfficeHourRepo) getFromRows(rows *sql.Rows) ([]models.OfficeHour, error) { + var officeHours []models.OfficeHour + for rows.Next() { + var officeHour models.OfficeHour + var 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 { + return officeHours, err + } + officeHour.Date = models.Date{day, hour, minute} + officeHour.Room, _ = r.roomRepo.FindById(roomId) + officeHour.Tutor, _ = r.tutorRepo.FindById(tutorId) + officeHour.Course, _ = r.courseRepo.FindById(courseId) + officeHours = append(officeHours, officeHour) + } + return officeHours, nil +} diff --git a/repositories/room.go b/repositories/room.go new file mode 100644 index 0000000..63f434b --- /dev/null +++ b/repositories/room.go @@ -0,0 +1,59 @@ +// raum +package repositories + +import ( + "database/sql" + "sprechstundentool/models" +) + +type RoomRepo struct { + db *sql.DB +} + +func NewRoomRepo(db *sql.DB) *RoomRepo { + return &RoomRepo{ + db: db, + } +} + +func (r *RoomRepo) FindByName(name string) (models.Room, error) { + row := r.db.QueryRow("SELECT * FROM room WHERE name=?", name) + var room models.Room + if err := row.Scan(&room.Name, &room.MaxOccupy); err != nil { + return models.Room{}, err + } + return room, nil +} + +func (r *RoomRepo) FindById(id int) (models.Room, error) { + row := r.db.QueryRow("SELECT * FROM room WHERE id=?", id) + var room models.Room + if err := row.Scan(&room.Id, &room.Name, &room.MaxOccupy); err != nil { + return models.Room{}, err + } + return room, nil +} + +func (r *RoomRepo) GetAll() ([]models.Room, error) { + rows, err := r.db.Query("SELECT * FROM room") + if err != nil { + return nil, err + } + defer rows.Close() + + var rooms []models.Room + for rows.Next() { + var room models.Room + if err := rows.Scan(&room.Id, &room.Name, &room.MaxOccupy); err != nil { + return rooms, err + } + rooms = append(rooms, room) + } + return rooms, nil +} +func (r *RoomRepo) Save(room models.Room) error { + return nil +} +func (r *RoomRepo) Add(room models.Room) error { + return nil +} diff --git a/repositories/tutor.go b/repositories/tutor.go new file mode 100644 index 0000000..f78b702 --- /dev/null +++ b/repositories/tutor.go @@ -0,0 +1,68 @@ +// tutor +package repositories + +import ( + "database/sql" + "sprechstundentool/models" +) + +type TutorRepo struct { + db *sql.DB +} + +func NewTutorRepo(db *sql.DB) *TutorRepo { + return &TutorRepo{ + db: db, + } +} + +func (r *TutorRepo) FindByEmail(email string) ([]models.Tutor, error) { + rows, err := r.db.Query("SELECT * FROM tutor WHERE email=?", email) + if err != nil { + return nil, err + } + defer rows.Close() + + var tutors []models.Tutor + for rows.Next() { + var tutor models.Tutor + if err := rows.Scan(&tutor.Id, &tutor.Name, &tutor.Email); err != nil { + return tutors, err + } + tutors = append(tutors, tutor) + } + return tutors, nil +} + +func (r *TutorRepo) FindById(id int) (models.Tutor, error) { + row := r.db.QueryRow("SELECT * FROM tutor WHERE id=?", id) + 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) { + rows, err := r.db.Query("SELECT * FROM tutor") + if err != nil { + return nil, err + } + defer rows.Close() + + var tutors []models.Tutor + for rows.Next() { + var tutor models.Tutor + if err := rows.Scan(&tutor.Id, &tutor.Name, &tutor.Email); err != nil { + return tutors, err + } + tutors = append(tutors, tutor) + } + return tutors, nil +} +func (r *TutorRepo) Save(tutor models.Tutor) error { + return nil +} +func (r *TutorRepo) Add(tutor models.Tutor) error { + return nil +} diff --git a/room.go b/room.go deleted file mode 100644 index 1022fc4..0000000 --- a/room.go +++ /dev/null @@ -1,20 +0,0 @@ -// raum -package main - -type Room struct { - Id int - Name string - Max_occupy int - Active bool -} - -func getRooms() []Room { - return []Room{ - Room{1, "S2 15 345", 2, true}, - Room{2, "S2 15 415", 1, true}, - Room{3, "S2 15 336", 2, true}, - Room{4, "S2 15 444", 1, true}, - Room{5, "S2 15 333", 1, true}, - Room{6, "S2 14 420", 1, false}, - Room{7, "Sonstige", 255, true}} -} diff --git a/sqldb/sqldb.go b/sqldb/sqldb.go new file mode 100644 index 0000000..5596e81 --- /dev/null +++ b/sqldb/sqldb.go @@ -0,0 +1,17 @@ +package sqldb + +import ( + "database/sql" + + _ "github.com/mattn/go-sqlite3" +) + +// ConnectDB opens a connection to the database +func ConnectDB() *sql.DB { + db, err := sql.Open("sqlite3", "sprechstunden.db") + if err != nil { + panic(err.Error()) + } + + return db +} diff --git a/sqlite.sql b/sqlite.sql new file mode 100644 index 0000000..d4569e9 --- /dev/null +++ b/sqlite.sql @@ -0,0 +1,62 @@ +-- +-- Table structure for table `room` +-- + +DROP TABLE IF EXISTS `room`; +CREATE TABLE `room` ( + `id` INTEGER PRIMARY KEY, + `name` text NOT NULL, + `max_occupy` int DEFAULT NULL +); + +-- +-- Table structure for table `request` +-- + +DROP TABLE IF EXISTS `request`; +CREATE TABLE `request` ( + `id` INTEGER PRIMARY KEY, + `officeHour` int DEFAULT NULL, + `type` int DEFAULT NULL, + `code` text DEFAULT NULL +); + +-- +-- Table structure for table `officeHour` +-- + +DROP TABLE IF EXISTS `officeHour`; +CREATE TABLE `officeHour` ( + `id` INTEGER PRIMARY KEY, + `tutor` int DEFAULT NULL, + `day` int DEFAULT NULL, + `hour` int DEFAULT NULL, + `minute` int DEFAULT NULL, + `room` int DEFAULT NULL, + `course` int DEFAULT NULL, + `week` int DEFAULT NULL, + `info` text DEFAULT NULL, + `active` bool DEFAULT NULL, + `duration` int DEFAULT NULL +); + +-- +-- Table structure for table `tutor` +-- + +DROP TABLE IF EXISTS `tutor`; +CREATE TABLE `tutor` ( + `id` INTEGER PRIMARY KEY, + `name` tinytext DEFAULT NULL, + `email` tinytext DEFAULT NULL +); + +-- +-- Table structure for table `course` +-- + +DROP TABLE IF EXISTS `course`; +CREATE TABLE `course` ( + `id` INTEGER PRIMARY KEY, + `name` varchar(255) DEFAULT NULL +); diff --git a/templates/index.html b/templates/index.html index c02cd48..48344c7 100644 --- a/templates/index.html +++ b/templates/index.html @@ -6,7 +6,7 @@
@@ -15,7 +15,7 @@ diff --git a/tutor.go b/tutor.go deleted file mode 100644 index bbdf75b..0000000 --- a/tutor.go +++ /dev/null @@ -1,8 +0,0 @@ -// tutor -package main - -type Tutor struct { - Id int - Name string - Email string -}