From df745ac35ce8ab1861b97f781c5043c6edf6e989 Mon Sep 17 00:00:00 2001 From: Aldino Kemal Date: Sun, 14 Jul 2024 08:05:12 +0700 Subject: [PATCH] feat: add api login with code --- docker/golang.Dockerfile | 4 +-- src/domains/app/app.go | 2 +- src/internal/rest/app.go | 6 ++-- src/services/app.go | 27 +++++++++++---- src/validations/app_validation.go | 21 ++++++++++++ src/validations/app_validation_test.go | 46 ++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 src/validations/app_validation.go create mode 100644 src/validations/app_validation_test.go diff --git a/docker/golang.Dockerfile b/docker/golang.Dockerfile index 2b84905..ea9c7af 100644 --- a/docker/golang.Dockerfile +++ b/docker/golang.Dockerfile @@ -1,7 +1,7 @@ ############################ # STEP 1 build executable binary ############################ -FROM golang:1.21.5-alpine3.19 AS builder +FROM golang:1.22.5-alpine3.20 AS builder RUN apk update && apk add --no-cache gcc musl-dev gcompat WORKDIR /whatsapp COPY ./src . @@ -14,7 +14,7 @@ RUN go build -o /app/whatsapp ############################# ## STEP 2 build a smaller image ############################# -FROM alpine:3.19 +FROM alpine:3.20 RUN apk update && apk add --no-cache ffmpeg WORKDIR /app # Copy compiled from builder. diff --git a/src/domains/app/app.go b/src/domains/app/app.go index 1537fe9..dbe3bb3 100644 --- a/src/domains/app/app.go +++ b/src/domains/app/app.go @@ -7,7 +7,7 @@ import ( type IAppService interface { Login(ctx context.Context) (response LoginResponse, err error) - LoginWithCode(ctx context.Context, phoneNumber string) (err error) + LoginWithCode(ctx context.Context, phoneNumber string) (loginCode string, err error) Logout(ctx context.Context) (err error) Reconnect(ctx context.Context) (err error) FirstDevice(ctx context.Context) (response DevicesResponse, err error) diff --git a/src/internal/rest/app.go b/src/internal/rest/app.go index a976c90..e9e087a 100644 --- a/src/internal/rest/app.go +++ b/src/internal/rest/app.go @@ -38,14 +38,16 @@ func (handler *App) Login(c *fiber.Ctx) error { } func (handler *App) LoginWithCode(c *fiber.Ctx) error { - err := handler.Service.LoginWithCode(c.UserContext(), c.Query("phone")) + loginCode, err := handler.Service.LoginWithCode(c.UserContext(), c.Query("phone")) utils.PanicIfNeeded(err) return c.JSON(utils.ResponseData{ Status: 200, Code: "SUCCESS", Message: "Login with code success", - Results: nil, + Results: map[string]any{ + "login_code": loginCode, + }, }) } diff --git a/src/services/app.go b/src/services/app.go index d3fef2b..859871a 100644 --- a/src/services/app.go +++ b/src/services/app.go @@ -7,6 +7,8 @@ import ( "github.com/aldinokemal/go-whatsapp-web-multidevice/config" domainApp "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/app" pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error" + "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp" + "github.com/aldinokemal/go-whatsapp-web-multidevice/validations" fiberUtils "github.com/gofiber/fiber/v2/utils" "github.com/sirupsen/logrus" "github.com/skip2/go-qrcode" @@ -90,15 +92,28 @@ func (service serviceApp) Login(_ context.Context) (response domainApp.LoginResp return response, nil } -func (service serviceApp) LoginWithCode(ctx context.Context, phoneNumber string) (err error) { - phone, err := service.WaCli.PairPhone(phoneNumber, true, whatsmeow.PairClientChrome, "Chrome (Linux)") - if err != nil { - return err +func (service serviceApp) LoginWithCode(ctx context.Context, phoneNumber string) (loginCode string, err error) { + if err = validations.ValidateLoginWithCode(ctx, phoneNumber); err != nil { + logrus.Errorf("Error when validate login with code: %s", err.Error()) + return loginCode, err + } + + // detect is already logged in + if service.WaCli.IsLoggedIn() { + return loginCode, pkgError.ErrAlreadyLoggedIn } - logrus.Info("Phone: ", phone) + // check if on whatsapp + if exist := whatsapp.IsOnWhatsapp(service.WaCli, phoneNumber+"@s.whatsapp.net"); !exist { + return loginCode, pkgError.InvalidJID(fmt.Sprintf("Phone %s is not on whatsapp", phoneNumber)) + } + + loginCode, err = service.WaCli.PairPhone(phoneNumber, true, whatsmeow.PairClientChrome, "Chrome") + if err != nil { + return loginCode, err + } - return nil + return loginCode, nil } func (service serviceApp) Logout(_ context.Context) (err error) { diff --git a/src/validations/app_validation.go b/src/validations/app_validation.go new file mode 100644 index 0000000..e9eb1f7 --- /dev/null +++ b/src/validations/app_validation.go @@ -0,0 +1,21 @@ +package validations + +import ( + "context" + "fmt" + pkgError "github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/error" + validation "github.com/go-ozzo/ozzo-validation/v4" + "regexp" +) + +func ValidateLoginWithCode(ctx context.Context, phoneNumber string) error { + // Combine validations using a single ValidateWithContext call + err := validation.ValidateWithContext(ctx, &phoneNumber, + validation.Required, + validation.Match(regexp.MustCompile(`^\+?[0-9]{1,15}$`)), + ) + if err != nil { + return pkgError.ValidationError(fmt.Sprintf("phone_number(%s): %s", phoneNumber, err.Error())) + } + return nil +} diff --git a/src/validations/app_validation_test.go b/src/validations/app_validation_test.go new file mode 100644 index 0000000..5d6a6ec --- /dev/null +++ b/src/validations/app_validation_test.go @@ -0,0 +1,46 @@ +package validations + +import ( + "context" + "testing" +) + +func TestValidateLoginWithCode(t *testing.T) { + type args struct { + phoneNumber string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Phone with +", + args: args{phoneNumber: "+6281234567890"}, + wantErr: false, + }, + { + name: "Phone without +", + args: args{phoneNumber: "621234567890"}, + wantErr: false, + }, + { + name: "Phone with 0", + args: args{phoneNumber: "081234567890"}, + wantErr: false, + }, + { + name: "Phone contains alphabet", + args: args{phoneNumber: "+6281234567890a"}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ValidateLoginWithCode(context.Background(), tt.args.phoneNumber); (err != nil) != tt.wantErr { + t.Errorf("ValidateLoginWithCode() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +}