Skip to content

Commit 0ccbb9b

Browse files
committed
Add code to create webhook failed events
1 parent 9eb0bbd commit 0ccbb9b

File tree

7 files changed

+271
-31
lines changed

7 files changed

+271
-31
lines changed

api/pkg/emails/factory.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
package emails
22

3-
import "github.com/nyaruka/phonenumbers"
3+
import (
4+
"fmt"
5+
6+
"github.com/nyaruka/phonenumbers"
7+
)
48

59
type factory struct{}
610

711
func (factory *factory) formatPhoneNumber(number string) string {
812
value, _ := phonenumbers.Parse(number, phonenumbers.UNKNOWN_REGION)
9-
return phonenumbers.Format(value, phonenumbers.E164)
13+
return phonenumbers.Format(value, phonenumbers.INTERNATIONAL)
14+
}
15+
16+
func (factory *factory) formatHTTPResponseCode(code *int) string {
17+
responseCode := "-"
18+
if code != nil {
19+
responseCode = fmt.Sprintf("%d", *code)
20+
}
21+
return responseCode
1022
}

api/pkg/emails/hermes_notification_email_factory.go

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,107 @@ func NewHermesNotificationEmailFactory(config *HermesGeneratorConfig) Notificati
2525
}
2626
}
2727

28+
func (factory *hermesNotificationEmailFactory) DiscordMessageFailed(user *entities.User, eventName, owner, errorMessage, channelID string, httpResponseStatusCode *int) (*Email, error) {
29+
email := hermes.Email{
30+
Body: hermes.Body{
31+
Title: "Hello",
32+
Intros: []string{
33+
fmt.Sprintf("We ran into an error while fowarding an incoming SMS to your discord server at %s", user.UserTimeString(time.Now())),
34+
},
35+
Dictionary: []hermes.Entry{
36+
{"Discord Channel ID", channelID},
37+
{"Event Name", eventName},
38+
{"Phone Number", factory.formatPhoneNumber(owner)},
39+
{"HTTP Response Code", factory.formatHTTPResponseCode(httpResponseStatusCode)},
40+
{"Error Message / HTTP Response", errorMessage},
41+
},
42+
Actions: []hermes.Action{
43+
{
44+
Instructions: "Usually this error happens because you have revoked permissions for the httpSMS discord app on your discord channel. You can always grant httpSMS permission to post to your discord channel under the settings page.",
45+
Button: hermes.Button{
46+
Color: "#329ef4",
47+
TextColor: "#FFFFFF",
48+
Text: "Settings",
49+
Link: "https://httpsms.com/settings",
50+
},
51+
},
52+
},
53+
Signature: "Cheers",
54+
Outros: []string{
55+
fmt.Sprintf("Don't hesitate to contact us by replying to this email."),
56+
},
57+
},
58+
}
59+
60+
html, err := factory.generator.GenerateHTML(email)
61+
if err != nil {
62+
return nil, stacktrace.Propagate(err, "cannot generate html email")
63+
}
64+
65+
text, err := factory.generator.GeneratePlainText(email)
66+
if err != nil {
67+
return nil, stacktrace.Propagate(err, "cannot generate text email")
68+
}
69+
70+
return &Email{
71+
ToEmail: user.Email,
72+
Subject: "📢 We could not forward an incoming message to your server",
73+
HTML: html,
74+
Text: text,
75+
}, nil
76+
}
77+
78+
func (factory *hermesNotificationEmailFactory) WebhookSendFailed(user *entities.User, eventName, eventID, owner, errorMessage, url string, httpResponseStatusCode *int) (*Email, error) {
79+
email := hermes.Email{
80+
Body: hermes.Body{
81+
Title: "Hello",
82+
Intros: []string{
83+
fmt.Sprintf("We ran into an error while fowarding a webhook event from httpSMS to your webserver at %s", user.UserTimeString(time.Now())),
84+
},
85+
Dictionary: []hermes.Entry{
86+
{"Server URL", url},
87+
{"Event Name", eventName},
88+
{"Event ID", eventID},
89+
{"Phone Number", factory.formatPhoneNumber(owner)},
90+
{"HTTP Response Code", factory.formatHTTPResponseCode(httpResponseStatusCode)},
91+
{"Error Message / HTTP Response", errorMessage},
92+
},
93+
Actions: []hermes.Action{
94+
{
95+
Instructions: "Usually this error happens because your webserver is either offline or inaccessible, you can always configure the webhook endpoint on the httpSMS website under the settings page.",
96+
Button: hermes.Button{
97+
Color: "#329ef4",
98+
TextColor: "#FFFFFF",
99+
Text: "Settings",
100+
Link: "https://httpsms.com/settings",
101+
},
102+
},
103+
},
104+
Signature: "Cheers",
105+
Outros: []string{
106+
fmt.Sprintf("Don't hesitate to contact us by replying to this email."),
107+
},
108+
},
109+
}
110+
111+
html, err := factory.generator.GenerateHTML(email)
112+
if err != nil {
113+
return nil, stacktrace.Propagate(err, "cannot generate html email")
114+
}
115+
116+
text, err := factory.generator.GeneratePlainText(email)
117+
if err != nil {
118+
return nil, stacktrace.Propagate(err, "cannot generate text email")
119+
}
120+
121+
return &Email{
122+
ToEmail: user.Email,
123+
Subject: "📢 We could not forward a webhook event to your server",
124+
HTML: html,
125+
Text: text,
126+
}, nil
127+
}
128+
28129
func (factory *hermesNotificationEmailFactory) MessageExpired(user *entities.User, messageID uuid.UUID, owner string, contact string, content string) (*Email, error) {
29130
email := hermes.Email{
30131
Body: hermes.Body{
@@ -68,7 +169,7 @@ func (factory *hermesNotificationEmailFactory) MessageExpired(user *entities.Use
68169

69170
return &Email{
70171
ToEmail: user.Email,
71-
Subject: "🔔 Your SMS message has expired on httpSMS",
172+
Subject: "📢 Your SMS message has expired on httpSMS",
72173
HTML: html,
73174
Text: text,
74175
}, nil
@@ -118,7 +219,7 @@ func (factory *hermesNotificationEmailFactory) MessageFailed(user *entities.User
118219

119220
return &Email{
120221
ToEmail: user.Email,
121-
Subject: " Your SMS message has failed on httpSMS",
222+
Subject: "📢 Your SMS message has failed on httpSMS",
122223
HTML: html,
123224
Text: text,
124225
}, nil

api/pkg/emails/notification_email_factory.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,10 @@ type NotificationEmailFactory interface {
1212

1313
// MessageFailed sends an email when the user's message is failed
1414
MessageFailed(user *entities.User, messageID uuid.UUID, owner, contact, content, reason string) (*Email, error)
15+
16+
// DiscordMessageFailed sends an email when the user's discord message is failed
17+
DiscordMessageFailed(user *entities.User, eventName, owner, errorMessage, channelID string, responseHTTPStatusCode *int) (*Email, error)
18+
19+
// WebhookSendFailed sends an email when the user's webhook message is failed
20+
WebhookSendFailed(user *entities.User, eventName, eventID, owner, errorMessage, url string, responseHTTPStatusCode *int) (*Email, error)
1521
}

api/pkg/events/discord_message_failed_event.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ const EventTypeDiscordMessageFailed = "discord.message.failed"
1010

1111
// DiscordMessageFailedPayload is the payload of the EventTypeDiscordMessageFailed event
1212
type DiscordMessageFailedPayload struct {
13-
DiscordID uuid.UUID `json:"discord_id"`
14-
UserID entities.UserID `json:"user_id"`
15-
MessageID uuid.UUID `json:"message_id"`
16-
EventType string `json:"event_type"`
17-
HTTPStatusCode int `json:"http_status_code"`
18-
ErrorMessage string `json:"error_message"`
19-
DiscordChannelID string `json:"discord_channel_id"`
13+
DiscordID uuid.UUID `json:"discord_id"`
14+
UserID entities.UserID `json:"user_id"`
15+
MessageID uuid.UUID `json:"message_id"`
16+
EventType string `json:"event_type"`
17+
Owner string `json:"owner"`
18+
HTTPResponseStatusCode *int `json:"http_response_status_code"`
19+
ErrorMessage string `json:"error_message"`
20+
DiscordChannelID string `json:"discord_channel_id"`
2021
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package events
2+
3+
import (
4+
"github.com/NdoleStudio/httpsms/pkg/entities"
5+
"github.com/google/uuid"
6+
)
7+
8+
// EventTypeWebhookSendFailed is emitted when we can't send a webhook event
9+
const EventTypeWebhookSendFailed = "webhook.send.failed"
10+
11+
// WebhookSendFailedPayload is the payload of the EventTypeWebhookSendFailed event
12+
type WebhookSendFailedPayload struct {
13+
WebhookID uuid.UUID `json:"webhook_id"`
14+
WebhookURL string `json:"webhook_url"`
15+
Owner string `json:"owner"`
16+
UserID entities.UserID `json:"user_id"`
17+
EventID string `json:"event_id"`
18+
EventType string `json:"event_type"`
19+
HTTPResponseStatusCode *int `json:"http_response_status_code"`
20+
ErrorMessage string `json:"error_message"`
21+
}

api/pkg/services/discord_service.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,23 @@ func (service *DiscordService) sendMessage(ctx context.Context, event cloudevent
248248
if err != nil {
249249
msg := fmt.Sprintf("cannot send [%s] event to discord channel [%s] for user [%s]", event.Type(), discord.IncomingChannelID, discord.UserID)
250250
ctxLogger.Error(service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg)))
251-
service.handleDiscordMessageFailed(ctx, event.Source(), &events.DiscordMessageFailedPayload{
251+
252+
eventPayload := &events.DiscordMessageFailedPayload{
252253
DiscordID: discord.ID,
253254
UserID: discord.UserID,
254255
MessageID: payload.MessageID,
256+
Owner: payload.Owner,
255257
EventType: event.Type(),
256-
HTTPStatusCode: response.HTTPResponse.StatusCode,
257-
ErrorMessage: string(*response.Body),
258+
ErrorMessage: err.Error(),
258259
DiscordChannelID: discord.IncomingChannelID,
259-
})
260+
}
261+
262+
if response != nil {
263+
eventPayload.HTTPResponseStatusCode = &response.HTTPResponse.StatusCode
264+
eventPayload.ErrorMessage = string(*response.Body)
265+
}
266+
267+
service.handleDiscordMessageFailed(ctx, event.Source(), eventPayload)
260268
return
261269
}
262270

0 commit comments

Comments
 (0)