hivedav

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

commit 704f5a88754fb4a1bf3c1a2e8e9c5cbfed1f7df3
parent 0fd55cea6e720d4de56f46d61a6b8dfb1230ff82
Author: Andreas Gruhler <andreas.gruhler@adfinis.com>
Date:   Sun, 25 Feb 2024 22:11:15 +0100

feat: simplify availability query

Diffstat:
MREADME.md | 38++++++++++++++++++++++++++------------
Mserver.go | 34++++++++++++++--------------------
2 files changed, 40 insertions(+), 32 deletions(-)

diff --git a/README.md b/README.md @@ -148,44 +148,58 @@ stored in a local database for further processing. ## Availability Query +- s: start time +- e: end time +- ?: sql query parameter (start/end) +- |: time slot (1h) + +The (un)availability query returns true if an existing appointment is found +(unavailable, no free time slot). It returns false, when there exists no +existing calendar entry during the time slot (available). + ``` // e ? ? // - | | false - +// // s e ? // - + | false - +// // s ? e ? // - | - | true (2) - +// // s ? e // - | + true (2) - +// // s ? ? e // - | | - true (3) - +// // s e ? // + - | true (1) - +// // s e -// + + true (2) - +// + + true (3) +// // s ? e // + | - true (1) - +// // ? s e // | - + true (1) - +// // ? s ? e // | - | - true (1) - +// // ? s e // | + - false ``` +Note: +The calendar does not show events marked with the +(X-MICROSOFT-CDO-INTENDEDSTATUS") "FREE" status. This can be helpful to skip +certain "reminders" in your calendar, which should not be considered as +"blocked time" (e.g., full day events). + TODO: - Time slots are 1h each (TODO: make it configurable) -- Sqlite date comparison always inclusive? - Picture for the query ## Development & Contributions diff --git a/server.go b/server.go @@ -81,11 +81,9 @@ var create_availability_1 = `CREATE TABLE IF NOT EXISTS availability_1 ( end DATETIME NOT NULL, recurring BOOL NOT NULL);` -// BETWEEN is inclusive, we tweak start/time by 1 min to make the edge cases -// 08:01, 09:59, etc. behave correctly var available = `SELECT id FROM availability WHERE - (start BETWEEN ? AND ?) OR - (end BETWEEN ? AND ?) OR + (start >= ? AND start < ?) OR + (end > ? AND end <= ?) OR (start <= ? AND end >= ?);` func (s *Server) NewServer(c *config.Config) (*Server, error) { @@ -213,7 +211,7 @@ func (s *Server) Week(w http.ResponseWriter, req *http.Request, ps httprouter.Pa log.Printf("Serving week '%v' of year '%v'\n", week, year) log.Printf("Monday is '%v'\n", monday) - sqlDateFmt := "2006-01-02 15:04" + sqlDateFmt := "2006-01-02 15:04:00" termRows := make([][]string, 9) for i := range termRows { @@ -266,11 +264,10 @@ func (s *Server) Week(w http.ResponseWriter, req *http.Request, ps httprouter.Pa // Working days - Monday through Friday //for d := 0; d < 5; d++ { for _, d := range []int{1, 2, 3, 4, 5} { - // add/remove 1 minute to make the sql time query in available() below behave correctly // convert to read/compare in UTC from db - startTime := timeIt.Add(time.Hour * time.Duration((d-1)*24+h)).Add(1 * time.Minute) + startTime := timeIt.Add(time.Hour * time.Duration((d-1)*24+h)) start := startTime.UTC().Format(sqlDateFmt) - endTime := timeIt.Add(time.Hour * time.Duration((d-1)*24+h+1)).Add(-1 * time.Minute) + endTime := timeIt.Add(time.Hour * time.Duration((d-1)*24+h+1)) end := endTime.UTC().Format(sqlDateFmt) avi, err := s.available(start, end) if err != nil { @@ -438,7 +435,7 @@ func (s *Server) UpdateAvailability(calData []caldav.CalData) error { } // set new availability in temporary table availability_1 - if _, err = s.db.Exec("INSERT INTO availability_1 VALUES(NULL, ?, ?, false);", startTime, endTime); err != nil { + if _, err = s.db.Exec("INSERT INTO availability_1 VALUES(NULL, DATETIME(?), DATETIME(?), false);", startTime, endTime); err != nil { return err } @@ -466,7 +463,7 @@ func (s *Server) UpdateAvailability(calData []caldav.CalData) error { // don't include the first event, handled outside the loop rDates := set.Between(startTime, rrLimit, false) for _, rrd := range rDates { - if _, err = s.db.Exec("INSERT INTO availability_1 VALUES(NULL, ?, ?, true);", rrd, rrd.Add(duration)); err != nil { + if _, err = s.db.Exec("INSERT INTO availability_1 VALUES(NULL, DATETIME(?), DATETIME(?), true);", rrd, rrd.Add(duration)); err != nil { return err } } @@ -551,7 +548,7 @@ func (s *Server) ListCubiclesInWeek(w http.ResponseWriter, req *http.Request, ps log.Printf("Serving week '%v' of year '%v'\n", week, year) log.Printf("Monday is '%v'\n", monday) - sqlDateFmt := "2006-01-02 15:04" + sqlDateFmt := "2006-01-02 15:04:00" var rows [][]string @@ -579,12 +576,11 @@ func (s *Server) ListCubiclesInWeek(w http.ResponseWriter, req *http.Request, ps for d := 0; d < 5; d++ { // 9 1hour time slots for h := 8; h < 17; h++ { - // add/remove 1 minute to make the sql time query in available() below behave correctly // convert to read/compare in UTC from db startTime := timeIt.Add(time.Hour * time.Duration((d)*24+h)) endTime := timeIt.Add(time.Hour * time.Duration((d)*24+h+1)) - start := startTime.Add(1 * time.Minute).UTC().Format(sqlDateFmt) - end := endTime.Add(-1 * time.Minute).UTC().Format(sqlDateFmt) + start := startTime.UTC().Format(sqlDateFmt) + end := endTime.UTC().Format(sqlDateFmt) avi, err := s.available(start, end) if err != nil { log.Printf("Error getting availability on day '%d' hour '%d'\n", d, h) @@ -728,12 +724,10 @@ func (s *Server) BookCubicle(w http.ResponseWriter, req *http.Request, ps httpro return } - // TODO: move this 1 minute logic + sqlDateFmt into available() function - // add/remove 1 minute to make the sql time query in available() below behave correctly // convert to read/compare in UTC from db - sqlDateFmt := "2006-01-02 15:04" - start := dtstart.Add(1 * time.Minute).UTC().Format(sqlDateFmt) - end := dtstart.Add(time.Hour).Add(-1 * time.Minute).UTC().Format(sqlDateFmt) + sqlDateFmt := "2006-01-02 15:04:00" + start := dtstart.UTC().Format(sqlDateFmt) + end := dtstart.Add(time.Hour).UTC().Format(sqlDateFmt) avi, err := s.available(start, end) if err != nil { log.Printf("Error getting availability on '%s'\n", start) @@ -757,7 +751,7 @@ func (s *Server) BookCubicle(w http.ResponseWriter, req *http.Request, ps httpro // update availability startTimeUtc := dtstart.UTC() endTimeUtc := dtstart.Add(time.Hour).UTC() - if _, err = s.db.Exec("INSERT INTO availability VALUES(NULL, ?, ?, false);", startTimeUtc, endTimeUtc); err != nil { + if _, err = s.db.Exec("INSERT INTO availability VALUES(NULL, DATETIME(?), DATETIME(?), false);", startTimeUtc, endTimeUtc); err != nil { log.Printf("Error updating availability database with new booking: %v\n", err) http.Error(w, err.Error(), http.StatusInternalServerError) return