package main import ( // External werr "git.gibonuddevalla.se/go/wrappederror" // Standard "encoding/json" "fmt" "regexp" "strconv" "strings" "time" ) func init() { fmt.Printf("") } type Schedule struct { ID int UserID int `json:"user_id" db:"user_id"` Node Node ScheduleUUID string `db:"schedule_uuid"` Time time.Time RemindMinutes int `db:"remind_minutes"` Description string Acknowledged bool } func ScanForSchedules(timeOffset int, content string) (schedules []Schedule) { // {{{ schedules = []Schedule{} rxp := regexp.MustCompile(`\{\s*([0-9]{4}-[0-9]{2}-[0-9]{2}\s+[0-9]{2}:[0-9]{2}(?::[0-9]{2})?)\s*\,\s*(?:(\d+)\s*(h|min)\s*,)?\s*([^\]]+?)\s*\}`) foundSchedules := rxp.FindAllStringSubmatch(content, -1) for _, data := range foundSchedules { // Missing seconds if strings.Count(data[1], ":") == 1 { data[1] = data[1] + ":00" } // Timezone calculations var timeTZ string if timeOffset < 0 { hours := (-timeOffset) / 60 mins := (-timeOffset) % 60 timeTZ = fmt.Sprintf("%s -%02d%02d", data[1], hours, mins) } else { hours := timeOffset / 60 mins := timeOffset % 60 timeTZ = fmt.Sprintf("%s +%02d%02d", data[1], hours, mins) } timestamp, err := time.Parse("2006-01-02 15:04:05 -0700", timeTZ) if err != nil { continue } // Reminder var remindMinutes int if data[2] != "" && data[3] != "" { value, _ := strconv.Atoi(data[2]) unit := strings.ToLower(data[3]) switch unit { case "min": remindMinutes = value case "h": remindMinutes = value * 60 } } schedule := Schedule{ Time: timestamp, RemindMinutes: remindMinutes, Description: data[4], } schedules = append(schedules, schedule) } return } // }}} func RetrieveSchedules(userID int, nodeID int) (schedules []Schedule, err error) { // {{{ schedules = []Schedule{} res := service.Db.Conn.QueryRow(` WITH schedule_events AS ( SELECT id, user_id, json_build_object('id', node_id) AS node, schedule_uuid, time - MAKE_INTERVAL(mins => remind_minutes) AS time, description, acknowledged FROM schedule WHERE user_id=$1 AND CASE WHEN $2 > 0 THEN node_id = $2 ELSE true END ) SELECT COALESCE(jsonb_agg(s.*), '[]'::jsonb) FROM schedule_events s `, userID, nodeID, ) var data []byte err = res.Scan(&data) if err != nil { return } err = json.Unmarshal(data, &schedules) return } // }}} func (a Schedule) IsEqual(b Schedule) bool { // {{{ return a.UserID == b.UserID && a.Node.ID == b.Node.ID && a.Time.Equal(b.Time) && a.Description == b.Description } // }}} func (s *Schedule) Insert(queryable Queryable) error { // {{{ res := queryable.QueryRow(` INSERT INTO schedule(user_id, node_id, time, remind_minutes, description) VALUES($1, $2, $3, $4, $5) RETURNING id `, s.UserID, s.Node.ID, s.Time, s.RemindMinutes, s.Description, ) return res.Scan(&s.ID) } // }}} func (s *Schedule) Delete(queryable Queryable) error { // {{{ _, err := queryable.Exec(` DELETE FROM schedule WHERE user_id = $1 AND id = $2 `, s.UserID, s.ID, ) return err } // }}} func ExpiredSchedules() (schedules []Schedule) { // {{{ schedules = []Schedule{} res, err := service.Db.Conn.Queryx(` SELECT id, user_id, node_id, schedule_uuid, time - MAKE_INTERVAL(mins => remind_minutes) AS time, description FROM schedule WHERE (time - MAKE_INTERVAL(mins => remind_minutes)) < NOW() AND NOT acknowledged ORDER BY time ASC `) if err != nil { err = werr.Wrap(err).WithCode("002-0009") return } defer res.Close() for res.Next() { s := Schedule{} if err = res.Scan(&s.ID, &s.UserID, &s.Node.ID, &s.ScheduleUUID, &s.Time, &s.Description); err != nil { werr.Wrap(err).WithCode("002-000a") continue } schedules = append(schedules, s) } return } // }}}