diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 2b61892..f83081a 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: WhatsApp API MultiDevice - version: 3.0.0 + version: 3.1.0 description: This API is used for sending whatsapp via API servers: - url: http://localhost:3000 @@ -566,6 +566,49 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorInternalServer' + /send/location: + post: + operationId: sendLocation + tags: + - message + summary: Send Location + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + phone: + type: integer + example: '6289685024051@s.whatsapp.net' + description: Phone number with country code + latitude: + type: string + example: "-7.797068" + description: Latitude coordinate + longitude: + type: string + example: '110.370529' + description: Longitude coordinate + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/SendResponse' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBadRequest' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorInternalServer' /message/:message_id/revoke: post: operationId: revokeMessage diff --git a/readme.md b/readme.md index b2b2eb5..367ff35 100644 --- a/readme.md +++ b/readme.md @@ -107,7 +107,8 @@ API using [openapi-generator](https://openapi-generator.tech/#try) | ✅ | Send Video | POST | /send/video | | ✅ | Send Contact | POST | /send/contact | | ✅ | Send Link | POST | /send/link | -| ✅ | Revoke Messave | POST | /message/:message_id/revoke | +| ✅ | Send Location | POST | /send/location | +| ✅ | Revoke Message | POST | /message/:message_id/revoke | ``` ✅ = Available @@ -116,20 +117,21 @@ API using [openapi-generator](https://openapi-generator.tech/#try) ### App User Interface -1. Homepage  +1. Homepage  2. Login  -3. Send Message  -4. Send Image  -5. Send File  -6. Send Video  +3. Send Message  +4. Send Image  +5. Send File  +6. Send Video  7. Send Contact  -8. Revoke Message  -9. User Info  -10. User Avatar  -11. My Privacy  -12. My Group  -13. Auto Reply  -14. Basic Auth Prompt  +8. Send Location  +9. Revoke Message  +10. User Info  +11. User Avatar  +12. My Privacy  +13. My Group  +14. Auto Reply  +15. Basic Auth Prompt  ### Mac OS NOTE diff --git a/src/config/settings.go b/src/config/settings.go index 5e9989d..094a56f 100644 --- a/src/config/settings.go +++ b/src/config/settings.go @@ -6,7 +6,7 @@ import ( ) var ( - AppVersion = "v4.2.0" + AppVersion = "v4.3.0" AppPort = "3000" AppDebug = false AppOs = fmt.Sprintf("AldinoKemal") diff --git a/src/domains/send/location.go b/src/domains/send/location.go new file mode 100644 index 0000000..a577f4d --- /dev/null +++ b/src/domains/send/location.go @@ -0,0 +1,12 @@ +package send + +type LocationRequest struct { + Phone string `json:"phone" form:"phone"` + Latitude string `json:"latitude" form:"latitude"` + Longitude string `json:"longitude" form:"longitude"` +} + +type LocationResponse struct { + MessageID string `json:"message_id"` + Status string `json:"status"` +} diff --git a/src/domains/send/send.go b/src/domains/send/send.go index c6fe122..ddcc0b0 100644 --- a/src/domains/send/send.go +++ b/src/domains/send/send.go @@ -11,6 +11,7 @@ type ISendService interface { SendVideo(ctx context.Context, request VideoRequest) (response VideoResponse, err error) SendContact(ctx context.Context, request ContactRequest) (response ContactResponse, err error) SendLink(ctx context.Context, request LinkRequest) (response LinkResponse, err error) + SendLocation(ctx context.Context, request LocationRequest) (response LocationResponse, err error) Revoke(ctx context.Context, request RevokeRequest) (response RevokeResponse, err error) UpdateMessage(ctx context.Context, request UpdateMessageRequest) (response UpdateMessageResponse, err error) } diff --git a/src/internal/rest/send.go b/src/internal/rest/send.go index 5de40e7..7872427 100644 --- a/src/internal/rest/send.go +++ b/src/internal/rest/send.go @@ -19,6 +19,7 @@ func InitRestSend(app *fiber.App, service domainSend.ISendService) Send { app.Post("/send/video", rest.SendVideo) app.Post("/send/contact", rest.SendContact) app.Post("/send/link", rest.SendLink) + app.Post("/send/location", rest.SendLocation) app.Post("/message/:message_id/revoke", rest.RevokeMessage) app.Post("/message/:message_id/update", rest.UpdateMessage) return rest @@ -140,6 +141,23 @@ func (controller *Send) SendLink(c *fiber.Ctx) error { }) } +func (controller *Send) SendLocation(c *fiber.Ctx) error { + var request domainSend.LocationRequest + err := c.BodyParser(&request) + utils.PanicIfNeeded(err) + + whatsapp.SanitizePhone(&request.Phone) + + response, err := controller.Service.SendLocation(c.UserContext(), request) + utils.PanicIfNeeded(err) + + return c.JSON(utils.ResponseData{ + Status: 200, + Message: response.Status, + Results: response, + }) +} + func (controller *Send) RevokeMessage(c *fiber.Ctx) error { var request domainSend.RevokeRequest err := c.BodyParser(&request) diff --git a/src/pkg/utils/general.go b/src/pkg/utils/general.go index 133ac22..a1a96ac 100644 --- a/src/pkg/utils/general.go +++ b/src/pkg/utils/general.go @@ -4,6 +4,8 @@ import ( "fmt" "os" "path/filepath" + "strconv" + "strings" "time" ) @@ -46,3 +48,11 @@ func PanicIfNeeded(err any, message ...string) { } } } + +func StrToFloat64(text string) float64 { + var result float64 + if text != "" { + result, _ = strconv.ParseFloat(strings.TrimSpace(text), 64) + } + return result +} diff --git a/src/pkg/whatsapp/whatsapp.go b/src/pkg/whatsapp/whatsapp.go index f0f2213..ad1f0a8 100644 --- a/src/pkg/whatsapp/whatsapp.go +++ b/src/pkg/whatsapp/whatsapp.go @@ -240,7 +240,7 @@ func handler(rawEvt interface{}) { } case *events.HistorySync: id := atomic.AddInt32(&historySyncID, 1) - fileName := fmt.Sprintf("%s/history-%d-%d.json", config.PathStorages, startupTime, id) + fileName := fmt.Sprintf("%s/history-%d-%s-%d-%s.json", config.PathStorages, startupTime, cli.Store.ID.String(), id, evt.Data.SyncType.String()) file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0600) if err != nil { log.Errorf("Failed to open file to write history sync: %v", err) diff --git a/src/services/app.go b/src/services/app.go index 04fed66..8ec0bd8 100644 --- a/src/services/app.go +++ b/src/services/app.go @@ -12,6 +12,7 @@ import ( "go.mau.fi/whatsmeow/store/sqlstore" "os" "path/filepath" + "strings" "time" ) @@ -86,7 +87,7 @@ func (service serviceApp) Login(_ context.Context) (response domainApp.LoginResp func (service serviceApp) Logout(_ context.Context) (err error) { // delete history - files, err := filepath.Glob("./history-*") + files, err := filepath.Glob(fmt.Sprintf("./%s/history-*", config.PathStorages)) if err != nil { return err } @@ -98,7 +99,7 @@ func (service serviceApp) Logout(_ context.Context) (err error) { } } // delete qr images - qrImages, err := filepath.Glob("./statics/images/qrcode/scan-*") + qrImages, err := filepath.Glob(fmt.Sprintf("./%s/scan-*", config.PathQrCode)) if err != nil { return err } @@ -110,6 +111,21 @@ func (service serviceApp) Logout(_ context.Context) (err error) { } } + // delete senditems + qrItems, err := filepath.Glob(fmt.Sprintf("./%s/*", config.PathSendItems)) + if err != nil { + return err + } + + for _, f := range qrItems { + if !strings.Contains(f, ".gitignore") { + err = os.Remove(f) + if err != nil { + return err + } + } + } + err = service.WaCli.Logout() return } diff --git a/src/services/send.go b/src/services/send.go index e7eb7a2..eae34d4 100644 --- a/src/services/send.go +++ b/src/services/send.go @@ -32,7 +32,7 @@ func NewSendService(waCli *whatsmeow.Client) domainSend.ISendService { } func (service serviceSend) SendText(ctx context.Context, request domainSend.MessageRequest) (response domainSend.MessageResponse, err error) { - err = validations.ValidateSendMessage(request) + err = validations.ValidateSendMessage(ctx, request) if err != nil { return response, err } @@ -54,7 +54,7 @@ func (service serviceSend) SendText(ctx context.Context, request domainSend.Mess } func (service serviceSend) SendImage(ctx context.Context, request domainSend.ImageRequest) (response domainSend.ImageResponse, err error) { - err = validations.ValidateSendImage(request) + err = validations.ValidateSendImage(ctx, request) if err != nil { return response, err } @@ -152,7 +152,7 @@ func (service serviceSend) SendImage(ctx context.Context, request domainSend.Ima } func (service serviceSend) SendFile(ctx context.Context, request domainSend.FileRequest) (response domainSend.FileResponse, err error) { - err = validations.ValidateSendFile(request) + err = validations.ValidateSendFile(ctx, request) if err != nil { return response, err } @@ -207,7 +207,7 @@ func (service serviceSend) SendFile(ctx context.Context, request domainSend.File } func (service serviceSend) SendVideo(ctx context.Context, request domainSend.VideoRequest) (response domainSend.VideoResponse, err error) { - err = validations.ValidateSendVideo(request) + err = validations.ValidateSendVideo(ctx, request) if err != nil { return response, err } @@ -286,20 +286,23 @@ func (service serviceSend) SendVideo(ctx context.Context, request domainSend.Vid msgId := whatsmeow.GenerateMessageID() msg := &waProto.Message{VideoMessage: &waProto.VideoMessage{ - Url: proto.String(uploaded.URL), - Mimetype: proto.String(http.DetectContentType(dataWaVideo)), - Caption: proto.String(request.Caption), - FileLength: proto.Uint64(uploaded.FileLength), - FileSha256: uploaded.FileSHA256, - FileEncSha256: uploaded.FileEncSHA256, - MediaKey: uploaded.MediaKey, - DirectPath: proto.String(uploaded.DirectPath), - ViewOnce: proto.Bool(request.ViewOnce), - JpegThumbnail: dataWaThumbnail, + Url: proto.String(uploaded.URL), + Mimetype: proto.String(http.DetectContentType(dataWaVideo)), + Caption: proto.String(request.Caption), + FileLength: proto.Uint64(uploaded.FileLength), + FileSha256: uploaded.FileSHA256, + FileEncSha256: uploaded.FileEncSHA256, + MediaKey: uploaded.MediaKey, + DirectPath: proto.String(uploaded.DirectPath), + ViewOnce: proto.Bool(request.ViewOnce), + JpegThumbnail: dataWaThumbnail, + ThumbnailEncSha256: dataWaThumbnail, + ThumbnailSha256: dataWaThumbnail, + ThumbnailDirectPath: proto.String(uploaded.DirectPath), }} ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msgId, msg) go func() { - errDelete := utils.RemoveFile(0, deletedItems...) + errDelete := utils.RemoveFile(1, deletedItems...) if errDelete != nil { fmt.Println(errDelete) } @@ -314,7 +317,7 @@ func (service serviceSend) SendVideo(ctx context.Context, request domainSend.Vid } func (service serviceSend) SendContact(ctx context.Context, request domainSend.ContactRequest) (response domainSend.ContactResponse, err error) { - err = validations.ValidateSendContact(request) + err = validations.ValidateSendContact(ctx, request) if err != nil { return response, err } @@ -341,7 +344,7 @@ func (service serviceSend) SendContact(ctx context.Context, request domainSend.C } func (service serviceSend) SendLink(ctx context.Context, request domainSend.LinkRequest) (response domainSend.LinkResponse, err error) { - err = validations.ValidateSendLink(request) + err = validations.ValidateSendLink(ctx, request) if err != nil { return response, err } @@ -372,8 +375,38 @@ func (service serviceSend) SendLink(ctx context.Context, request domainSend.Link return response, nil } -func (service serviceSend) Revoke(_ context.Context, request domainSend.RevokeRequest) (response domainSend.RevokeResponse, err error) { - err = validations.ValidateRevokeMessage(request) +func (service serviceSend) SendLocation(ctx context.Context, request domainSend.LocationRequest) (response domainSend.LocationResponse, err error) { + err = validations.ValidateSendLocation(ctx, request) + if err != nil { + return response, err + } + dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone) + if err != nil { + return response, err + } + + // Compose WhatsApp Proto + msgId := whatsmeow.GenerateMessageID() + msg := &waProto.Message{ + LocationMessage: &waProto.LocationMessage{ + DegreesLatitude: proto.Float64(utils.StrToFloat64(request.Latitude)), + DegreesLongitude: proto.Float64(utils.StrToFloat64(request.Longitude)), + }, + } + + // Send WhatsApp Message Proto + ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msgId, msg) + if err != nil { + return response, err + } + + response.MessageID = msgId + response.Status = fmt.Sprintf("Send location success %s (server timestamp: %s)", request.Phone, ts) + return response, nil +} + +func (service serviceSend) Revoke(ctx context.Context, request domainSend.RevokeRequest) (response domainSend.RevokeResponse, err error) { + err = validations.ValidateRevokeMessage(ctx, request) if err != nil { return response, err } @@ -394,7 +427,7 @@ func (service serviceSend) Revoke(_ context.Context, request domainSend.RevokeRe } func (service serviceSend) UpdateMessage(ctx context.Context, request domainSend.UpdateMessageRequest) (response domainSend.UpdateMessageResponse, err error) { - err = validations.ValidateUpdateMessage(request) + err = validations.ValidateUpdateMessage(ctx, request) if err != nil { return response, err } diff --git a/src/services/user.go b/src/services/user.go index 16a825b..ba24d7b 100644 --- a/src/services/user.go +++ b/src/services/user.go @@ -21,8 +21,8 @@ func NewUserService(waCli *whatsmeow.Client) domainUser.IUserService { } } -func (service userService) Info(_ context.Context, request domainUser.InfoRequest) (response domainUser.InfoResponse, err error) { - err = validations.ValidateUserInfo(request) +func (service userService) Info(ctx context.Context, request domainUser.InfoRequest) (response domainUser.InfoResponse, err error) { + err = validations.ValidateUserInfo(ctx, request) if err != nil { return response, err } @@ -64,8 +64,8 @@ func (service userService) Info(_ context.Context, request domainUser.InfoReques return response, nil } -func (service userService) Avatar(_ context.Context, request domainUser.AvatarRequest) (response domainUser.AvatarResponse, err error) { - err = validations.ValidateUserAvatar(request) +func (service userService) Avatar(ctx context.Context, request domainUser.AvatarRequest) (response domainUser.AvatarResponse, err error) { + err = validations.ValidateUserAvatar(ctx, request) if err != nil { return response, err } @@ -106,7 +106,7 @@ func (service userService) MyListGroups(_ context.Context) (response domainUser. func (service userService) MyPrivacySetting(_ context.Context) (response domainUser.MyPrivacySettingResponse, err error) { whatsapp.MustLogin(service.WaCli) - resp, err := service.WaCli.TryFetchPrivacySettings(false) + resp, err := service.WaCli.TryFetchPrivacySettings(true) if err != nil { return } diff --git a/src/validations/send_validation.go b/src/validations/send_validation.go index 101f922..5078201 100644 --- a/src/validations/send_validation.go +++ b/src/validations/send_validation.go @@ -1,6 +1,7 @@ package validations import ( + "context" "fmt" "github.com/aldinokemal/go-whatsapp-web-multidevice/config" domainSend "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/send" @@ -10,8 +11,8 @@ import ( "github.com/go-ozzo/ozzo-validation/v4/is" ) -func ValidateSendMessage(request domainSend.MessageRequest) error { - err := validation.ValidateStruct(&request, +func ValidateSendMessage(ctx context.Context, request domainSend.MessageRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), validation.Field(&request.Message, validation.Required), ) @@ -22,8 +23,8 @@ func ValidateSendMessage(request domainSend.MessageRequest) error { return nil } -func ValidateSendImage(request domainSend.ImageRequest) error { - err := validation.ValidateStruct(&request, +func ValidateSendImage(ctx context.Context, request domainSend.ImageRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), validation.Field(&request.Image, validation.Required), ) @@ -45,8 +46,8 @@ func ValidateSendImage(request domainSend.ImageRequest) error { return nil } -func ValidateSendFile(request domainSend.FileRequest) error { - err := validation.ValidateStruct(&request, +func ValidateSendFile(ctx context.Context, request domainSend.FileRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), validation.Field(&request.File, validation.Required), ) @@ -63,8 +64,8 @@ func ValidateSendFile(request domainSend.FileRequest) error { return nil } -func ValidateSendVideo(request domainSend.VideoRequest) error { - err := validation.ValidateStruct(&request, +func ValidateSendVideo(ctx context.Context, request domainSend.VideoRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), validation.Field(&request.Video, validation.Required), ) @@ -91,8 +92,8 @@ func ValidateSendVideo(request domainSend.VideoRequest) error { return nil } -func ValidateSendContact(request domainSend.ContactRequest) error { - err := validation.ValidateStruct(&request, +func ValidateSendContact(ctx context.Context, request domainSend.ContactRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), validation.Field(&request.ContactPhone, validation.Required), validation.Field(&request.ContactName, validation.Required), @@ -105,8 +106,8 @@ func ValidateSendContact(request domainSend.ContactRequest) error { return nil } -func ValidateSendLink(request domainSend.LinkRequest) error { - err := validation.ValidateStruct(&request, +func ValidateSendLink(ctx context.Context, request domainSend.LinkRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), validation.Field(&request.Link, validation.Required, is.URL), validation.Field(&request.Caption, validation.Required), @@ -119,8 +120,22 @@ func ValidateSendLink(request domainSend.LinkRequest) error { return nil } -func ValidateRevokeMessage(request domainSend.RevokeRequest) error { - err := validation.ValidateStruct(&request, +func ValidateSendLocation(ctx context.Context, request domainSend.LocationRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, + validation.Field(&request.Phone, validation.Required), + validation.Field(&request.Latitude, validation.Required, is.Latitude), + validation.Field(&request.Longitude, validation.Required, is.Longitude), + ) + + if err != nil { + return pkgError.ValidationError(err.Error()) + } + + return nil +} + +func ValidateRevokeMessage(ctx context.Context, request domainSend.RevokeRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), validation.Field(&request.MessageID, validation.Required), ) @@ -132,8 +147,8 @@ func ValidateRevokeMessage(request domainSend.RevokeRequest) error { return nil } -func ValidateUpdateMessage(request domainSend.UpdateMessageRequest) error { - err := validation.ValidateStruct(&request, +func ValidateUpdateMessage(ctx context.Context, request domainSend.UpdateMessageRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), validation.Field(&request.MessageID, validation.Required), validation.Field(&request.Message, validation.Required), diff --git a/src/validations/send_validation_test.go b/src/validations/send_validation_test.go index f04dedf..27359a5 100644 --- a/src/validations/send_validation_test.go +++ b/src/validations/send_validation_test.go @@ -1,6 +1,7 @@ package validations import ( + "context" domainSend "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/send" pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error" "github.com/stretchr/testify/assert" @@ -45,7 +46,7 @@ func TestValidateSendMessage(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateSendMessage(tt.args.request) + err := ValidateSendMessage(context.Background(), tt.args.request) assert.Equal(t, tt.err, err) }) } @@ -107,7 +108,7 @@ func TestValidateSendImage(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateSendImage(tt.args.request) + err := ValidateSendImage(context.Background(), tt.args.request) assert.Equal(t, tt.err, err) }) } @@ -156,7 +157,7 @@ func TestValidateSendFile(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateSendFile(tt.args.request) + err := ValidateSendFile(context.Background(), tt.args.request) assert.Equal(t, tt.err, err) }) } @@ -231,7 +232,7 @@ func TestValidateSendVideo(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateSendVideo(tt.args.request) + err := ValidateSendVideo(context.Background(), tt.args.request) assert.Equal(t, tt.err, err) }) } @@ -295,7 +296,7 @@ func TestValidateSendLink(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateSendLink(tt.args.request) + err := ValidateSendLink(context.Background(), tt.args.request) assert.Equal(t, tt.err, err) }) } @@ -338,7 +339,7 @@ func TestValidateRevokeMessage(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateRevokeMessage(tt.args.request) + err := ValidateRevokeMessage(context.Background(), tt.args.request) assert.Equal(t, tt.err, err) }) } @@ -393,7 +394,7 @@ func TestValidateUpdateMessage(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateUpdateMessage(tt.args.request) + err := ValidateUpdateMessage(context.Background(), tt.args.request) assert.Equal(t, tt.err, err) }) } @@ -448,7 +449,80 @@ func TestValidateSendContact(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateSendContact(tt.args.request) + err := ValidateSendContact(context.Background(), tt.args.request) + assert.Equal(t, tt.err, err) + }) + } +} + +func TestValidateSendLocation(t *testing.T) { + type args struct { + request domainSend.LocationRequest + } + tests := []struct { + name string + args args + err any + }{ + { + name: "should success normal condition", + args: args{request: domainSend.LocationRequest{ + Phone: "1728937129312@s.whatsapp.net", + Latitude: "-7.797068", + Longitude: "110.370529", + }}, + err: nil, + }, + { + name: "should error with empty phone", + args: args{request: domainSend.LocationRequest{ + Phone: "", + Latitude: "-7.797068", + Longitude: "110.370529", + }}, + err: pkgError.ValidationError("phone: cannot be blank."), + }, + { + name: "should error with empty latitude", + args: args{request: domainSend.LocationRequest{ + Phone: "1728937129312@s.whatsapp.net", + Latitude: "", + Longitude: "110.370529", + }}, + err: pkgError.ValidationError("latitude: cannot be blank."), + }, + { + name: "should error with empty longitude", + args: args{request: domainSend.LocationRequest{ + Phone: "1728937129312@s.whatsapp.net", + Latitude: "-7.797068", + Longitude: "", + }}, + err: pkgError.ValidationError("longitude: cannot be blank."), + }, + { + name: "should error with invalid latitude", + args: args{request: domainSend.LocationRequest{ + Phone: "1728937129312@s.whatsapp.net", + Latitude: "ABCDEF", + Longitude: "110.370529", + }}, + err: pkgError.ValidationError("latitude: must be a valid latitude."), + }, + { + name: "should error with invalid latitude", + args: args{request: domainSend.LocationRequest{ + Phone: "1728937129312@s.whatsapp.net", + Latitude: "-7.797068", + Longitude: "ABCDEF", + }}, + err: pkgError.ValidationError("longitude: must be a valid longitude."), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := ValidateSendLocation(context.Background(), tt.args.request) assert.Equal(t, tt.err, err) }) } diff --git a/src/validations/user_validation.go b/src/validations/user_validation.go index 8f1b1d8..36a27fe 100644 --- a/src/validations/user_validation.go +++ b/src/validations/user_validation.go @@ -1,13 +1,14 @@ package validations import ( + "context" domainUser "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/user" pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error" validation "github.com/go-ozzo/ozzo-validation/v4" ) -func ValidateUserInfo(request domainUser.InfoRequest) error { - err := validation.ValidateStruct(&request, +func ValidateUserInfo(ctx context.Context, request domainUser.InfoRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), ) @@ -17,8 +18,8 @@ func ValidateUserInfo(request domainUser.InfoRequest) error { return nil } -func ValidateUserAvatar(request domainUser.AvatarRequest) error { - err := validation.ValidateStruct(&request, +func ValidateUserAvatar(ctx context.Context, request domainUser.AvatarRequest) error { + err := validation.ValidateStructWithContext(ctx, &request, validation.Field(&request.Phone, validation.Required), ) diff --git a/src/validations/user_validation_test.go b/src/validations/user_validation_test.go index d444887..15f7751 100644 --- a/src/validations/user_validation_test.go +++ b/src/validations/user_validation_test.go @@ -1,6 +1,7 @@ package validations import ( + "context" domainUser "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/user" pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error" "github.com/stretchr/testify/assert" @@ -34,7 +35,7 @@ func TestValidateUserAvatar(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateUserAvatar(tt.args.request) + err := ValidateUserAvatar(context.Background(), tt.args.request) assert.Equal(t, tt.err, err) }) } @@ -67,7 +68,7 @@ func TestValidateUserInfo(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := ValidateUserInfo(tt.args.request) + err := ValidateUserInfo(context.Background(), tt.args.request) assert.Equal(t, tt.err, err) }) } diff --git a/src/views/index.html b/src/views/index.html index b437a5b..28f3d16 100644 --- a/src/views/index.html +++ b/src/views/index.html @@ -124,6 +124,15 @@ +