Passed
Push — main ( 203737...4cb1c0 )
by Acho
01:56
created

ageSearch   B

Complexity

Conditions 1

Size

Total Lines 50
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 41
dl 0
loc 50
rs 8.896
c 0
b 0
f 0
nop 2
1
package validators
2
3
import (
4
	"context"
5
	"fmt"
6
	"net/url"
7
	"strings"
8
9
	"github.com/NdoleStudio/httpsms/pkg/repositories"
10
	"github.com/NdoleStudio/httpsms/pkg/services"
11
	"github.com/palantir/stacktrace"
12
13
	"github.com/NdoleStudio/httpsms/pkg/entities"
14
15
	"github.com/NdoleStudio/httpsms/pkg/requests"
16
	"github.com/NdoleStudio/httpsms/pkg/telemetry"
17
	"github.com/thedevsaddam/govalidator"
18
)
19
20
// MessageHandlerValidator validates models used in handlers.MessageHandler
21
type MessageHandlerValidator struct {
22
	validator
23
	logger       telemetry.Logger
24
	tracer       telemetry.Tracer
25
	phoneService *services.PhoneService
26
}
27
28
// NewMessageHandlerValidator creates a new handlers.MessageHandler validator
29
func NewMessageHandlerValidator(
30
	logger telemetry.Logger,
31
	tracer telemetry.Tracer,
32
	phoneService *services.PhoneService,
33
) (v *MessageHandlerValidator) {
34
	return &MessageHandlerValidator{
35
		logger:       logger.WithService(fmt.Sprintf("%T", v)),
36
		tracer:       tracer,
37
		phoneService: phoneService,
38
	}
39
}
40
41
// ValidateMessageReceive validates the requests.MessageReceive request
42
func (validator MessageHandlerValidator) ValidateMessageReceive(_ context.Context, request requests.MessageReceive) url.Values {
43
	v := govalidator.New(govalidator.Options{
44
		Data: &request,
45
		Rules: govalidator.MapData{
46
			"to": []string{
47
				"required",
48
				phoneNumberRule,
49
			},
50
			"from": []string{
51
				"required",
52
			},
53
			"content": []string{
54
				"required",
55
				"min:1",
56
				"max:2048",
57
			},
58
			"sim": []string{
59
				"required",
60
				"in:" + strings.Join([]string{
61
					string(entities.SIM1),
62
					string(entities.SIM2),
63
				}, ","),
64
			},
65
		},
66
	})
67
68
	return v.ValidateStruct()
69
}
70
71
// ValidateMessageSend validates the requests.MessageSend request
72
func (validator MessageHandlerValidator) ValidateMessageSend(ctx context.Context, userID entities.UserID, request requests.MessageSend) url.Values {
73
	ctx, span := validator.tracer.Start(ctx)
74
	defer span.End()
75
76
	ctxLogger := validator.tracer.CtxLogger(validator.logger, span)
77
78
	v := govalidator.New(govalidator.Options{
79
		Data: &request,
80
		Rules: govalidator.MapData{
81
			"to": []string{
82
				"required",
83
				contactPhoneNumberRule,
84
			},
85
			"request_id": []string{
86
				"max:255",
87
			},
88
			"from": []string{
89
				"required",
90
				phoneNumberRule,
91
			},
92
			"content": []string{
93
				"required",
94
				"min:1",
95
				"max:2048",
96
			},
97
		},
98
	})
99
100
	result := v.ValidateStruct()
101
	if len(result) != 0 {
102
		return result
103
	}
104
105
	_, err := validator.phoneService.Load(ctx, userID, request.From)
106
	if stacktrace.GetCode(err) == repositories.ErrCodeNotFound {
107
		result.Add("from", fmt.Sprintf("no phone found with with 'from' number [%s]. install the android app on your phone to start sending messages", request.From))
108
	}
109
110
	if err != nil {
111
		ctxLogger.Error(validator.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, fmt.Sprintf("could not load phone for user [%s] and phone [%s]", userID, request.From))))
112
		result.Add("from", fmt.Sprintf("could not validate 'from' number [%s], please try again later", request.From))
113
	}
114
115
	return result
116
}
117
118
// ValidateMessageBulkSend validates the requests.MessageBulkSend request
119
func (validator MessageHandlerValidator) ValidateMessageBulkSend(ctx context.Context, userID entities.UserID, request requests.MessageBulkSend) url.Values {
120
	ctx, span := validator.tracer.Start(ctx)
121
	defer span.End()
122
123
	ctxLogger := validator.tracer.CtxLogger(validator.logger, span)
124
125
	v := govalidator.New(govalidator.Options{
126
		Data: &request,
127
		Rules: govalidator.MapData{
128
			"to": []string{
129
				"required",
130
				"max:1000",
131
				"min:1",
132
				multipleContactPhoneNumberRule,
133
			},
134
			"from": []string{
135
				"required",
136
				phoneNumberRule,
137
			},
138
			"content": []string{
139
				"required",
140
				"min:1",
141
				"max:1024",
142
			},
143
		},
144
	})
145
146
	result := v.ValidateStruct()
147
	if len(result) != 0 {
148
		return result
149
	}
150
151
	_, err := validator.phoneService.Load(ctx, userID, request.From)
152
	if stacktrace.GetCode(err) == repositories.ErrCodeNotFound {
153
		result.Add("from", fmt.Sprintf("no phone found with with 'from' number [%s]. Install the android app on your phone to start sending messages", request.From))
154
	}
155
156
	if err != nil {
157
		ctxLogger.Error(validator.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, fmt.Sprintf("could not load phone for user [%s] and phone [%s]", userID, request.From))))
