Erster Commit
This commit is contained in:
commit
b26544756a
11 changed files with 405 additions and 0 deletions
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
sprechstundentool
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
vendor/
|
||||||
|
|
||||||
|
# Go workspace file
|
||||||
|
go.work
|
15
course.go
Normal file
15
course.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// 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},
|
||||||
|
}
|
||||||
|
}
|
8
date.go
Normal file
8
date.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// date
|
||||||
|
package main
|
||||||
|
|
||||||
|
type Date struct {
|
||||||
|
Day int
|
||||||
|
Hour int
|
||||||
|
Minute int
|
||||||
|
}
|
6
doc.go
Normal file
6
doc.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// sprechstundentool project doc.go
|
||||||
|
|
||||||
|
/*
|
||||||
|
sprechstundentool document
|
||||||
|
*/
|
||||||
|
package main
|
68
main.go
Normal file
68
main.go
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
http.HandleFunc("/", root)
|
||||||
|
|
||||||
|
http.ListenAndServe(":8080", nil)
|
||||||
|
}
|
217
officeHour.go
Normal file
217
officeHour.go
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
// 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 += "<tr>"
|
||||||
|
if minute == 0 {
|
||||||
|
tableBody += fmt.Sprintf("<td>%d Uhr</td>\n", hour)
|
||||||
|
} else {
|
||||||
|
tableBody += "<td></td>\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 += "<td style=\"border-right: 1px dotted\"></td>\n"
|
||||||
|
} else {
|
||||||
|
tableBody += "<td></td>\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tableBody += "</tr>\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())
|
||||||
|
}
|
20
room.go
Normal file
20
room.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// 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}}
|
||||||
|
}
|
27
templates/index.html
Normal file
27
templates/index.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Sprechstunden</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form method="GET" action="/getByCourse">
|
||||||
|
<label for="veranstaltung">Veranstaltung: </label>
|
||||||
|
<select name="veranstaltung" size="1" onchange="document.forms[0].submit()">
|
||||||
|
<option value="0">Alle</option>
|
||||||
|
{{range $course := .Courses}}
|
||||||
|
<option value="{{$course.Id}}"{{if eq $course.Id $.SelectedCourse}} selected{{end}}>{{$course.Name}}</option>{{end}}
|
||||||
|
</select>
|
||||||
|
<input type="submit" value="Auswählen" />
|
||||||
|
</form>
|
||||||
|
<form method="GET" action="/getByRoom">
|
||||||
|
<label for="raum">Raum: </label>
|
||||||
|
<select name="raum" size="1" onchange="document.forms[1].submit()">
|
||||||
|
<option value="0">Alle</option>
|
||||||
|
{{range $room := .Rooms}}
|
||||||
|
<option value="{{$room.Id}}"{{if eq $room.Id $.SelectedRoom}} selected{{end}}>{{$room.Name}}</option>{{end}}
|
||||||
|
</select>
|
||||||
|
<input type="submit" value="Auswählen" />
|
||||||
|
</form>
|
||||||
|
{{.Timetable}}
|
||||||
|
Technische Fragen an <a href="mailto:sprechstundentool@mathebau.de">sprechstundentool@mathebau.de</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
11
templates/officeHourTable.html
Normal file
11
templates/officeHourTable.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th> </th>
|
||||||
|
<th colspan="{{.ColspanMon}}" style="padding-left: 10px; padding-right: 10px; border-right: 1px dotted">Montag</th>
|
||||||
|
<th colspan="{{.ColspanTue}}" style="padding-left: 10px; padding-right: 10px; border-right: 1px dotted">Dienstag</th>
|
||||||
|
<th colspan="{{.ColspanWed}}" style="padding-left: 10px; padding-right: 10px; border-right: 1px dotted">Mittwoch</th>
|
||||||
|
<th colspan="{{.ColspanThu}}" style="padding-left: 10px; padding-right: 10px; border-right: 1px dotted">Donnerstag</th>
|
||||||
|
<th colspan="{{.ColspanFri}}" style="padding-left: 10px; padding-right: 10px; border-right: 1px dotted">Freitag</th>
|
||||||
|
</tr>
|
||||||
|
{{.TableBody}}
|
||||||
|
</table>
|
6
templates/td.html
Normal file
6
templates/td.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<td rowspan="{{.Rowspan}}" style="border: 1px solid">
|
||||||
|
{{.StartHour}}:{{printf "%02d" .StartMinute}} - {{.EndHour}}:{{printf "%02d" .EndMinute}}<br />
|
||||||
|
{{.CourseName}}<br />
|
||||||
|
{{.TutorName}}<br />
|
||||||
|
{{.RoomName}}
|
||||||
|
</td>
|
8
tutor.go
Normal file
8
tutor.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// tutor
|
||||||
|
package main
|
||||||
|
|
||||||
|
type Tutor struct {
|
||||||
|
Id int
|
||||||
|
Name string
|
||||||
|
Email string
|
||||||
|
}
|
Loading…
Reference in a new issue