forked from nyaruka/courier
-
Notifications
You must be signed in to change notification settings - Fork 0
/
responses.go
176 lines (150 loc) · 5.95 KB
/
responses.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package courier
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"github.com/nyaruka/gocommon/urns"
validator "gopkg.in/go-playground/validator.v9"
)
const statusMsgNotFoundDetail = "message not found, ignored"
// writeAndLogRequestError writes a JSON response for the passed in message and logs an info messages
func writeAndLogRequestError(ctx context.Context, w http.ResponseWriter, r *http.Request, c Channel, err error) error {
LogRequestError(r, c, err)
return WriteError(ctx, w, r, err)
}
// WriteError writes a JSON response for the passed in error
func WriteError(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) error {
errors := []interface{}{NewErrorData(err.Error())}
vErrs, isValidation := err.(validator.ValidationErrors)
if isValidation {
for i := range vErrs {
errors = append(errors, NewErrorData(fmt.Sprintf("field '%s' %s", strings.ToLower(vErrs[i].Field()), vErrs[i].Tag())))
}
}
return WriteDataResponse(ctx, w, http.StatusBadRequest, "Error", errors)
}
// WriteIgnored writes a JSON response indicating that we ignored the request
func WriteIgnored(ctx context.Context, w http.ResponseWriter, r *http.Request, details string) error {
return WriteDataResponse(ctx, w, http.StatusOK, "Ignored", []interface{}{NewInfoData(details)})
}
// WriteAndLogUnauthorized writes a JSON response for the passed in message and logs an info message
func WriteAndLogUnauthorized(ctx context.Context, w http.ResponseWriter, r *http.Request, c Channel, err error) error {
LogRequestError(r, c, err)
return WriteDataResponse(ctx, w, http.StatusUnauthorized, "Unauthorized", []interface{}{NewErrorData(err.Error())})
}
// WriteChannelEventSuccess writes a JSON response for the passed in event indicating we handled it
func WriteChannelEventSuccess(ctx context.Context, w http.ResponseWriter, r *http.Request, event ChannelEvent) error {
return WriteDataResponse(ctx, w, http.StatusOK, "Event Accepted", []interface{}{NewEventReceiveData(event)})
}
// WriteMsgSuccess writes a JSON response for the passed in msg indicating we handled it
func WriteMsgSuccess(ctx context.Context, w http.ResponseWriter, r *http.Request, msgs []Msg) error {
data := []interface{}{}
for _, msg := range msgs {
data = append(data, NewMsgReceiveData(msg))
}
return WriteDataResponse(ctx, w, http.StatusOK, "Message Accepted", data)
}
// WriteStatusSuccess writes a JSON response for the passed in status update indicating we handled it
func WriteStatusSuccess(ctx context.Context, w http.ResponseWriter, r *http.Request, statuses []MsgStatus) error {
data := []interface{}{}
for _, status := range statuses {
data = append(data, NewStatusData(status))
}
return WriteDataResponse(ctx, w, http.StatusOK, "Status Update Accepted", data)
}
// WriteDataResponse writes a JSON formatted response with the passed in status code, message and data
func WriteDataResponse(ctx context.Context, w http.ResponseWriter, statusCode int, message string, data []interface{}) error {
return writeJSONResponse(ctx, w, statusCode, &dataResponse{message, data})
}
// MsgReceiveData is our response payload for a received message
type MsgReceiveData struct {
Type string `json:"type"`
ChannelUUID ChannelUUID `json:"channel_uuid"`
MsgUUID MsgUUID `json:"msg_uuid"`
Text string `json:"text"`
URN urns.URN `json:"urn"`
Attachments []string `json:"attachments,omitempty"`
ExternalID string `json:"external_id,omitempty"`
ReceivedOn *time.Time `json:"received_on,omitempty"`
}
// NewMsgReceiveData creates a new data response for the passed in msg parameters
func NewMsgReceiveData(msg Msg) MsgReceiveData {
return MsgReceiveData{
"msg",
msg.Channel().UUID(),
msg.UUID(),
msg.Text(),
msg.URN(),
msg.Attachments(),
msg.ExternalID(),
msg.ReceivedOn(),
}
}
// EventReceiveData is our response payload for a channel event
type EventReceiveData struct {
Type string `json:"type"`
ChannelUUID ChannelUUID `json:"channel_uuid"`
EventType ChannelEventType `json:"event_type"`
URN urns.URN `json:"urn"`
ReceivedOn time.Time `json:"received_on"`
Extra map[string]interface{} `json:"extra,omitempty"`
}
// NewEventReceiveData creates a new receive data for the passed in event
func NewEventReceiveData(event ChannelEvent) EventReceiveData {
return EventReceiveData{
"event",
event.ChannelUUID(),
event.EventType(),
event.URN(),
event.OccurredOn(),
event.Extra(),
}
}
// StatusData is our response payload for a status update
type StatusData struct {
Type string `json:"type"`
ChannelUUID ChannelUUID `json:"channel_uuid"`
Status MsgStatusValue `json:"status"`
MsgID MsgID `json:"msg_id,omitempty"`
ExternalID string `json:"external_id,omitempty"`
}
// NewStatusData creates a new status data object for the passed in status
func NewStatusData(status MsgStatus) StatusData {
return StatusData{
"status",
status.ChannelUUID(),
status.Status(),
status.ID(),
status.ExternalID(),
}
}
// ErrorData is our response payload for an error
type ErrorData struct {
Type string `json:"type"`
Error string `json:"error"`
}
// NewErrorData creates a new data segment for the passed in error string
func NewErrorData(err string) ErrorData {
return ErrorData{"error", err}
}
// InfoData is our response payload for an informational message
type InfoData struct {
Type string `json:"type"`
Info string `json:"info"`
}
// NewInfoData creates a new data segment for the passed in info string
func NewInfoData(info string) InfoData {
return InfoData{"info", info}
}
type dataResponse struct {
Message string `json:"message"`
Data []interface{} `json:"data"`
}
func writeJSONResponse(ctx context.Context, w http.ResponseWriter, statusCode int, response interface{}) error {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
return json.NewEncoder(w).Encode(response)
}