package notification import ( // External werr "git.gibonuddevalla.se/go/wrappederror" // Standard "bytes" "encoding/json" "fmt" "io" "log/slog" "net/http" "net/url" "strconv" "strings" ) type NTFY struct { URL string Prio int AcknowledgeURL string logger *slog.Logger exists bool updated Service } func init() { allServices = append(allServices, &NTFY{}) } func NewNTFY(config []byte, prio int, ackURL string) (instance *NTFY, err error) { instance = new(NTFY) err = json.Unmarshal(config, &instance) if err != nil { err = werr.Wrap(err).WithCode("002-0001").WithData(config) return } instance.Prio = prio instance.AcknowledgeURL = ackURL return instance, nil } func (ntfy *NTFY) SetLogger(l *slog.Logger) { ntfy.logger = l } func (ntfy *NTFY) GetType() string { return "NTFY" } func (ntfy *NTFY) GetPrio() int { return ntfy.Prio } func (ntfy *NTFY) SetPrio(prio int) { ntfy.Prio = prio } func (ntfy *NTFY) SetExists(exists bool) { ntfy.exists = exists } func (ntfy NTFY) Exists() bool { return ntfy.exists } func (ntfy *NTFY) String() string { return ntfy.URL } func (ntfy NTFY) Send(problemID int, msg []byte) (err error) { var req *http.Request var res *http.Response req, err = http.NewRequest("POST", ntfy.URL, bytes.NewReader(msg)) if err != nil { err = werr.Wrap(err).WithCode("002-0002").WithData(ntfy.URL) return } ackURL := fmt.Sprintf("http, OK, %s/notification/ack?problemID=%d", ntfy.AcknowledgeURL, problemID) req.Header.Add("X-Actions", ackURL) req.Header.Add("X-Priority", "4") // XXX: should be 5 req.Header.Add("X-Tags", "calendar") res, err = http.DefaultClient.Do(req) if err != nil { err = werr.Wrap(err).WithCode("002-0003") return } body, _ := io.ReadAll(res.Body) if res.StatusCode != 200 { err = werr.New("Invalid NTFY response").WithCode("002-0004").WithData(body) return } ntfyResp := struct { ID string }{} err = json.Unmarshal(body, &ntfyResp) if err != nil { err = werr.Wrap(err).WithCode("002-0005").WithData(body) return } return } func (ntfy *NTFY) Update(values url.Values) (err error) { updated := NTFY{} ntfy.updated = &updated updated.Prio, err = strconv.Atoi(values.Get("prio")) if err != nil { return werr.Wrap(err) } givenURL := values.Get("url") if strings.TrimSpace(givenURL) == "" { return werr.New("URL cannot be empty") } updated.URL = strings.TrimSpace(givenURL) return } func (ntfy *NTFY) Updated() Service { return ntfy.updated } func (ntfy *NTFY) Commit() { updatedNTFY := ntfy.updated.(*NTFY) ntfy.Prio = updatedNTFY.Prio ntfy.URL = updatedNTFY.URL } func (ntfy NTFY) JSON() []byte { data := struct { URL string `json:"url"` }{ ntfy.URL, } j, _ := json.Marshal(data) return j }