Skip to content

Commit

Permalink
solve libs
Browse files Browse the repository at this point in the history
  • Loading branch information
allan committed Mar 8, 2024
1 parent 536d61d commit e6cd907
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 4 deletions.
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ require (
github.com/go-chi/chi v1.5.5 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/jmoiron/sqlx v1.2.0 // indirect
github.com/knadh/koanf v1.5.0 // indirect
github.com/lib/pq v1.3.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/yuin/goldmark v1.3.5 // indirect
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 // indirect
golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 // indirect
golang.org/x/sys v0.4.0 // indirect
google.golang.org/appengine v1.6.6 // indirect
google.golang.org/protobuf v1.26.0 // indirect
gopkg.in/volatiletech/null.v6 v6.0.0-20170828023728-0bef4e07ae1b // indirect
)
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
Expand Down Expand Up @@ -271,6 +272,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
Expand Down Expand Up @@ -390,6 +392,7 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand All @@ -408,6 +411,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.4/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
Expand Down Expand Up @@ -750,6 +754,7 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/volatiletech/null.v6 v6.0.0-20170828023728-0bef4e07ae1b h1:P+3+n9hUbqSDkSdtusWHVPQRrpRpLiLFzlZ02xXskM0=
gopkg.in/volatiletech/null.v6 v6.0.0-20170828023728-0bef4e07ae1b/go.mod h1:0LRKfykySnChgQpG3Qpk+bkZFWazQ+MMfc5oldQCwnY=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Expand Down
168 changes: 168 additions & 0 deletions handlers.go
Original file line number Diff line number Diff line change
@@ -1,2 +1,170 @@
package main

import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/textproto"

"github.com/HiWay-Media/listmonk-onesignal/lib"
"github.com/go-chi/chi"
"github.com/knadh/listmonk/models"
)

type postback struct {
Subject string `json:"subject"`
FromEmail string `json:"from_email"`
ContentType string `json:"content_type"`
Body string `json:"body"`
Recipients []recipient `json:"recipients"`
Campaign *campaign `json:"campaign"`
Attachments []attachment `json:"attachments"`
}

type campaign struct {
FromEmail string `json:"from_email"`
UUID string `json:"uuid"`
Name string `json:"name"`
Tags []string `json:"tags"`
}

type recipient struct {
UUID string `json:"uuid"`
Email string `json:"email"`
Name string `json:"name"`
Attribs models.SubscriberAttribs `json:"attribs"`
Status string `json:"status"`
}

type attachment struct {
Name string `json:"name"`
Header textproto.MIMEHeader `json:"header"`
Content []byte `json:"content"`
}

type httpResp struct {
Status string `json:"status"`
Message string `json:"message,omitempty"`
Data interface{} `json:"data,omitempty"`
}

