Skip to content

Commit 2149b15

Browse files
added ses keys crud endpoints, implemented configuration sets creation and sns topics
1 parent bd0ecc9 commit 2149b15

File tree

2 files changed

+255
-0
lines changed

2 files changed

+255
-0
lines changed

actions/seskeys.go

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
package actions
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/aws/aws-sdk-go/aws"
7+
"github.com/aws/aws-sdk-go/service/ses"
8+
"github.com/aws/aws-sdk-go/service/sns"
9+
10+
"github.com/sirupsen/logrus"
11+
12+
"github.com/gin-gonic/gin"
13+
"github.com/news-maily/api/emails"
14+
"github.com/news-maily/api/entities"
15+
"github.com/news-maily/api/events"
16+
"github.com/news-maily/api/routes/middleware"
17+
"github.com/news-maily/api/storage"
18+
)
19+
20+
func GetSESKeys(c *gin.Context) {
21+
u := middleware.GetUser(c)
22+
23+
keys, err := storage.GetSesKeys(c, u.Id)
24+
if err != nil {
25+
c.JSON(http.StatusNotFound, gin.H{
26+
"reason": "AWS Ses keys not set.",
27+
})
28+
return
29+
}
30+
31+
keys.SecretKey = "" //do not return the secret
32+
33+
c.JSON(http.StatusOK, keys)
34+
}
35+
36+
func PostSESKeys(c *gin.Context) {
37+
u := middleware.GetUser(c)
38+
39+
keys, err := storage.GetSesKeys(c, u.Id)
40+
if err == nil {
41+
c.JSON(http.StatusBadRequest, gin.H{
42+
"reason": "AWS Ses keys are already set.",
43+
})
44+
return
45+
}
46+
47+
keys = &entities.SesKeys{
48+
AccessKey: c.PostForm("access_key"),
49+
SecretKey: c.PostForm("secret_key"),
50+
Region: c.PostForm("region"),
51+
UserId: u.Id,
52+
}
53+
54+
if !keys.Validate() {
55+
c.JSON(http.StatusBadRequest, keys.Errors)
56+
return
57+
}
58+
59+
sender, err := emails.NewSesSender(keys.AccessKey, keys.SecretKey, keys.Region)
60+
if err != nil {
61+
logrus.Errorln(err.Error())
62+
c.JSON(http.StatusBadRequest, gin.H{
63+
"reason": "SES keys are incorrect.",
64+
})
65+
return
66+
}
67+
68+
snsClient, err := events.NewEventsClient(keys.AccessKey, keys.SecretKey, keys.Region)
69+
if err != nil {
70+
logrus.Errorln(err.Error())
71+
c.JSON(http.StatusBadRequest, gin.H{
72+
"reason": "SES keys are incorrect.",
73+
})
74+
return
75+
}
76+
77+
// Check if the configuration set is already created
78+
topicArn := ""
79+
cs, err := sender.DescribeConfigurationSet(&ses.DescribeConfigurationSetInput{
80+
ConfigurationSetName: aws.String(emails.ConfigurationSetName),
81+
ConfigurationSetAttributeNames: []*string{
82+
aws.String("eventDestinations"),
83+
},
84+
})
85+
86+
if err != nil {
87+
_, err := sender.CreateConfigurationSet(&ses.CreateConfigurationSetInput{
88+
ConfigurationSet: &ses.ConfigurationSet{
89+
Name: aws.String(emails.ConfigurationSetName),
90+
},
91+
})
92+
if err != nil {
93+
logrus.Errorln(err)
94+
return
95+
}
96+
97+
snsRes, err := snsClient.CreateTopic(&sns.CreateTopicInput{
98+
Name: aws.String(events.SNSTopicName),
99+
})
100+
if err != nil {
101+
// rollback
102+
sender.DeleteConfigurationSet(&ses.DeleteConfigurationSetInput{
103+
ConfigurationSetName: aws.String(emails.ConfigurationSetName),
104+
})
105+
logrus.Errorln(err)
106+
return
107+
}
108+
109+
topicArn = *snsRes.TopicArn
110+
111+
_, err = snsClient.Subscribe(&sns.SubscribeInput{
112+
Protocol: aws.String("https"),
113+
Endpoint: aws.String("https://4aa71fbb.ngrok.io/api/hooks"),
114+
TopicArn: aws.String(topicArn),
115+
})
116+
if err != nil {
117+
// rollback
118+
sender.DeleteConfigurationSet(&ses.DeleteConfigurationSetInput{
119+
ConfigurationSetName: aws.String(emails.ConfigurationSetName),
120+
})
121+
snsClient.DeleteTopic(&sns.DeleteTopicInput{TopicArn: snsRes.TopicArn})
122+
logrus.Errorln(err)
123+
return
124+
}
125+
}
126+
127+
// Check if the event destination is set
128+
eventFound := false
129+
for _, e := range cs.EventDestinations {
130+
if e.Name != nil && *e.Name == events.SNSTopicName {
131+
eventFound = true
132+
}
133+
}
134+
135+
if !eventFound {
136+
if topicArn == "" {
137+
snsRes, err := snsClient.CreateTopic(&sns.CreateTopicInput{
138+
Name: aws.String(events.SNSTopicName),
139+
})
140+
if err != nil {
141+
logrus.Errorln(err)
142+
return
143+
}
144+
145+
topicArn = *snsRes.TopicArn
146+
147+
_, err = snsClient.Subscribe(&sns.SubscribeInput{
148+
Protocol: aws.String("https"),
149+
Endpoint: aws.String("https://4aa71fbb.ngrok.io/api/hooks"),
150+
TopicArn: aws.String(topicArn),
151+
})
152+
if err != nil {
153+
logrus.Errorln(err)
154+
return
155+
}
156+
}
157+
158+
_, err = sender.CreateConfigurationSetEventDestination(&ses.CreateConfigurationSetEventDestinationInput{
159+
ConfigurationSetName: aws.String(emails.ConfigurationSetName),
160+
EventDestination: &ses.EventDestination{
161+
Name: aws.String(events.SNSTopicName),
162+
Enabled: aws.Bool(true),
163+
MatchingEventTypes: []*string{
164+
aws.String("send"),
165+
aws.String("open"),
166+
aws.String("click"),
167+
aws.String("bounce"),
168+
aws.String("reject"),
169+
aws.String("delivery"),
170+
aws.String("complaint"),
171+
aws.String("renderingFailure"),
172+
},
173+
SNSDestination: &ses.SNSDestination{
174+
TopicARN: aws.String(topicArn),
175+
},
176+
},
177+
})
178+
179+
if err != nil {
180+
logrus.Errorln(err)
181+
}
182+
}
183+
184+
err = storage.CreateSesKeys(c, keys)
185+
186+
if err != nil {
187+
logrus.WithFields(logrus.Fields{
188+
"input": *keys,
189+
}).Error(err)
190+
c.JSON(http.StatusBadRequest, gin.H{
191+
"reason": "Unable to add ses keys.",
192+
})
193+
return
194+
}
195+
196+
keys.SecretKey = ""
197+
198+
c.JSON(http.StatusCreated, keys)
199+
}
200+
201+
func DeleteSESKeys(c *gin.Context) {
202+
u := middleware.GetUser(c)
203+
204+
err := storage.DeleteSesKeys(c, u.Id)
205+
if err != nil {
206+
c.JSON(http.StatusBadRequest, gin.H{
207+
"reason": "AWS Ses keys not set.",
208+
})
209+
return
210+
}
211+
212+
c.Status(http.StatusNoContent)
213+
}

