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