// handlePostback picks the messager based on url params and pushes message using it.
func handlePostback(w http.ResponseWriter, r *http.Request) {
var (
app = r.Context().Value("app").(*App)
provider = chi.URLParam(r, "provider")
)

// Decode body
body, err := ioutil.ReadAll(r.Body)
if err != nil {
app.logger.ErrorWith("error reading request body").Err("err", err).Write()
sendErrorResponse(w, "invalid body", http.StatusBadRequest, nil)
return
}
defer r.Body.Close()

data := &postback{}
if err := json.Unmarshal(body, &data); err != nil {
app.logger.ErrorWith("error unmarshalling request body").Err("err", err).Write()
sendErrorResponse(w, "invalid body", http.StatusBadRequest, nil)
return
}

// Get the provider.
p, ok := app.messengers[provider]
if !ok {
sendErrorResponse(w, "unknown provider", http.StatusBadRequest, nil)
return
}

if len(data.Recipients) > 1 {
sendErrorResponse(w, "invalid recipients", http.StatusBadRequest, nil)
return
}

rec := data.Recipients[0]
message := lib.Message{
From: data.FromEmail,
Subject: data.Subject,
ContentType: data.ContentType,
Body: []byte(data.Body),
Subscriber: models.Subscriber{
UUID: rec.UUID,
Email: rec.Email,
Name: rec.Name,
Status: rec.Status,
Attribs: rec.Attribs,
},
}

if data.Campaign != nil {
message.Campaign = &models.Campaign{
FromEmail: data.Campaign.FromEmail,
UUID: data.Campaign.UUID,
Name: data.Campaign.Name,
Tags: data.Campaign.Tags,
}
}

if len(data.Attachments) > 0 {
files := make([]lib.Attachment, 0, len(data.Attachments))
for _, f := range data.Attachments {
a := lib.Attachment{
Name: f.Name,
Header: f.Header,
Content: make([]byte, len(f.Content)),
}
copy(a.Content, f.Content)
files = append(files, a)
}

message.Attachments = files
}

app.logger.DebugWith("sending message").String("provider", provider).String("message", fmt.Sprintf("%#+v", message)).Write()

// Send message.
if err := p.Push(message); err != nil {
app.logger.ErrorWith("error sending message").Err("err", err).Write()
sendErrorResponse(w, "error sending message", http.StatusInternalServerError, nil)
return
}

sendResponse(w, "OK")
return
}

// wrap is a middleware that wraps HTTP handlers and injects the "app" context.
func wrap(app *App, next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), "app", app)
next.ServeHTTP(w, r.WithContext(ctx))
})
}

// sendResponse sends a JSON envelope to the HTTP response.
func sendResponse(w http.ResponseWriter, data interface{}) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
out, err := json.Marshal(httpResp{Status: "success", Data: data})
if err != nil {
sendErrorResponse(w, "Internal Server Error", http.StatusInternalServerError, nil)
return
}

w.Write(out)
}

// sendErrorResponse sends a JSON error envelope to the HTTP response.
func sendErrorResponse(w http.ResponseWriter, message string, code int, data interface{}) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(code)

resp := httpResp{Status: "error",
Message: message,
Data: data}
out, _ := json.Marshal(resp)
w.Write(out)
}
39 changes: 39 additions & 0 deletions lib/models.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package lib

import (
"net/textproto"

"github.com/knadh/listmonk/models"
)

type Messenger interface {
Name() string
Push(Message) error
Flush() error
Close() error
}

// Message is the message pushed to a Messenger.
type Message struct {
From string
To []string
Subject string
ContentType string
Body []byte
AltBody []byte
Headers textproto.MIMEHeader
Attachments []Attachment

Subscriber models.Subscriber

// Campaign is generally the same instance for a large number of subscribers.
Campaign *models.Campaign
}

// Attachment represents a file or blob attachment that can be
// sent along with a message by a Messenger.
type Attachment struct {
Name string
Header textproto.MIMEHeader
Content []byte
}
13 changes: 9 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"time"

"github.com/HiWay-Media/listmonk-onesignal/lib"
"github.com/francoispqt/onelog"
"github.com/go-chi/chi"
"github.com/knadh/koanf"
Expand All @@ -24,11 +25,15 @@ var (
buildString = "unknown"
)


type Cfg struct {
Config string `koanf:"config"`
}

type App struct {
logger *onelog.Logger

messengers map[string]lib.Messenger
}

func init() {
f := flag.NewFlagSet("config", flag.ContinueOnError)
Expand Down Expand Up @@ -81,8 +86,8 @@ func main() {

// load messengers
app := &App{logger: l}
r := chi.NewRouter()
//r.Post("/webhook/{provider}", wrap(app, handlePostback))
r := chi.NewRouter()
r.Post("/webhook/{provider}", wrap(app, handlePostback))

// HTTP Server.
srv := &http.Server{
Expand All @@ -96,4 +101,4 @@ func main() {
if err := srv.ListenAndServe(); err != nil {
logger.Fatalf("couldn't start server: %v", err)
}
}
}

0 comments on commit e6cd907

Please sign in to comment.