Browse Source

feat: introduce error and add test validation

pull/40/head
Aldino Kemal 3 years ago
parent
commit
78daec2db3
  1. 7
      src/cmd/root.go
  2. 2
      src/config/settings.go
  3. 26
      src/internal/rest/app.go
  4. 22
      src/internal/rest/middleware/recovery.go
  5. 50
      src/internal/rest/send.go
  6. 21
      src/internal/rest/user.go
  7. 19
      src/pkg/error/auth_error.go
  8. 27
      src/pkg/error/generic_error.go
  9. 19
      src/pkg/error/validation_error.go
  10. 24
      src/pkg/error/whatsapp_error.go
  11. 12
      src/pkg/utils/general.go
  12. 3
      src/pkg/utils/response.go
  13. 30
      src/pkg/whatsapp/whatsapp.go
  14. 0
      src/services/app.go
  15. 100
      src/services/send.go
  16. 28
      src/services/user.go
  17. 29
      src/utils/errors.go
  18. 82
      src/validations/send_validation.go
  19. 431
      src/validations/send_validation_test.go
  20. 18
      src/validations/user_validation.go
  21. 74
      src/validations/user_validation_test.go

7
src/cmd/root.go

@ -7,8 +7,9 @@ import (
"github.com/aldinokemal/go-whatsapp-web-multidevice/internal/rest/helpers"
"github.com/aldinokemal/go-whatsapp-web-multidevice/internal/rest/middleware"
"github.com/aldinokemal/go-whatsapp-web-multidevice/internal/websocket"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp"
"github.com/aldinokemal/go-whatsapp-web-multidevice/services"
"github.com/aldinokemal/go-whatsapp-web-multidevice/utils"
"github.com/dustin/go-humanize"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/basicauth"
@ -90,8 +91,8 @@ func runRest(_ *cobra.Command, _ []string) {
}
}
db := utils.InitWaDB()
cli := utils.InitWaCLI(db)
db := whatsapp.InitWaDB()
cli := whatsapp.InitWaCLI(db)
// Service
appService := services.NewAppService(cli, db)

2
src/config/settings.go

@ -6,7 +6,7 @@ import (
)
var (
AppVersion = "v4.0.0"
AppVersion = "v4.2.0"
AppPort = "3000"
AppDebug = false
AppOs = fmt.Sprintf("AldinoKemal")

26
src/internal/rest/app_rest.go → src/internal/rest/app.go

@ -3,7 +3,7 @@ package rest
import (
"fmt"
domainApp "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/app"
"github.com/aldinokemal/go-whatsapp-web-multidevice/utils"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils"
"github.com/gofiber/fiber/v2"
)
@ -21,12 +21,12 @@ func InitRestApp(app *fiber.App, service domainApp.IAppService) App {
return App{Service: service}
}
func (controller *App) Login(c *fiber.Ctx) error {
response, err := controller.Service.Login(c.UserContext())
func (handler *App) Login(c *fiber.Ctx) error {
response, err := handler.Service.Login(c.UserContext())
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: "Success",
Results: map[string]any{
"qr_link": fmt.Sprintf("%s://%s/%s", c.Protocol(), c.Hostname(), response.ImagePath),
@ -35,34 +35,34 @@ func (controller *App) Login(c *fiber.Ctx) error {
})
}
func (controller *App) Logout(c *fiber.Ctx) error {
err := controller.Service.Logout(c.UserContext())
func (handler *App) Logout(c *fiber.Ctx) error {
err := handler.Service.Logout(c.UserContext())
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: "Success logout",
Results: nil,
})
}
func (controller *App) Reconnect(c *fiber.Ctx) error {
err := controller.Service.Reconnect(c.UserContext())
func (handler *App) Reconnect(c *fiber.Ctx) error {
err := handler.Service.Reconnect(c.UserContext())
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: "Reconnect success",
Results: nil,
})
}
func (controller *App) Devices(c *fiber.Ctx) error {
devices, err := controller.Service.FetchDevices(c.UserContext())
func (handler *App) Devices(c *fiber.Ctx) error {
devices, err := handler.Service.FetchDevices(c.UserContext())
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: "Fetch device success",
Results: devices,
})

22
src/internal/rest/middleware/recovery.go

