Skip to content

Commit 18dabe5

Browse files
committed
[handlers] separate message status DTOs
1 parent 26e205d commit 18dabe5

File tree

9 files changed

+264
-155
lines changed

9 files changed

+264
-155
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ toolchain go1.23.2
66

77
require (
88
firebase.google.com/go/v4 v4.12.1
9-
github.com/android-sms-gateway/client-go v1.8.2
9+
github.com/android-sms-gateway/client-go v1.8.3-0.20250708235905-d5c9b879467b
1010
github.com/ansrivas/fiberprometheus/v2 v2.6.1
1111
github.com/capcom6/go-helpers v0.3.0
1212
github.com/capcom6/go-infra-fx v0.2.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ github.com/android-sms-gateway/client-go v1.8.2-0.20250703013756-220a21ca308a h1
3030
github.com/android-sms-gateway/client-go v1.8.2-0.20250703013756-220a21ca308a/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
3131
github.com/android-sms-gateway/client-go v1.8.2 h1:uywKRE9j1UL+u9e8k4MDg7qri0RFN+4lSdR9ZYd7vSo=
3232
github.com/android-sms-gateway/client-go v1.8.2/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
33+
github.com/android-sms-gateway/client-go v1.8.3-0.20250708235905-d5c9b879467b h1:1gbDvRyHzSx3A9l9A1G1xPIcHjswLoi3Q5/5W1Izn4s=
34+
github.com/android-sms-gateway/client-go v1.8.3-0.20250708235905-d5c9b879467b/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
3335
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
3436
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
3537
github.com/ansrivas/fiberprometheus/v2 v2.6.1 h1:wac3pXaE6BYYTF04AC6K0ktk6vCD+MnDOJZ3SK66kXM=

internal/sms-gateway/handlers/messages/3rdparty.go

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,16 @@ type ThirdPartyController struct {
4545
// @Tags User, Messages
4646
// @Accept json
4747
// @Produce json
48-
// @Param skipPhoneValidation query bool false "Skip phone validation"
49-
// @Param deviceActiveWithin query int false "Filter devices active within the specified number of hours" default(0)
50-
// @Param request body smsgateway.Message true "Send message request"
51-
// @Success 202 {object} smsgateway.MessageState "Message enqueued"
52-
// @Failure 400 {object} smsgateway.ErrorResponse "Invalid request"
53-
// @Failure 401 {object} smsgateway.ErrorResponse "Unauthorized"
54-
// @Failure 409 {object} smsgateway.ErrorResponse "Message with such ID already exists"
55-
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
56-
// @Header 202 {string} Location "Get message state URL"
57-
// @Router /3rdparty/v1/messages [post]
48+
// @Param skipPhoneValidation query bool false "Skip phone validation"
49+
// @Param deviceActiveWithin query int false "Filter devices active within the specified number of hours" default(0)
50+
// @Param request body smsgateway.Message true "Send message request"
51+
// @Success 202 {object} smsgateway.GetMessageResponse "Message enqueued"
52+
// @Failure 400 {object} smsgateway.ErrorResponse "Invalid request"
53+
// @Failure 401 {object} smsgateway.ErrorResponse "Unauthorized"
54+
// @Failure 409 {object} smsgateway.ErrorResponse "Message with such ID already exists"
55+
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
56+
// @Header 202 {string} Location "Get message state URL"
57+
// @Router /3rdparty/v1/messages [post]
5858
//
5959
// Enqueue message
6060
func (h *ThirdPartyController) post(user models.User, c *fiber.Ctx) error {
@@ -157,20 +157,29 @@ func (h *ThirdPartyController) post(user models.User, c *fiber.Ctx) error {
157157
c.Location(location)
158158
}
159159

160-
return c.Status(fiber.StatusAccepted).JSON(state)
160+
return c.Status(fiber.StatusAccepted).
161+
JSON(smsgateway.GetMessageResponse{
162+
ID: state.ID,
163+
DeviceID: state.DeviceID,
164+
State: smsgateway.ProcessingState(state.State),
165+
IsHashed: state.IsHashed,
166+
IsEncrypted: state.IsEncrypted,
167+
Recipients: state.Recipients,
168+
States: state.States,
169+
})
161170
}
162171

163172
// @Summary Get message state
164173
// @Description Returns message state by ID
165174
// @Security ApiAuth
166175
// @Tags User, Messages
167176
// @Produce json
168-
// @Param id path string true "Message ID"
169-
// @Success 200 {object} smsgateway.MessageState "Message state"
170-
// @Failure 400 {object} smsgateway.ErrorResponse "Invalid request"
171-
// @Failure 401 {object} smsgateway.ErrorResponse "Unauthorized"
172-
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
173-
// @Router /3rdparty/v1/messages/{id} [get]
177+
// @Param id path string true "Message ID"
178+
// @Success 200 {object} smsgateway.GetMessageResponse "Message state"
179+
// @Failure 400 {object} smsgateway.ErrorResponse "Invalid request"
180+
// @Failure 401 {object} smsgateway.ErrorResponse "Unauthorized"
181+
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
182+
// @Router /3rdparty/v1/messages/{id} [get]
174183
//
175184
// Get message state
176185
func (h *ThirdPartyController) get(user models.User, c *fiber.Ctx) error {
@@ -185,7 +194,15 @@ func (h *ThirdPartyController) get(user models.User, c *fiber.Ctx) error {
185194
return err
186195
}
187196

188-
return c.JSON(state)
197+
return c.JSON(smsgateway.GetMessageResponse{
198+
ID: state.ID,
199+
DeviceID: state.DeviceID,
200+
State: smsgateway.ProcessingState(state.State),
201+
IsHashed: state.IsHashed,
202+
IsEncrypted: state.IsEncrypted,
203+
Recipients: state.Recipients,
204+
States: state.States,
205+
})
189206
}
190207

191208
// @Summary Request inbox messages export
@@ -199,7 +216,7 @@ func (h *ThirdPartyController) get(user models.User, c *fiber.Ctx) error {
199216
// @Failure 400 {object} smsgateway.ErrorResponse "Invalid request"
200217
// @Failure 401 {object} smsgateway.ErrorResponse "Unauthorized"
201218
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
202-
// @Router /3rdparty/v1/inbox/export [post]
219+
// @Router /3rdparty/v1/inbox/export [post]
203220
//
204221
// Export inbox
205222
func (h *ThirdPartyController) postInboxExport(user models.User, c *fiber.Ctx) error {

internal/sms-gateway/handlers/mobile.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -182,25 +182,27 @@ func (h *mobileHandler) getMessage(device models.Device, c *fiber.Ctx) error {
182182
// @Tags Device, Messages
183183
// @Accept json
184184
// @Produce json
185-
// @Param request body []smsgateway.MessageState true "New message state"
186-
// @Success 204 {object} nil "Successfully updated"
187-
// @Failure 400 {object} smsgateway.ErrorResponse "Invalid request"
188-
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
185+
// @Param request body smsgateway.MobilePatchMessageRequest true "New message state"
186+
// @Success 204 {object} nil "Successfully updated"
187+
// @Failure 400 {object} smsgateway.ErrorResponse "Invalid request"
188+
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
189189
// @Router /mobile/v1/message [patch]
190190
//
191191
// Update message state
192192
func (h *mobileHandler) patchMessage(device models.Device, c *fiber.Ctx) error {
193-
req := []smsgateway.MessageState{}
193+
var req smsgateway.MobilePatchMessageRequest
194194
if err := c.BodyParser(&req); err != nil {
195195
return fiber.NewError(fiber.StatusBadRequest, err.Error())
196196
}
197197

198+
var messageState messages.MessageStateIn
198199
for _, v := range req {
199-
if err := h.ValidateStruct(v); err != nil {
200-
return fiber.NewError(fiber.StatusBadRequest, err.Error())
201-
}
200+
messageState.ID = v.ID
201+
messageState.State = messages.ProcessingState(v.State)
202+
messageState.Recipients = v.Recipients
203+
messageState.States = v.States
202204

203-
err := h.messagesSvc.UpdateState(device.ID, v)
205+
err := h.messagesSvc.UpdateState(device.ID, messageState)
204206
if err != nil && !errors.Is(err, messages.ErrMessageNotFound) {
205207
h.Logger.Error("Can't update message status", zap.Error(err))
206208
}

internal/sms-gateway/modules/messages/domain.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,25 @@ type MessageOut struct {
2727

2828
CreatedAt time.Time
2929
}
30+
31+
type MessageStateIn struct {
32+
// Message ID
33+
ID string
34+
// State
35+
State ProcessingState
36+
// Recipients states
37+
Recipients []smsgateway.RecipientState
38+
// History of states
39+
States map[string]time.Time
40+
}
41+
42+
type MessageStateOut struct {
43+
// Device ID
44+
DeviceID string
45+
// Hashed
46+
IsHashed bool
47+
// Encrypted
48+
IsEncrypted bool
49+
50+
MessageStateIn
51+
}

internal/sms-gateway/modules/messages/service.go

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -104,17 +104,17 @@ func (s *Service) SelectPending(deviceID string) ([]MessageOut, error) {
104104
return slices.MapOrError(messages, messageToDomain)
105105
}
106106

107-
func (s *Service) UpdateState(deviceID string, message smsgateway.MessageState) error {
107+
func (s *Service) UpdateState(deviceID string, message MessageStateIn) error {
108108
existing, err := s.messages.Get(message.ID, MessagesSelectFilter{DeviceID: deviceID})
109109
if err != nil {
110110
return err
111111
}
112112

113-
if message.State == smsgateway.ProcessingStatePending {
114-
message.State = smsgateway.ProcessingStateProcessed
113+
if message.State == ProcessingStatePending {
114+
message.State = ProcessingStateProcessed
115115
}
116116

117-
existing.State = ProcessingState(message.State)
117+
existing.State = message.State
118118
existing.States = slices.Map(maps.Keys(message.States), func(key string) MessageState {
119119
return MessageState{
120120
MessageID: existing.ID,
@@ -135,28 +135,30 @@ func (s *Service) UpdateState(deviceID string, message smsgateway.MessageState)
135135
return nil
136136
}
137137

138-
func (s *Service) GetState(user models.User, ID string) (smsgateway.MessageState, error) {
138+
func (s *Service) GetState(user models.User, ID string) (MessageStateOut, error) {
139139
message, err := s.messages.Get(
140140
ID,
141141
MessagesSelectFilter{},
142142
MessagesSelectOptions{WithRecipients: true, WithDevice: true, WithStates: true},
143143
)
144144
if err != nil {
145-
return smsgateway.MessageState{}, ErrMessageNotFound
145+
return MessageStateOut{}, ErrMessageNotFound
146146
}
147147

148148
if message.Device.UserID != user.ID {
149-
return smsgateway.MessageState{}, ErrMessageNotFound
149+
return MessageStateOut{}, ErrMessageNotFound
150150
}
151151

152152
return modelToMessageState(message), nil
153153
}
154154

155-
func (s *Service) Enqueue(device models.Device, message MessageIn, opts EnqueueOptions) (smsgateway.MessageState, error) {
156-
state := smsgateway.MessageState{
157-
DeviceID: device.ID,
158-
State: smsgateway.ProcessingStatePending,
159-
Recipients: make([]smsgateway.RecipientState, len(message.PhoneNumbers)),
155+
func (s *Service) Enqueue(device models.Device, message MessageIn, opts EnqueueOptions) (MessageStateOut, error) {
156+
state := MessageStateOut{
157+
DeviceID: device.ID,
158+
MessageStateIn: MessageStateIn{
159+
State: ProcessingStatePending,
160+
Recipients: make([]smsgateway.RecipientState, len(message.PhoneNumbers)),
161+
},
160162
}
161163

162164
var phone string
@@ -293,19 +295,22 @@ func (s *Service) recipientsStateToModel(input []smsgateway.RecipientState, hash
293295
return output
294296
}
295297

296-
func modelToMessageState(input Message) smsgateway.MessageState {
297-
return smsgateway.MessageState{
298-
ID: input.ExtID,
298+
func modelToMessageState(input Message) MessageStateOut {
299+
return MessageStateOut{
299300
DeviceID: input.DeviceID,
300-
State: smsgateway.ProcessingState(input.State),
301301
IsHashed: input.IsHashed,
302302
IsEncrypted: input.IsEncrypted,
303-
Recipients: slices.Map(input.Recipients, modelToRecipientState),
304-
States: slices.Associate(
305-
input.States,
306-
func(state MessageState) string { return string(state.State) },
307-
func(state MessageState) time.Time { return state.UpdatedAt },
308-
),
303+
304+
MessageStateIn: MessageStateIn{
305+
ID: input.ExtID,
306+
State: input.State,
307+
Recipients: slices.Map(input.Recipients, modelToRecipientState),
308+
States: slices.Associate(
309+
input.States,
310+
func(state MessageState) string { return string(state.State) },
311+
func(state MessageState) time.Time { return state.UpdatedAt },
312+
),
313+
},
309314
}
310315
}
311316

pkg/swagger/docs/mobile.http

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Content-Type: application/json
4343

4444
[
4545
{
46-
"id": "2dcIAhcLg81cez7GE_Pdp",
46+
"id": "NBjsgnVp72pvcdonJm7a5",
4747
"state": "Failed",
4848
"recipients": [
4949
{

0 commit comments

Comments
 (0)