2025-06-30 12:37:33 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"net/http"
|
|
|
|
|
"net/url"
|
|
|
|
|
"os"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/AnthonyHewins/gotfy"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type authdTransport struct {
|
|
|
|
|
underlyingTransport http.RoundTripper
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (t *authdTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
|
|
|
var ntfyToken string
|
|
|
|
|
env := os.Environ()
|
|
|
|
|
for _, keyVal := range env {
|
|
|
|
|
keyValArr := strings.Split(keyVal, "=")
|
|
|
|
|
if keyValArr[0] == "NTFY_TOKEN" {
|
|
|
|
|
ntfyToken = keyValArr[1]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req.Header.Add("Authorization", "Bearer "+ntfyToken)
|
|
|
|
|
return t.underlyingTransport.RoundTrip(req)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Ntfy struct {
|
|
|
|
|
client *gotfy.Publisher
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func SetupNtfyClient() *Ntfy {
|
|
|
|
|
host := ""
|
|
|
|
|
env := os.Environ()
|
|
|
|
|
for _, keyVal := range env {
|
|
|
|
|
keyValArr := strings.Split(keyVal, "=")
|
|
|
|
|
if keyValArr[0] == "NTFY_HOST" {
|
|
|
|
|
host = keyValArr[1]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if host == "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
server, err := url.Parse(host)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
authdHttpClient := &http.Client{Transport: &authdTransport{underlyingTransport: http.DefaultTransport}}
|
|
|
|
|
|
|
|
|
|
tp, err := gotfy.NewPublisher(server, authdHttpClient)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-30 12:37:33 +02:00
|
|
|
fmt.Println("ntfy ready")
|
|
|
|
|
|
2025-06-30 12:37:33 +02:00
|
|
|
return &Ntfy{client: tp}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-02 16:48:44 +02:00
|
|
|
func numberToEmoji(num int64) string {
|
|
|
|
|
switch num {
|
|
|
|
|
case 0:
|
|
|
|
|
return "zero"
|
|
|
|
|
case 1:
|
|
|
|
|
return "one"
|
|
|
|
|
case 2:
|
|
|
|
|
return "two"
|
|
|
|
|
case 3:
|
|
|
|
|
return "three"
|
|
|
|
|
case 4:
|
|
|
|
|
return "four"
|
|
|
|
|
case 5:
|
|
|
|
|
return "five"
|
|
|
|
|
case 6:
|
|
|
|
|
return "six"
|
|
|
|
|
case 7:
|
|
|
|
|
return "seven"
|
|
|
|
|
case 8:
|
|
|
|
|
return "eight"
|
|
|
|
|
case 9:
|
|
|
|
|
return "nine"
|
|
|
|
|
default:
|
|
|
|
|
return "question"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func buildRsvpTitle(rsvp *Rsvp) string {
|
2025-06-30 12:37:33 +02:00
|
|
|
builder := new(strings.Builder)
|
|
|
|
|
if rsvp.Attending {
|
|
|
|
|
peoplePerson := "people"
|
|
|
|
|
if rsvp.PartySize == 1 {
|
|
|
|
|
peoplePerson = "person"
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(builder, "%d %s confirmed!", rsvp.PartySize, peoplePerson)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(builder, "Someone can't make it")
|
|
|
|
|
}
|
|
|
|
|
return builder.String()
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-02 16:48:44 +02:00
|
|
|
func buildRsvpMessage(rsvp *Rsvp) string {
|
2025-06-30 12:37:33 +02:00
|
|
|
builder := new(strings.Builder)
|
|
|
|
|
if rsvp.Attending {
|
|
|
|
|
builder.WriteString("Here's who is coming 👇")
|
|
|
|
|
for _, mem := range rsvp.PartyMembers {
|
|
|
|
|
age := "adult"
|
|
|
|
|
if mem.Child {
|
|
|
|
|
age = "👶"
|
|
|
|
|
} else {
|
|
|
|
|
age = "🧓"
|
|
|
|
|
}
|
|
|
|
|
dp := "n/a"
|
|
|
|
|
if len(mem.DietaryPreferences) > 0 {
|
|
|
|
|
dp = mem.DietaryPreferences
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(builder, "\n- %s %s, %s", age, mem.Name, dp)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for _, mem := range rsvp.PartyMembers {
|
|
|
|
|
fmt.Fprintf(builder, "%s\n", mem.Name)
|
|
|
|
|
}
|
|
|
|
|
builder.WriteString("can't make it")
|
|
|
|
|
}
|
|
|
|
|
return builder.String()
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-02 16:48:44 +02:00
|
|
|
func buildRsvpTags(rsvp *Rsvp) []string {
|
2025-06-30 12:37:33 +02:00
|
|
|
if rsvp.Attending {
|
|
|
|
|
return []string{"white_check_mark", numberToEmoji(rsvp.PartySize)}
|
|
|
|
|
} else {
|
|
|
|
|
return []string{"x"}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-02 16:48:44 +02:00
|
|
|
func BuildRsvpMessage(topic string, rsvp *Rsvp) *gotfy.Message {
|
2025-06-30 12:37:33 +02:00
|
|
|
return &gotfy.Message{
|
|
|
|
|
Topic: topic,
|
2025-09-02 16:48:44 +02:00
|
|
|
Message: buildRsvpMessage(rsvp),
|
|
|
|
|
Title: buildRsvpTitle(rsvp),
|
|
|
|
|
Tags: buildRsvpTags(rsvp),
|
2025-06-30 12:37:33 +02:00
|
|
|
Priority: gotfy.Default,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (n *Ntfy) PublishNewRsvpNotification(rsvp *Rsvp) (string, error) {
|
2025-09-02 16:48:44 +02:00
|
|
|
resp, err := n.client.SendMessage(context.Background(), BuildRsvpMessage("collinenlucy_nl", rsvp))
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resp.ID, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func buildVisitTitle(visit *Visit) string {
|
|
|
|
|
return "Someone visited!"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func buildVisitMessage(visit *Visit) string {
|
|
|
|
|
return fmt.Sprintf("Got a visit from %s (%s)", visit.Location, visit.RemoteAddr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BuildVisitMessage(topic string, visit *Visit) *gotfy.Message {
|
|
|
|
|
return &gotfy.Message{
|
|
|
|
|
Topic: topic,
|
|
|
|
|
Message: buildVisitMessage(visit),
|
|
|
|
|
Title: buildVisitTitle(visit),
|
|
|
|
|
Tags: []string{"eyes"},
|
|
|
|
|
Priority: gotfy.Default,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (n *Ntfy) PublishNewVisitNotification(visit *Visit) (string, error) {
|
|
|
|
|
resp, err := n.client.SendMessage(context.Background(), BuildVisitMessage("collinenlucy_nl", visit))
|
2025-06-30 12:37:33 +02:00
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resp.ID, nil
|
|
|
|
|
}
|