hivedav

A curlable free/busy scheduler with CalDAV integration
git clone https://git.in0rdr.ch/hivedav.git
Log | Files | Refs | Pull requests |Archive | README | LICENSE

commit a5bd60f719958c77bb7f9338c926574ce9f1a1fc
parent 95621588a755c1c2a0318d1bf7c3ca8267d766e7
Author: Andreas Gruhler <andreas.gruhler@adfinis.com>
Date:   Sat, 30 Sep 2023 15:21:49 +0200

feat: add html CubicleForm

Diffstat:
Mcss/style.css | 27+++++++++++++++++++++++++++
Mmain.go | 1+
Mserver.go | 46++++++++++++++++++++++++++++++++++++++++++++++
Atemplates/cubicleform.html | 24++++++++++++++++++++++++
Mtemplates/index.html | 24++++++++++++++----------
5 files changed, 112 insertions(+), 10 deletions(-)

diff --git a/css/style.css b/css/style.css @@ -25,3 +25,30 @@ footer { padding: 5px; flex-wrap: wrap; } + +.calendar a { + text-decoration: none; +} +.calendar .free, .calendar .busy { + font-size: 200%; +} +.calendar .free { + color: #F4900C; +} +.calendar .busy { + color: #b0b0b6; +} + +.cubicleform { + max-width: 500px; + padding: 30px; +} +.cubicleform input, .cubicleform textarea { + display: block; + padding: 5px; + margin: 20px; +} +.cubicleform textarea { + height: 200px; + width: 100%; +} diff --git a/main.go b/main.go @@ -44,6 +44,7 @@ func main() { router.GET("/list", server.ListCubicles) router.GET("/list/:week", server.ListCubiclesInWeek) router.POST("/book/:dtstart", server.BookCubicle) + router.GET("/book/:dtstart", server.CubicleForm) router.ServeFiles("/css/*filepath", http.Dir("./css")) router.GET("/healthz", server.Healthz) log.Printf("Listening:\t\t%s:%d\n", conf.ListenAddress, conf.ListenPort) diff --git a/server.go b/server.go @@ -42,6 +42,12 @@ type TableData struct { HiveDavHost string } +type CubicleFormData struct { + Dtstart string + DtstartInput string + Version string +} + type IcsData struct { Timestamp string Prodid string @@ -169,6 +175,14 @@ func (s *Server) available(start string, end string) (bool, error) { var funcMap = template.FuncMap{ "next": func(i int) int { return i + 1 }, "prev": func(i int) int { return i - 1 }, + "mkSlice": func(a int, b int) []int { + // return slice of integers from a to b + var r []int + for i := a; i <= b; i++ { + r = append(r, i) + } + return r + }, } func (s *Server) Week(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { @@ -605,6 +619,38 @@ func (s *Server) ListCubiclesInWeek(w http.ResponseWriter, req *http.Request, ps } } +func (s *Server) CubicleForm(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + dtstart := ps.ByName("dtstart") + dtStartTimeLocal, err := time.ParseInLocation("2006-01-02-15", dtstart, time.Local) + + if err != nil { + log.Printf("Error parsing booking dtstart: %v\n", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + icsData := CubicleFormData{ + DtstartInput: dtStartTimeLocal.Format("2006-01-02T15:04"), + Dtstart: dtstart, + Version: hivedavVersion, + } + + w.Header().Set("Content-Type", "text/html") + + tmpl, err := template.New("cubicleform.html").Funcs(funcMap).ParseFiles("./templates/cubicleform.html") + if err != nil { + log.Printf("Error parsing html template: %v\n", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + err = tmpl.Execute(w, icsData) + if err != nil { + log.Printf("Error executing html template: %v\n", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + func (s *Server) BookCubicle(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { dtstart := ps.ByName("dtstart") //TODO: replace Local TZ by config setting diff --git a/templates/cubicleform.html b/templates/cubicleform.html @@ -0,0 +1,24 @@ +<html> + <head> + <title>HiveDAV - Book Cubicle</title> + <link rel="stylesheet" href="/css/index.css"> + <link rel="stylesheet" href="/css/style.css"> + </head> + <body> + <nav> + <ul> + <li><a href="/">Back to calendar</a></li> + </ul> + </nav> + Reserve cubicle for 1 hour + <form method="post" enctype="multipart/form-data" action="/book/{{ .Dtstart }}" class="cubicleform"> + <label for="dtstart">Date and time:</label><input type="datetime-local" value="{{ .DtstartInput }}" id="dtstart" /> + <label for="mail">Email:</label><input type="email" id="mail" name="mail" /> + <label for="mail">Your message:</label><textarea id="msg" name="msg"></textarea> + <input type="submit" value="Book me" /> + </form> + <footer> + HiveDAV <a href="https://code.in0rdr.ch/hivedav/refs.html">{{ .Version }}</a> &#127855; + </footer> + </body> +</html> diff --git a/templates/index.html b/templates/index.html @@ -18,22 +18,26 @@ <li><a href="/week/{{ next .Week }}">Next week</a></li> </ul> </nav> - <table> + <table class="calendar"> <tr> - {{ range $i, $h := .TableHead }} + {{- range $i, $h := .TableHead }} <th>{{ $h }}</th> - {{ end }} + {{- end }} </tr> - {{ range $i, $r := .Rows }} + {{- range $i, $r := .Rows }} <tr> <td>{{ index $r 0 }}</td> - <td>{{with index $r 1}}<a href="/book/{{ index $r 1 }}">book</a>{{else}}X{{end}}</td> - <td>{{with index $r 2}}<a href="/book/{{ index $r 2 }}">book</a>{{else}}X{{end}}</td> - <td>{{with index $r 3}}<a href="/book/{{ index $r 3 }}">book</a>{{else}}X{{end}}</td> - <td>{{with index $r 5}}<a href="/book/{{ index $r 4 }}">book</a>{{else}}X{{end}}</td> - <td>{{with index $r 1}}<a href="/book/{{ index $r 5 }}">book</a>{{else}}X{{end}}</td> + {{- range $v := mkSlice 1 5 }} + <td> + {{- with index $r $v -}} + <a aria-label="free" href="/book/{{ index $r $v }}" class="free">&#9633;</a> + {{- else -}} + <span aria-label="busy" class="busy">&#9635;</span> + {{- end -}} + </td> + {{- end }} </tr> - {{ end }} + {{- end }} </table> <footer> HiveDAV <a href="https://code.in0rdr.ch/hivedav/refs.html">{{ .Version }}</a> &#127855;