events/client.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package events
2+
3+
import (
4+
"github.com/aws/aws-sdk-go/aws"
5+
"github.com/aws/aws-sdk-go/aws/credentials"
6+
"github.com/aws/aws-sdk-go/aws/session"
7+
"github.com/aws/aws-sdk-go/service/sns"
8+
)
9+
10+
type EventsClient interface {
11+
CreateTopic(input *sns.CreateTopicInput) (*sns.CreateTopicOutput, error)
12+
DeleteTopic(input *sns.DeleteTopicInput) (*sns.DeleteTopicOutput, error)
13+
Subscribe(input *sns.SubscribeInput) (*sns.SubscribeOutput, error)
14+
}
15+
16+
const SNSTopicName = "MailbadgerEvents"
17+
18+
type eventsClientImpl struct {
19+
*sns.SNS
20+
}
21+
22+
func NewSNSClient(key, secret, region string) (*sns.SNS, error) {
23+
sess, err := session.NewSession(&aws.Config{
24+
Region: aws.String(region),
25+
Credentials: credentials.NewStaticCredentials(key, secret, ""),
26+
})
27+
28+
if err != nil {
29+
return nil, err
30+
}
31+
32+
return sns.New(sess), nil
33+
}
34+
35+
func NewEventsClient(key, secret, region string) (EventsClient, error) {
36+
client, err := NewSNSClient(key, secret, region)
37+
if err != nil {
38+
return nil, err
39+
}
40+
41+
return &eventsClientImpl{client}, nil
42+
}

0 commit comments

Comments
 (0)