@ -2,7 +2,8 @@ package middleware
import (
"fmt"
"github.com/aldinokemal/go-whatsapp-web-multidevice/utils"
pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils"
"github.com/gofiber/fiber/v2"
)
@ -12,22 +13,17 @@ func Recovery() fiber.Handler {
err := recover()
if err != nil {
var res utils.ResponseData
res.Code = 500
res.Status = 500
res.Message = fmt.Sprintf("%s", err)
errValidation, okValidation := err.(utils.ValidationError)
if okValidation {
res.Code = 400
res.Message = errValidation.Message
errValidation, isValidationError := err.(pkgError.GenericError)
if isValidationError {
res.Status = errValidation.StatusCode()
res.Code = errValidation.ErrCode()
res.Message = errValidation.Error()
}
errAuth, okAuth := err.(utils.AuthError)
if okAuth {
res.Code = 401
res.Message = errAuth.Message
}
_ = ctx.Status(res.Code).JSON(res)
_ = ctx.Status(res.Status).JSON(res)
}
}()

50
src/internal/rest/send_rest.go → src/internal/rest/send.go

@ -2,7 +2,8 @@ package rest
import (
domainSend "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/send"
"github.com/aldinokemal/go-whatsapp-web-multidevice/utils"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp"
"github.com/aldinokemal/go-whatsapp-web-multidevice/validations"
"github.com/gofiber/fiber/v2"
)
@ -30,14 +31,15 @@ func (controller *Send) SendText(c *fiber.Ctx) error {
utils.PanicIfNeeded(err)
// add validation send message
validations.ValidateSendMessage(request)
utils.SanitizePhone(&request.Phone)
whatsapp.SanitizePhone(&request.Phone)
err = validations.ValidateSendMessage(request)
utils.PanicIfNeeded(err)
response, err := controller.Service.SendText(c.UserContext(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: response.Status,
Results: response,
})
@ -56,14 +58,15 @@ func (controller *Send) SendImage(c *fiber.Ctx) error {
request.Image = file
//add validation send image
validations.ValidateSendImage(request)
utils.SanitizePhone(&request.Phone)
whatsapp.SanitizePhone(&request.Phone)
err = validations.ValidateSendImage(request)
utils.PanicIfNeeded(err)
response, err := controller.Service.SendImage(c.UserContext(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: response.Status,
Results: response,
})
@ -80,14 +83,15 @@ func (controller *Send) SendFile(c *fiber.Ctx) error {
request.File = file
//add validation send image
validations.ValidateSendFile(request)
utils.SanitizePhone(&request.Phone)
whatsapp.SanitizePhone(&request.Phone)
err = validations.ValidateSendFile(request)
utils.PanicIfNeeded(err)
response, err := controller.Service.SendFile(c.UserContext(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: response.Status,
Results: response,
})
@ -104,14 +108,15 @@ func (controller *Send) SendVideo(c *fiber.Ctx) error {
request.Video = video
//add validation send image
validations.ValidateSendVideo(request)
utils.SanitizePhone(&request.Phone)
whatsapp.SanitizePhone(&request.Phone)
err = validations.ValidateSendVideo(request)
utils.PanicIfNeeded(err)
response, err := controller.Service.SendVideo(c.UserContext(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: response.Status,
Results: response,
})
@ -123,14 +128,15 @@ func (controller *Send) SendContact(c *fiber.Ctx) error {
utils.PanicIfNeeded(err)
// add validation send contect
validations.ValidateSendContact(request)
utils.SanitizePhone(&request.Phone)
whatsapp.SanitizePhone(&request.Phone)
err = validations.ValidateSendContact(request)
utils.PanicIfNeeded(err)
response, err := controller.Service.SendContact(c.UserContext(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: response.Status,
Results: response,
})
@ -141,15 +147,15 @@ func (controller *Send) SendLink(c *fiber.Ctx) error {
err := c.BodyParser(&request)
utils.PanicIfNeeded(err)
whatsapp.SanitizePhone(&request.Phone)
err = validations.ValidateSendLink(request)
utils.PanicIfNeeded(err)
utils.SanitizePhone(&request.Phone)
response, err := controller.Service.SendLink(c.UserContext(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: response.Status,
Results: response,
})
@ -163,13 +169,13 @@ func (controller *Send) RevokeMessage(c *fiber.Ctx) error {
err = validations.ValidateRevokeMessage(request)
utils.PanicIfNeeded(err)
utils.SanitizePhone(&request.Phone)
whatsapp.SanitizePhone(&request.Phone)
response, err := controller.Service.Revoke(c.UserContext(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: response.Status,
Results: response,
})
@ -183,13 +189,13 @@ func (controller *Send) UpdateMessage(c *fiber.Ctx) error {
err = validations.ValidateUpdateMessage(request)
utils.PanicIfNeeded(err)
utils.SanitizePhone(&request.Phone)
whatsapp.SanitizePhone(&request.Phone)
response, err := controller.Service.UpdateMessage(c.UserContext(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: response.Status,
Results: response,
})

21
src/internal/rest/user_rest.go → src/internal/rest/user.go

@ -2,7 +2,8 @@ package rest
import (
domainUser "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/user"
"github.com/aldinokemal/go-whatsapp-web-multidevice/utils"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp"
"github.com/aldinokemal/go-whatsapp-web-multidevice/validations"
"github.com/gofiber/fiber/v2"
)
@ -34,14 +35,15 @@ func (controller *User) UserInfo(c *fiber.Ctx) error {
utils.PanicIfNeeded(err)
// add validation send message
validations.ValidateUserInfo(request)
utils.SanitizePhone(&request.Phone)
whatsapp.SanitizePhone(&request.Phone)
err = validations.ValidateUserInfo(request)
utils.PanicIfNeeded(err)
response, err := controller.Service.Info(c.Context(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: "Success",
Results: response.Data[0],
})
@ -53,14 +55,15 @@ func (controller *User) UserAvatar(c *fiber.Ctx) error {
utils.PanicIfNeeded(err)
// add validation send message
validations.ValidateUserAvatar(request)
utils.SanitizePhone(&request.Phone)
whatsapp.SanitizePhone(&request.Phone)
err = validations.ValidateUserAvatar(request)
utils.PanicIfNeeded(err)
response, err := controller.Service.Avatar(c.Context(), request)
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: "Success get avatar",
Results: response,
})
@ -71,7 +74,7 @@ func (controller *User) UserMyPrivacySetting(c *fiber.Ctx) error {
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: "Success get privacy",
Results: response,
})
@ -82,7 +85,7 @@ func (controller *User) UserMyListGroups(c *fiber.Ctx) error {
utils.PanicIfNeeded(err)
return c.JSON(utils.ResponseData{
Code: 200,
Status: 200,
Message: "Success get list groups",
Results: response,
})

19
src/pkg/error/auth_error.go

@ -0,0 +1,19 @@
package error
import "net/http"
type AuthError string
func (err AuthError) Error() string {
return string(err)
}
// ErrCode will return the error code based on the error data type
func (err AuthError) ErrCode() string {
return "AUTHENTICATION_ERROR"
}
// StatusCode will return the HTTP status code based on the error data type
func (err AuthError) StatusCode() int {
return http.StatusUnauthorized
}

27
src/pkg/error/generic_error.go

@ -0,0 +1,27 @@
package error
import "net/http"
// GenericError represent as the contract of generic error
type GenericError interface {
Error() string
ErrCode() string
StatusCode() int
}
type InternalServerError string
// Error for complying the error interface
func (e InternalServerError) Error() string {
return string(e)
}
// ErrCode will return the error code based on the error data type
func (e InternalServerError) ErrCode() string {
return "INTERNAL_SERVER_ERROR"
}
// StatusCode will return the HTTP status code based on the error data type
func (e InternalServerError) StatusCode() int {
return http.StatusInternalServerError
}

19
src/pkg/error/validation_error.go

@ -0,0 +1,19 @@
package error
import "net/http"
type ValidationError string
func (err ValidationError) Error() string {
return string(err)
}
// ErrCode will return the error code based on the error data type
func (err ValidationError) ErrCode() string {
return "VALIDATION_ERROR"
}
// StatusCode will return the HTTP status code based on the error data type
func (err ValidationError) StatusCode() int {
return http.StatusBadRequest
}

24
src/pkg/error/whatsapp_error.go

@ -0,0 +1,24 @@
package error
import "net/http"
type InvalidJID string
// Error for complying the error interface
func (e InvalidJID) Error() string {
return string(e)
}
// ErrCode will return the error code based on the error data type
func (e InvalidJID) ErrCode() string {
return "INVALID_JID"
}
// StatusCode will return the HTTP status code based on the error data type
func (e InvalidJID) StatusCode() int {
return http.StatusBadRequest
}
const (
ErrInvalidJID = InvalidJID("your JID is invalid")
)

12
src/utils/general.go → src/pkg/utils/general.go

@ -1,6 +1,7 @@
package utils
import (
"fmt"
"os"
"path/filepath"
"time"
@ -34,3 +35,14 @@ func CreateFolder(folderPath ...string) error {
}
return nil
}
// PanicIfNeeded is panic if error is not nil
func PanicIfNeeded(err any, message ...string) {
if err != nil {
if fmt.Sprintf("%s", err) == "record not found" && len(message) > 0 {
panic(message[0])
} else {
panic(err)
}
}
}

3
src/utils/response.go → src/pkg/utils/response.go

@ -1,7 +1,8 @@
package utils
type ResponseData struct {
Code int `json:"code"`
Status int
Code string `json:"code,omitempty"`
Message string `json:"message"`
Results any `json:"results"`
}

30
src/utils/whatsapp.go → src/pkg/whatsapp/whatsapp.go

@ -1,4 +1,4 @@
package utils
package whatsapp
import (
"bytes"
@ -7,6 +7,7 @@ import (
"fmt"
"github.com/aldinokemal/go-whatsapp-web-multidevice/config"
"github.com/aldinokemal/go-whatsapp-web-multidevice/internal/websocket"
pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error"
"go.mau.fi/whatsmeow"
"go.mau.fi/whatsmeow/appstate"
waProto "go.mau.fi/whatsmeow/binary/proto"
@ -32,9 +33,9 @@ var (
)
func SanitizePhone(phone *string) {
if phone != nil && !strings.Contains(*phone, "@") {
if phone != nil && len(*phone) > 0 && !strings.Contains(*phone, "@") {
if len(*phone) <= 15 {
*phone = fmt.Sprintf("%s@.whatsapp.net", *phone)
*phone = fmt.Sprintf("%s@s.whatsapp.net", *phone)
} else {
*phone = fmt.Sprintf("%s@g.us", *phone)
}
@ -76,25 +77,30 @@ func GetPlatformName(deviceID int) string {
}
}
func ParseJID(arg string) (types.JID, bool) {
func ParseJID(arg string) (types.JID, error) {
if arg[0] == '+' {
arg = arg[1:]
}
if !strings.ContainsRune(arg, '@') {
return types.NewJID(arg, types.DefaultUserServer), true
return types.NewJID(arg, types.DefaultUserServer), nil
} else {
recipient, err := types.ParseJID(arg)
if err != nil {
_ = fmt.Errorf("invalid JID %s: %v", arg, err)
return recipient, false
fmt.Printf("invalid JID %s: %v", arg, err)
return recipient, pkgError.ErrInvalidJID
} else if recipient.User == "" {
_ = fmt.Errorf("invalid JID %s: no server specified", arg)
return recipient, false
fmt.Printf("invalid JID %v: no server specified", arg)
return recipient, pkgError.ErrInvalidJID
}
return recipient, true
return recipient, nil
}
}
func ValidateJidWithLogin(waCli *whatsmeow.Client, phone string) (types.JID, error) {
MustLogin(waCli)
return ParseJID(phone)
}
func InitWaDB() *sqlstore.Container {
// Running Whatsapp
log = waLog.Stdout("Main", config.WhatsappLogLevel, true)
@ -128,9 +134,9 @@ func InitWaCLI(storeContainer *sqlstore.Container) *whatsmeow.Client {
func MustLogin(waCli *whatsmeow.Client) {
if !waCli.IsConnected() {
panic(AuthError{Message: "you are not connect to whatsapp server, please reconnect"})
panic(pkgError.AuthError("you are not connect to services server, please reconnect"))
} else if !waCli.IsLoggedIn() {
panic(AuthError{Message: "you are not login"})
panic(pkgError.AuthError("you are not login to services server, please login"))
}
}

0
src/services/app_service.go → src/services/app.go

100
src/services/send_service.go → src/services/send.go

@ -2,11 +2,12 @@ package services
import (
"context"
"errors"
"fmt"
"github.com/aldinokemal/go-whatsapp-web-multidevice/config"
domainSend "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/send"
"github.com/aldinokemal/go-whatsapp-web-multidevice/utils"
pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp"
fiberUtils "github.com/gofiber/fiber/v2/utils"
"github.com/h2non/bimg"
"github.com/valyala/fasthttp"
@ -30,16 +31,14 @@ func NewSendService(waCli *whatsmeow.Client) domainSend.ISendService {
}
func (service serviceSend) SendText(ctx context.Context, request domainSend.MessageRequest) (response domainSend.MessageResponse, err error) {
utils.MustLogin(service.WaCli)
recipient, ok := utils.ParseJID(request.Phone)
if !ok {
return response, errors.New("invalid JID " + request.Phone)
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
msgId := whatsmeow.GenerateMessageID()
msg := &waProto.Message{Conversation: proto.String(request.Message)}
ts, err := service.WaCli.SendMessage(ctx, recipient, msgId, msg)
ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msgId, msg)
if err != nil {
return response, err
}
@ -50,7 +49,10 @@ 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) {
utils.MustLogin(service.WaCli)
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
var (
imagePath string
@ -100,10 +102,6 @@ func (service serviceSend) SendImage(ctx context.Context, request domainSend.Ima
// Send to WA server
dataWaCaption := request.Caption
dataWaRecipient, ok := utils.ParseJID(request.Phone)
if !ok {
return response, errors.New("invalid JID " + request.Phone)
}
dataWaImage, err := os.ReadFile(imagePath)
if err != nil {
return response, err
@ -145,7 +143,10 @@ 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) {
utils.MustLogin(service.WaCli)
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
oriFilePath := fmt.Sprintf("%s/%s", config.PathSendItems, request.File.Filename)
err = fasthttp.SaveMultipartFile(request.File, oriFilePath)
@ -154,10 +155,6 @@ func (service serviceSend) SendFile(ctx context.Context, request domainSend.File
}
// Send to WA server
dataWaRecipient, ok := utils.ParseJID(request.Phone)
if !ok {
return response, errors.New("invalid JID " + request.Phone)
}
dataWaFile, err := os.ReadFile(oriFilePath)
if err != nil {
return response, err
@ -197,7 +194,10 @@ 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) {
utils.MustLogin(service.WaCli)
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
var (
videoPath string
@ -210,25 +210,27 @@ func (service serviceSend) SendVideo(ctx context.Context, request domainSend.Vid
oriVideoPath := fmt.Sprintf("%s/%s", config.PathSendItems, generateUUID+request.Video.Filename)
err = fasthttp.SaveMultipartFile(request.Video, oriVideoPath)
if err != nil {
return response, err
return response, pkgError.InternalServerError(fmt.Sprintf("failed to store video in server %v", err))
}
// Get thumbnail video with ffmpeg
thumbnailVideoPath := fmt.Sprintf("%s/%s", config.PathSendItems, generateUUID+".png")
cmdThumbnail := exec.Command("ffmpeg", "-i", oriVideoPath, "-ss", "00:00:01.000", "-vframes", "1", thumbnailVideoPath)
err = cmdThumbnail.Run()
utils.PanicIfNeeded(err, "error when getting thumbnail")
if err != nil {
return response, pkgError.InternalServerError(fmt.Sprintf("failed to create thumbnail %v", err))
}
// Resize Thumbnail
openImageBuffer, err := bimg.Read(thumbnailVideoPath)
resize, err := bimg.NewImage(openImageBuffer).Process(bimg.Options{Quality: 90, Width: 600, Embed: true})
if err != nil {
return response, err
return response, pkgError.InternalServerError(fmt.Sprintf("failed to resize thumbnail %v", err))
}
thumbnailResizeVideoPath := fmt.Sprintf("%s/%s", config.PathSendItems, generateUUID+"_resize.png")
err = bimg.Write(thumbnailResizeVideoPath, resize)
if err != nil {
return response, err
return response, pkgError.InternalServerError(fmt.Sprintf("failed to create image thumbnail %v", err))
}
deletedItems = append(deletedItems, thumbnailVideoPath)
@ -240,7 +242,9 @@ func (service serviceSend) SendVideo(ctx context.Context, request domainSend.Vid
// Compress video with ffmpeg
cmdCompress := exec.Command("ffmpeg", "-i", oriVideoPath, "-strict", "-2", compresVideoPath)
err = cmdCompress.Run()
utils.PanicIfNeeded(err, "error when compress video")
if err != nil {
return response, pkgError.InternalServerError("failed to compress video")
}
videoPath = compresVideoPath
deletedItems = append(deletedItems, compresVideoPath)
@ -250,18 +254,13 @@ func (service serviceSend) SendVideo(ctx context.Context, request domainSend.Vid
}
//Send to WA server
dataWaRecipient, ok := utils.ParseJID(request.Phone)
if !ok {
return response, errors.New("invalid JID " + request.Phone)
}
dataWaVideo, err := os.ReadFile(videoPath)
if err != nil {
return response, err
}
uploaded, err := service.WaCli.Upload(context.Background(), dataWaVideo, whatsmeow.MediaVideo)
if err != nil {
fmt.Printf("Failed to upload file: %v", err)
return response, err
return response, pkgError.InternalServerError(fmt.Sprintf("Failed to upload file: %v", err))
}
dataWaThumbnail, err := os.ReadFile(videoThumbnail)
if err != nil {
@ -298,12 +297,11 @@ 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) {
utils.MustLogin(service.WaCli)
recipient, ok := utils.ParseJID(request.Phone)
if !ok {
return response, errors.New("invalid JID " + request.Phone)
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
msgVCard := fmt.Sprintf("BEGIN:VCARD\nVERSION:3.0\nN:;%v;;;\nFN:%v\nTEL;type=CELL;waid=%v:+%v\nEND:VCARD",
request.ContactName, request.ContactName, request.ContactPhone, request.ContactPhone)
msgId := whatsmeow.GenerateMessageID()
@ -311,7 +309,7 @@ func (service serviceSend) SendContact(ctx context.Context, request domainSend.C
DisplayName: proto.String(request.ContactName),
Vcard: proto.String(msgVCard),
}}
ts, err := service.WaCli.SendMessage(ctx, recipient, "", msg)
ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, "", msg)
if err != nil {
return response, err
}
@ -322,11 +320,9 @@ 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) {
utils.MustLogin(service.WaCli)
recipient, ok := utils.ParseJID(request.Phone)
if !ok {
return response, errors.New("invalid JID " + request.Phone)
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
msgId := whatsmeow.GenerateMessageID()
@ -341,7 +337,7 @@ func (service serviceSend) SendLink(ctx context.Context, request domainSend.Link
},
},
}}
ts, err := service.WaCli.SendMessage(ctx, recipient, msgId, msg)
ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msgId, msg)
if err != nil {
return response, err
}
@ -352,15 +348,13 @@ func (service serviceSend) SendLink(ctx context.Context, request domainSend.Link
}
func (service serviceSend) Revoke(_ context.Context, request domainSend.RevokeRequest) (response domainSend.RevokeResponse, err error) {
utils.MustLogin(service.WaCli)
recipient, ok := utils.ParseJID(request.Phone)
if !ok {
return response, errors.New("invalid JID " + request.Phone)
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
msgId := whatsmeow.GenerateMessageID()
ts, err := service.WaCli.SendMessage(context.Background(), recipient, msgId, service.WaCli.BuildRevoke(recipient, types.EmptyJID, request.MessageID))
ts, err := service.WaCli.SendMessage(context.Background(), dataWaRecipient, msgId, service.WaCli.BuildRevoke(dataWaRecipient, types.EmptyJID, request.MessageID))
if err != nil {
return response, err
}
@ -371,16 +365,14 @@ func (service serviceSend) Revoke(_ context.Context, request domainSend.RevokeRe
}
func (service serviceSend) UpdateMessage(ctx context.Context, request domainSend.UpdateMessageRequest) (response domainSend.UpdateMessageResponse, err error) {
utils.MustLogin(service.WaCli)
recipient, ok := utils.ParseJID(request.Phone)
if !ok {
return response, errors.New("invalid JID " + request.Phone)
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
msgId := whatsmeow.GenerateMessageID()
msg := &waProto.Message{Conversation: proto.String(request.Message)}
ts, err := service.WaCli.SendMessage(context.Background(), recipient, msgId, service.WaCli.BuildEdit(recipient, request.MessageID, msg))
ts, err := service.WaCli.SendMessage(context.Background(), dataWaRecipient, msgId, service.WaCli.BuildEdit(dataWaRecipient, request.MessageID, msg))
if err != nil {
return response, err
}

28
src/services/user_service.go → src/services/user.go

@ -5,7 +5,7 @@ import (
"errors"
"fmt"
domainUser "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/user"
"github.com/aldinokemal/go-whatsapp-web-multidevice/utils"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp"
"go.mau.fi/whatsmeow"
"go.mau.fi/whatsmeow/types"
)
@ -21,15 +21,13 @@ func NewUserService(waCli *whatsmeow.Client) domainUser.IUserService {
}
func (service userService) Info(_ context.Context, request domainUser.InfoRequest) (response domainUser.InfoResponse, err error) {
utils.MustLogin(service.WaCli)
var jids []types.JID
jid, ok := utils.ParseJID(request.Phone)
if !ok {
return response, errors.New("invalid JID " + request.Phone)
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
jids = append(jids, jid)
jids = append(jids, dataWaRecipient)
resp, err := service.WaCli.GetUserInfo(jids)
if err != nil {
return response, err
@ -41,7 +39,7 @@ func (service userService) Info(_ context.Context, request domainUser.InfoReques
device = append(device, domainUser.InfoResponseDataDevice{
User: j.User,
Agent: j.Agent,
Device: utils.GetPlatformName(int(j.Device)),
Device: whatsapp.GetPlatformName(int(j.Device)),
Server: j.Server,
AD: j.AD,
})
@ -62,13 +60,11 @@ func (service userService) Info(_ context.Context, request domainUser.InfoReques
}
func (service userService) Avatar(_ context.Context, request domainUser.AvatarRequest) (response domainUser.AvatarResponse, err error) {
utils.MustLogin(service.WaCli)
jid, ok := utils.ParseJID(request.Phone)
if !ok {
return response, errors.New("invalid JID " + request.Phone)
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
pic, err := service.WaCli.GetProfilePictureInfo(jid, false, "")
pic, err := service.WaCli.GetProfilePictureInfo(dataWaRecipient, false, "")
if err != nil {
return response, err
} else if pic == nil {
@ -83,7 +79,7 @@ func (service userService) Avatar(_ context.Context, request domainUser.AvatarRe
}
func (service userService) MyListGroups(_ context.Context) (response domainUser.MyListGroupsResponse, err error) {
utils.MustLogin(service.WaCli)
whatsapp.MustLogin(service.WaCli)
groups, err := service.WaCli.GetJoinedGroups()
if err != nil {
@ -99,7 +95,7 @@ func (service userService) MyListGroups(_ context.Context) (response domainUser.
}
func (service userService) MyPrivacySetting(_ context.Context) (response domainUser.MyPrivacySettingResponse, err error) {
utils.MustLogin(service.WaCli)
whatsapp.MustLogin(service.WaCli)
resp, err := service.WaCli.TryFetchPrivacySettings(false)
if err != nil {

29
src/utils/errors.go

@ -1,29 +0,0 @@
package utils
import "fmt"
func PanicIfNeeded(err any, message ...string) {
if err != nil {
if fmt.Sprintf("%s", err) == "record not found" && len(message) > 0 {
panic(message[0])
} else {
panic(err)
}
}
}
type ValidationError struct {
Message string
}
func (validationError ValidationError) Error() string {
return validationError.Message
}
type AuthError struct {
Message string
}
func (err AuthError) Error() string {
return err.Message
}

82
src/validations/send_validation.go

@ -4,32 +4,32 @@ import (
"fmt"
"github.com/aldinokemal/go-whatsapp-web-multidevice/config"
domainSend "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/send"
"github.com/aldinokemal/go-whatsapp-web-multidevice/utils"
pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error"
"github.com/dustin/go-humanize"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/go-ozzo/ozzo-validation/v4/is"
)
func ValidateSendMessage(request domainSend.MessageRequest) {
func ValidateSendMessage(request domainSend.MessageRequest) error {
err := validation.ValidateStruct(&request,
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.Message, validation.Required),
)
if err != nil {
panic(utils.ValidationError{
Message: err.Error(),
})
return pkgError.ValidationError(err.Error())
}
return nil
}
func ValidateSendImage(request domainSend.ImageRequest) {
func ValidateSendImage(request domainSend.ImageRequest) error {
err := validation.ValidateStruct(&request,
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.Image, validation.Required),
)
if err != nil {
panic(utils.ValidationError{
Message: err.Error(),
})
return pkgError.ValidationError(err.Error())
}
availableMimes := map[string]bool{
@ -39,40 +39,38 @@ func ValidateSendImage(request domainSend.ImageRequest) {
}
if !availableMimes[request.Image.Header.Get("Content-Type")] {
panic(utils.ValidationError{
Message: "your image is not allowed. please use jpg/jpeg/png",
})
return pkgError.ValidationError("your image is not allowed. please use jpg/jpeg/png")
}
return nil
}
func ValidateSendFile(request domainSend.FileRequest) {
func ValidateSendFile(request domainSend.FileRequest) error {
err := validation.ValidateStruct(&request,
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.File, validation.Required),
)
if err != nil {
panic(utils.ValidationError{
Message: err.Error(),
})
return pkgError.ValidationError(err.Error())
}
if request.File.Size > config.WhatsappSettingMaxFileSize { // 10MB
maxSizeString := humanize.Bytes(uint64(config.WhatsappSettingMaxFileSize))
panic(utils.ValidationError{
Message: fmt.Sprintf("max file upload is %s, please upload in cloud and send via text if your file is higher than %s", maxSizeString, maxSizeString),
})
return pkgError.ValidationError(fmt.Sprintf("max file upload is %s, please upload in cloud and send via text if your file is higher than %s", maxSizeString, maxSizeString))
}
return nil
}
func ValidateSendVideo(request domainSend.VideoRequest) {
func ValidateSendVideo(request domainSend.VideoRequest) error {
err := validation.ValidateStruct(&request,
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.Video, validation.Required),
)
if err != nil {
panic(utils.ValidationError{
Message: err.Error(),
})
return pkgError.ValidationError(err.Error())
}
availableMimes := map[string]bool{
@ -82,42 +80,40 @@ func ValidateSendVideo(request domainSend.VideoRequest) {
}
if !availableMimes[request.Video.Header.Get("Content-Type")] {
panic(utils.ValidationError{
Message: "your video type is not allowed. please use mp4/mkv",
})
return pkgError.ValidationError("your video type is not allowed. please use mp4/mkv/avi")
}
if request.Video.Size > config.WhatsappSettingMaxVideoSize { // 30MB
maxSizeString := humanize.Bytes(uint64(config.WhatsappSettingMaxVideoSize))
panic(utils.ValidationError{
Message: fmt.Sprintf("max video upload is %s, please upload in cloud and send via text if your file is higher than %s", maxSizeString, maxSizeString),
})
return pkgError.ValidationError(fmt.Sprintf("max video upload is %s, please upload in cloud and send via text if your file is higher than %s", maxSizeString, maxSizeString))
}
return nil
}
func ValidateSendContact(request domainSend.ContactRequest) {
func ValidateSendContact(request domainSend.ContactRequest) error {
err := validation.ValidateStruct(&request,
validation.Field(&request.ContactName, validation.Required),
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.ContactPhone, validation.Required),
validation.Field(&request.ContactName, validation.Required),
)
if err != nil {
panic(utils.ValidationError{
Message: err.Error(),
})
return pkgError.ValidationError(err.Error())
}
return nil
}
func ValidateSendLink(request domainSend.LinkRequest) error {
err := validation.ValidateStruct(&request,
validation.Field(&request.Link, validation.Required),
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.Link, validation.Required, is.URL),
validation.Field(&request.Caption, validation.Required),
)
if err != nil {
return utils.ValidationError{
Message: err.Error(),
}
return pkgError.ValidationError(err.Error())
}
return nil
@ -125,13 +121,12 @@ func ValidateSendLink(request domainSend.LinkRequest) error {
func ValidateRevokeMessage(request domainSend.RevokeRequest) error {
err := validation.ValidateStruct(&request,
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.MessageID, validation.Required),
)
if err != nil {
return utils.ValidationError{
Message: err.Error(),
}
return pkgError.ValidationError(err.Error())
}
return nil
@ -139,14 +134,13 @@ func ValidateRevokeMessage(request domainSend.RevokeRequest) error {
func ValidateUpdateMessage(request domainSend.UpdateMessageRequest) error {
err := validation.ValidateStruct(&request,
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.MessageID, validation.Required),
validation.Field(&request.Message, validation.Required),
)
if err != nil {
return utils.ValidationError{
Message: err.Error(),
}
return pkgError.ValidationError(err.Error())
}
return nil

431
src/validations/send_validation_test.go

@ -2,7 +2,9 @@ package validations
import (
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"
"mime/multipart"
"testing"
)
@ -16,25 +18,438 @@ func TestValidateSendMessage(t *testing.T) {
err any
}{
{
name: "success phone & message normal",
name: "should success with phone and message",
args: args{request: domainSend.MessageRequest{
Phone: "1728937129312@s.whatsapp.net",
Message: "Hello this is testing",
}},
err: nil,
},
{
name: "should error with empty phone",
args: args{request: domainSend.MessageRequest{
Phone: "",
Message: "Hello this is testing",
}},
err: pkgError.ValidationError("phone: cannot be blank."),
},
{
name: "should error with empty message",
args: args{request: domainSend.MessageRequest{
Phone: "1728937129312@s.whatsapp.net",
Message: "",
}},
err: pkgError.ValidationError("message: cannot be blank."),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateSendMessage(tt.args.request)
assert.Equal(t, tt.err, err)
})
}
}
func TestValidateSendImage(t *testing.T) {
image := &multipart.FileHeader{
Filename: "sample-image.png",
Size: 100,
Header: map[string][]string{"Content-Type": {"image/png"}},
}
type args struct {
request domainSend.ImageRequest
}
tests := []struct {
name string
args args
err any
}{
{
name: "should success with normal condition",
args: args{request: domainSend.ImageRequest{
Phone: "1728937129312@s.whatsapp.net",
Caption: "Hello this is testing",
Image: image,
}},
err: nil,
},
{
name: "should error with empty phone",
args: args{request: domainSend.ImageRequest{
Phone: "",
Image: image,
}},
err: pkgError.ValidationError("phone: cannot be blank."),
},
{
name: "should error with empty image",
args: args{request: domainSend.ImageRequest{
Phone: "1728937129312@s.whatsapp.net",
Image: nil,
}},
err: pkgError.ValidationError("image: cannot be blank."),
},
{
name: "should error with invalid image type",
args: args{request: domainSend.ImageRequest{
Phone: "1728937129312@s.whatsapp.net",
Image: &multipart.FileHeader{
Filename: "sample-image.pdf",
Size: 100,
Header: map[string][]string{"Content-Type": {"application/pdf"}},
},
}},
err: pkgError.ValidationError("your image is not allowed. please use jpg/jpeg/png"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateSendImage(tt.args.request)
assert.Equal(t, tt.err, err)
})
}
}
func TestValidateSendFile(t *testing.T) {
file := &multipart.FileHeader{
Filename: "sample-image.png",
Size: 100,
Header: map[string][]string{"Content-Type": {"image/png"}},
}
type args struct {
request domainSend.FileRequest
}
tests := []struct {
name string
args args
err any
}{
{
name: "should success with normal condition",
args: args{request: domainSend.FileRequest{
Phone: "1728937129312@s.whatsapp.net",
File: file,
}},
err: nil,
},
{
name: "should error with empty phone",
args: args{request: domainSend.FileRequest{
Phone: "",
File: file,
}},
err: pkgError.ValidationError("phone: cannot be blank."),
},
{
name: "should error with empty file",
args: args{request: domainSend.FileRequest{
Phone: "1728937129312@s.whatsapp.net",
File: nil,
}},
err: pkgError.ValidationError("file: cannot be blank."),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateSendFile(tt.args.request)
assert.Equal(t, tt.err, err)
})
}
}
func TestValidateSendVideo(t *testing.T) {
file := &multipart.FileHeader{
Filename: "sample-video.mp4",
Size: 100,
Header: map[string][]string{"Content-Type": {"video/mp4"}},
}
type args struct {
request domainSend.VideoRequest
}
tests := []struct {
name string
args args
err any
}{
{
name: "should success with normal condition",
args: args{request: domainSend.VideoRequest{
Phone: "1728937129312@s.whatsapp.net",
Caption: "simple caption",
Video: file,
ViewOnce: false,
Compress: false,
}},
err: nil,
},
{
name: "should error with empty phone",
args: args{request: domainSend.VideoRequest{
Phone: "",
Caption: "simple caption",
Video: file,
ViewOnce: false,
Compress: false,
}},
err: pkgError.ValidationError("phone: cannot be blank."),
},
{
name: "should error with empty video",
args: args{request: domainSend.VideoRequest{
Phone: "1728937129312@s.whatsapp.net",
Caption: "simple caption",
Video: nil,
ViewOnce: false,
Compress: false,
}},
err: pkgError.ValidationError("video: cannot be blank."),
},
{
name: "should error with invalid format video",
args: args{request: domainSend.VideoRequest{
Phone: "1728937129312@s.whatsapp.net",
Caption: "simple caption",
Video: func() *multipart.FileHeader {
return &multipart.FileHeader{
Filename: "sample-video.jpg",
Size: 100,
Header: map[string][]string{"Content-Type": {"image/png"}},
}
}(),
ViewOnce: false,
Compress: false,
}},
err: pkgError.ValidationError("your video type is not allowed. please use mp4/mkv/avi"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateSendVideo(tt.args.request)
assert.Equal(t, tt.err, err)
})
}
}
func TestValidateSendLink(t *testing.T) {
type args struct {
request domainSend.LinkRequest
}
tests := []struct {
name string
args args
err any
}{
{
name: "should success normal condition",
args: args{request: domainSend.LinkRequest{
Phone: "1728937129312@s.whatsapp.net",
Caption: "description",
Link: "https://google.com",
}},
err: nil,
},
{
name: "should error with empty phone",
args: args{request: domainSend.LinkRequest{
Phone: "",
Caption: "description",
Link: "https://google.com",
}},
err: pkgError.ValidationError("phone: cannot be blank."),
},
{
name: "should error with empty caption",
args: args{request: domainSend.LinkRequest{
Phone: "1728937129312@s.whatsapp.net",
Caption: "",
Link: "https://google.com",
}},
err: pkgError.ValidationError("caption: cannot be blank."),
},
{
name: "should error with empty link",
args: args{request: domainSend.LinkRequest{
Phone: "1728937129312@s.whatsapp.net",
Caption: "description",
Link: "",
}},
err: pkgError.ValidationError("link: cannot be blank."),
},
{
name: "should error with invalid link",
args: args{request: domainSend.LinkRequest{
Phone: "1728937129312@s.whatsapp.net",
Caption: "description",
Link: "googlecom",
}},
err: pkgError.ValidationError("link: must be a valid URL."),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.err == nil {
ValidateSendMessage(tt.args.request)
} else {
assert.PanicsWithValue(t, tt.err, func() {
ValidateSendMessage(tt.args.request)
})
}
err := ValidateSendLink(tt.args.request)
assert.Equal(t, tt.err, err)
})
}
}
func TestValidateRevokeMessage(t *testing.T) {
type args struct {
request domainSend.RevokeRequest
}
tests := []struct {
name string
args args
err any
}{
{
name: "should success normal condition",
args: args{request: domainSend.RevokeRequest{
Phone: "1728937129312@s.whatsapp.net",
MessageID: "1382901271239781",
}},
err: nil,
},
{
name: "should error with empty phone",
args: args{request: domainSend.RevokeRequest{
Phone: "",
MessageID: "1382901271239781",
}},
err: pkgError.ValidationError("phone: cannot be blank."),
},
{
name: "should error with empty message id",
args: args{request: domainSend.RevokeRequest{
Phone: "1728937129312@s.whatsapp.net",
MessageID: "",
}},
err: pkgError.ValidationError("message_id: cannot be blank."),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateRevokeMessage(tt.args.request)
assert.Equal(t, tt.err, err)
})
}
}
func TestValidateUpdateMessage(t *testing.T) {
type args struct {
request domainSend.UpdateMessageRequest
}
tests := []struct {
name string
args args
err any
}{
{
name: "should success normal condition",
args: args{request: domainSend.UpdateMessageRequest{
MessageID: "1382901271239781",
Message: "some update message",
Phone: "1728937129312@s.whatsapp.net",
}},
err: nil,
},
{
name: "should error with empty phone",
args: args{request: domainSend.UpdateMessageRequest{
MessageID: "1382901271239781",
Message: "some update message",
Phone: "",
}},
err: pkgError.ValidationError("phone: cannot be blank."),
},
{
name: "should error with empty message id",
args: args{request: domainSend.UpdateMessageRequest{
MessageID: "",
Message: "some update message",
Phone: "1728937129312@s.whatsapp.net",
}},
err: pkgError.ValidationError("message_id: cannot be blank."),
},
{
name: "should error with empty message update",
args: args{request: domainSend.UpdateMessageRequest{
MessageID: "1382901271239781",
Message: "",
Phone: "1728937129312@s.whatsapp.net",
}},
err: pkgError.ValidationError("message: cannot be blank."),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateUpdateMessage(tt.args.request)
assert.Equal(t, tt.err, err)
})
}
}
func TestValidateSendContact(t *testing.T) {
type args struct {
request domainSend.ContactRequest
}
tests := []struct {
name string
args args
err any
}{
{
name: "should success normal condition",
args: args{request: domainSend.ContactRequest{
Phone: "1728937129312@s.whatsapp.net",
ContactName: "Aldino",
ContactPhone: "62788712738123",
}},
err: nil,
},
{
name: "should error with empty phone",
args: args{request: domainSend.ContactRequest{
Phone: "",
ContactName: "Aldino",
ContactPhone: "62788712738123",
}},
err: pkgError.ValidationError("phone: cannot be blank."),
},
{
name: "should error with empty contact name",
args: args{request: domainSend.ContactRequest{
Phone: "1728937129312@s.whatsapp.net",
ContactName: "",
ContactPhone: "62788712738123",
}},
err: pkgError.ValidationError("contact_name: cannot be blank."),
},
{
name: "should error with empty contact phone",
args: args{request: domainSend.ContactRequest{
Phone: "1728937129312@s.whatsapp.net",
ContactName: "Aldino",
ContactPhone: "",
}},
err: pkgError.ValidationError("contact_phone: cannot be blank."),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateSendContact(tt.args.request)
assert.Equal(t, tt.err, err)
})
}
}

18
src/validations/user_validation.go

@ -2,29 +2,29 @@ package validations
import (
domainUser "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/user"
"github.com/aldinokemal/go-whatsapp-web-multidevice/utils"
pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error"
validation "github.com/go-ozzo/ozzo-validation/v4"
)
func ValidateUserInfo(request domainUser.InfoRequest) {
func ValidateUserInfo(request domainUser.InfoRequest) error {
err := validation.ValidateStruct(&request,
validation.Field(&request.Phone, validation.Required),
)
if err != nil {
panic(utils.ValidationError{
Message: err.Error(),
})
return pkgError.ValidationError(err.Error())
}
return nil
}
func ValidateUserAvatar(request domainUser.AvatarRequest) {
func ValidateUserAvatar(request domainUser.AvatarRequest) error {
err := validation.ValidateStruct(&request,
validation.Field(&request.Phone, validation.Required),
)
if err != nil {
panic(utils.ValidationError{
Message: err.Error(),
})
return pkgError.ValidationError(err.Error())
}
return nil
}

74
src/validations/user_validation_test.go

@ -0,0 +1,74 @@
package validations
import (
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"
"testing"
)
func TestValidateUserAvatar(t *testing.T) {
type args struct {
request domainUser.AvatarRequest
}
tests := []struct {
name string
args args
err any
}{
{
name: "should success",
args: args{request: domainUser.AvatarRequest{
Phone: "1728937129312@s.whatsapp.net",
}},
err: nil,
},
{
name: "should error with empty phone",
args: args{request: domainUser.AvatarRequest{
Phone: "",
}},
err: pkgError.ValidationError("phone: cannot be blank."),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateUserAvatar(tt.args.request)
assert.Equal(t, tt.err, err)
})
}
}
func TestValidateUserInfo(t *testing.T) {
type args struct {
request domainUser.InfoRequest
}
tests := []struct {
name string
args args
err any
}{
{
name: "should success",
args: args{request: domainUser.InfoRequest{
Phone: "1728937129312@s.whatsapp.net",
}},
err: nil,
},
{
name: "should error with empty phone",
args: args{request: domainUser.InfoRequest{
Phone: "",
}},
err: pkgError.ValidationError("phone: cannot be blank."),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateUserInfo(tt.args.request)
assert.Equal(t, tt.err, err)
})
}
}
Loading…
Cancel
Save