158
		result.Add("from", fmt.Sprintf("could not validate 'from' number [%s], please try again later", request.From))
159
	}
160
161
	return result
162
}
163
164
// ValidateMessageOutstanding validates the requests.MessageOutstanding request
165
func (validator MessageHandlerValidator) ValidateMessageOutstanding(_ context.Context, request requests.MessageOutstanding) url.Values {
166
	v := govalidator.New(govalidator.Options{
167
		Data: &request,
168
		Rules: govalidator.MapData{
169
			"message_id": []string{
170
				"required",
171
				"uuid",
172
			},
173
		},
174
	})
175
	return v.ValidateStruct()
176
}
177
178
// ValidateMessageIndex validates the requests.MessageIndex request
179
func (validator MessageHandlerValidator) ValidateMessageIndex(_ context.Context, request requests.MessageIndex) url.Values {
180
	v := govalidator.New(govalidator.Options{
181
		Data: &request,
182
		Rules: govalidator.MapData{
183
			"limit": []string{
184
				"required",
185
				"numeric",
186
				"min:1",
187
				"max:20",
188
			},
189
			"skip": []string{
190
				"required",
191
				"numeric",
192
				"min:0",
193
			},
194
			"contact": []string{
195
				"required",
196
				"min:1",
197
			},
198
			"query": []string{
199
				"max:100",
200
			},
201
			"owner": []string{
202
				"required",
203
				phoneNumberRule,
204
			},
205
		},
206
	})
207
	return v.ValidateStruct()
208
}
209
210
// ValidateMessageSearch validates the requests.MessageSearch request
211
func (validator MessageHandlerValidator) ValidateMessageSearch(_ context.Context, request requests.MessageSearch) url.Values {
212
	v := govalidator.New(govalidator.Options{
213
		Data: &request,
214
		Rules: govalidator.MapData{
215
			"owners": []string{
216
				multipleContactPhoneNumberRule,
217
			},
218
			"types": []string{
219
				multipleInRule + ":" + strings.Join([]string{
220
					entities.MessageTypeCallMissed,
221
					entities.MessageTypeMobileOriginated,
222
					entities.MessageTypeMobileTerminated,
223
				}, ","),
224
			},
225
			"statuses": []string{
226
				multipleInRule + ":" + strings.Join([]string{
227
					entities.MessageStatusPending,
228
					entities.MessageStatusSent,
229
					entities.MessageStatusDelivered,
230
					entities.MessageStatusFailed,
231
					entities.MessageStatusExpired,
232
					entities.MessageStatusReceived,
233
				}, ","),
234
			},
235
			"sort_by": []string{
236
				"in:" + strings.Join([]string{
237
					"created_at",
238
					"owner",
239
					"contact",
240
					"type",
241
					"status",
242
				}, ","),
243
			},
244
			"limit": []string{
245
				"required",
246
				"numeric",
247
				"min:1",
248
				"max:200",
249
			},
250
			"skip": []string{
251
				"required",
252
				"numeric",
253
				"min:0",
254
			},
255
			"query": []string{
256
				"max:100",
257
			},
258
		},
259
	})
260
	return v.ValidateStruct()
261
}
262
263
// ValidateMessageEvent validates the requests.MessageEvent request
264
func (validator MessageHandlerValidator) ValidateMessageEvent(_ context.Context, request requests.MessageEvent) url.Values {
265
	v := govalidator.New(govalidator.Options{
266
		Data: &request,
267
		Rules: govalidator.MapData{
268
			"event_name": []string{
269
				"required",
270
				"in:" + strings.Join([]string{
271
					string(entities.MessageEventNameSent),
272
					string(entities.MessageEventNameFailed),
273
					string(entities.MessageEventNameDelivered),
274
				}, ","),
275
			},
276
			"messageID": []string{
277
				"required",
278
				"uuid",
279
			},
280
		},
281
	})
282
	return v.ValidateStruct()
283
}
284
285
// ValidateCallMissed validates the requests.MessageCallMissed request
286
func (validator MessageHandlerValidator) ValidateCallMissed(_ context.Context, request requests.MessageCallMissed) url.Values {
287
	v := govalidator.New(govalidator.Options{
288
		Data: &request,
289
		Rules: govalidator.MapData{
290
			"to": []string{
291
				"required",
292
				phoneNumberRule,
293
			},
294
			"from": []string{
295
				"required",
296
			},
297
			"sim": []string{
298
				"required",
299
				"in:" + strings.Join([]string{
300
					string(entities.SIM1),
301
					string(entities.SIM2),
302
				}, ","),
303
			},
304
		},
305
	})
306
307
	return v.ValidateStruct()
308
}
309