diff --git a/go.mod b/go.mod index 3df242e..8a509ae 100644 --- a/go.mod +++ b/go.mod @@ -6,34 +6,34 @@ require ( github.com/go-playground/validator/v10 v10.16.0 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/joho/godotenv v1.5.1 - github.com/labstack/echo/v4 v4.11.2 + github.com/labstack/echo/v4 v4.11.3 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 github.com/wneessen/go-mail v0.4.0 - golang.org/x/crypto v0.14.0 + golang.org/x/crypto v0.15.0 gorm.io/driver/mysql v1.5.2 gorm.io/gorm v1.25.5 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/labstack/gommon v0.4.0 // indirect + github.com/labstack/gommon v0.4.1 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/net v0.18.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 3d99b75..d834c72 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -10,8 +10,9 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -20,19 +21,17 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/labstack/echo/v4 v4.11.2 h1:T+cTLQxWCDfqDEoydYm5kCobjmHwOwcv4OJAPHilmdE= -github.com/labstack/echo/v4 v4.11.2/go.mod h1:UcGuQ8V6ZNRmSweBIJkPvGfwCMIlFmiqrPqiEBfPYws= -github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= -github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/labstack/echo/v4 v4.11.3 h1:Upyu3olaqSHkCjs1EJJwQ3WId8b8b1hxbogyommKktM= +github.com/labstack/echo/v4 v4.11.3/go.mod h1:UcGuQ8V6ZNRmSweBIJkPvGfwCMIlFmiqrPqiEBfPYws= +github.com/labstack/gommon v0.4.1 h1:gqEff0p/hTENGMABzezPoPSRtIh1Cvw0ueMOe0/dfOk= +github.com/labstack/gommon v0.4.1/go.mod h1:TyTrpPqxR5KMk8LKVtLmfMjeQ5FEkBYdxLYPw/WfrOM= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -49,31 +48,26 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/wneessen/go-mail v0.4.0 h1:Oo4HLIV8My7G9JuZkoOX6eipXQD+ACvIqURYeIzUc88= github.com/wneessen/go-mail v0.4.0/go.mod h1:zxOlafWCP/r6FEhAaRgH4IC1vg2YXxO0Nar9u0IScZ8= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= diff --git a/main.go b/main.go index 9044f0c..c755141 100644 --- a/main.go +++ b/main.go @@ -72,14 +72,17 @@ func main() { challengeHandler := hChallenge.NewChallengeHandler(challengeService) e.Pre(middleware.RemoveTrailingSlash()) - e.Use(middleware.CORS()) + e.Use(middleware.CORSWithConfig(middleware.CORSConfig{ + AllowOrigins: []string{"*"}, + AllowMethods: []string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete}, + })) e.Use(middlewares.ConfigureLogging()) e.GET("/", func(c echo.Context) error { return c.String(http.StatusOK, "Hello, Disappear!") }) routes.RouteUser(e, userHandler, jwtService, userService) - routes.RouteAuth(e, authHandler) + routes.RouteAuth(e, authHandler, jwtService, userService) routes.RouteVoucher(e, voucherHandler) routes.RouteProduct(e, productHandler) routes.RouteArticle(e, articleHandler) diff --git a/module/feature/auth/dto/request.go b/module/feature/auth/dto/request.go index 994a53a..9269008 100644 --- a/module/feature/auth/dto/request.go +++ b/module/feature/auth/dto/request.go @@ -18,3 +18,12 @@ type EmailRequest struct { type ResendOTPRequest struct { Email string `form:"email" json:"email" validate:"required"` } + +type ForgotPasswordRequest struct { + Email string `form:"email" json:"email" validate:"required"` +} + +type ResetPasswordRequest struct { + NewPassword string `json:"new_password" validate:"required,min=6"` + ConfirmPassword string `json:"confirm_password" validate:"required,min=6"` +} diff --git a/module/feature/auth/dto/response.go b/module/feature/auth/dto/response.go index d252634..4cb2a87 100644 --- a/module/feature/auth/dto/response.go +++ b/module/feature/auth/dto/response.go @@ -4,3 +4,7 @@ type LoginResponse struct { Email string `json:"email"` AccessToken string `json:"access_token"` } + +type VerifyOTPResponse struct { + AccessToken string `json:"access_token"` +} diff --git a/module/feature/auth/handler/handler.go b/module/feature/auth/handler/handler.go index a31837c..845c33f 100644 --- a/module/feature/auth/handler/handler.go +++ b/module/feature/auth/handler/handler.go @@ -134,3 +134,70 @@ func (h *AuthHandler) ResendOTP() echo.HandlerFunc { } } + +func (h *AuthHandler) ForgotPassword() echo.HandlerFunc { + return func(c echo.Context) error { + var forgotPasswordRequest dto2.ForgotPasswordRequest + if err := c.Bind(&forgotPasswordRequest); err != nil { + return response.SendErrorResponse(c, http.StatusBadRequest, "Format input yang Anda masukkan tidak sesuai.") + } + + if err := utils.ValidateStruct(forgotPasswordRequest); err != nil { + return response.SendErrorResponse(c, http.StatusBadRequest, "Validasi gagal: "+err.Error()) + } + + newOTP, err := h.service.ResendOTP(forgotPasswordRequest.Email) + if err != nil { + return response.SendErrorResponse(c, http.StatusBadRequest, "Gagal mengirim OTP: "+err.Error()) + } + + err = email.EmaiilService(forgotPasswordRequest.Email, newOTP.OTP) + if err != nil { + return response.SendErrorResponse(c, http.StatusBadRequest, "Gagal mengirim OTP ke email: "+err.Error()) + + } + + return response.SendStatusOkResponse(c, "Permintaan OTP berhasil dikirim") + } +} + +func (h *AuthHandler) VerifyOTP() echo.HandlerFunc { + return func(c echo.Context) error { + var emailRequest dto2.EmailRequest + + if err := c.Bind(&emailRequest); err != nil { + return response.SendErrorResponse(c, http.StatusBadRequest, "Format input yang Anda masukkan tidak sesuai.") + } + if err := utils.ValidateStruct(emailRequest); err != nil { + return response.SendErrorResponse(c, http.StatusBadRequest, "Validasi gagal: "+err.Error()) + } + accessToken, err := h.service.VerifyOTP(emailRequest.Email, emailRequest.OTP) + if err != nil { + return response.SendErrorResponse(c, http.StatusBadRequest, "Gagal verifikasi OTP: "+err.Error()) + } + + result := &dto2.VerifyOTPResponse{ + AccessToken: accessToken, + } + return response.SendSuccessResponse(c, "Verifikasi OTP berhasil", result) + } +} + +func (h *AuthHandler) ResetPassword() echo.HandlerFunc { + return func(c echo.Context) error { + var resetPasswordRequest dto2.ResetPasswordRequest + if err := c.Bind(&resetPasswordRequest); err != nil { + return response.SendErrorResponse(c, http.StatusBadRequest, "Gagal Mengikat Data: Pengikatan data ke struktur gagal") + } + + if err := utils.ValidateStruct(resetPasswordRequest); err != nil { + return response.SendErrorResponse(c, http.StatusBadRequest, "Validasi gagal: "+err.Error()) + } + currentUser := c.Get("CurrentUser").(*user.UserModels) + err := h.service.ResetPassword(currentUser.Email, resetPasswordRequest.NewPassword, resetPasswordRequest.ConfirmPassword) + if err != nil { + return response.SendErrorResponse(c, http.StatusInternalServerError, "Gagal mereset kata sandi: "+err.Error()) + } + return response.SendStatusOkResponse(c, "Reset kata sandi berhasil") + } +} diff --git a/module/feature/auth/interface.go b/module/feature/auth/interface.go index 739596c..2f898cf 100644 --- a/module/feature/auth/interface.go +++ b/module/feature/auth/interface.go @@ -13,6 +13,7 @@ type RepositoryAuthInterface interface { FindValidOTP(userID int, otp string) (*entities.OTPModels, error) DeleteOTP(otp *entities.OTPModels) error DeleteUserOTP(userId uint64) error + ResetPassword(email, newPasswordHash string) error } type ServiceAuthInterface interface { @@ -20,6 +21,8 @@ type ServiceAuthInterface interface { Login(email, password string) (*entities.UserModels, string, error) VerifyEmail(email, otp string) error ResendOTP(email string) (*entities.OTPModels, error) + ResetPassword(email, newPassword, confirmPass string) error + VerifyOTP(email, otp string) (string, error) } type HandlerAuthInterface interface { @@ -27,4 +30,7 @@ type HandlerAuthInterface interface { Login() echo.HandlerFunc VerifyEmail() echo.HandlerFunc ResendOTP() echo.HandlerFunc + VerifyOTP() echo.HandlerFunc + ForgotPassword() echo.HandlerFunc + ResetPassword() echo.HandlerFunc } diff --git a/module/feature/auth/repository/repository.go b/module/feature/auth/repository/repository.go index 7260208..d9879b1 100644 --- a/module/feature/auth/repository/repository.go +++ b/module/feature/auth/repository/repository.go @@ -74,3 +74,11 @@ func (r *AuthRepository) DeleteUserOTP(userId uint64) error { return nil } + +func (r *AuthRepository) ResetPassword(email, newPasswordHash string) error { + var user entities.UserModels + if err := r.db.Model(&user).Where("email = ?", email).Update("password", newPasswordHash).Error; err != nil { + return err + } + return nil +} diff --git a/module/feature/auth/service/service.go b/module/feature/auth/service/service.go index 3021e51..1592f05 100644 --- a/module/feature/auth/service/service.go +++ b/module/feature/auth/service/service.go @@ -119,10 +119,7 @@ func (s *AuthService) VerifyEmail(email, otp string) error { func (s *AuthService) ResendOTP(email string) (*entities.OTPModels, error) { user, err := s.userService.GetUsersByEmail(email) if err != nil { - return nil, err - } - if user.ID == 0 { - return nil, errors.New("user tidak ditemukan pada email ini") + return nil, errors.New("pengguna tidak ditemukan") } errDeleteOTP := s.repo.DeleteUserOTP(user.ID) if errDeleteOTP != nil { @@ -141,3 +138,66 @@ func (s *AuthService) ResendOTP(email string) (*entities.OTPModels, error) { } return newOTP, nil } + +func (s *AuthService) ResetPassword(email, newPassword, confirmPass string) error { + user, err := s.userService.GetUsersByEmail(email) + if err != nil { + return errors.New("user tidak ditemukan") + } + if user.ID == 0 { + return errors.New("user tidak ditemukan") + } + + if newPassword != confirmPass { + return errors.New("konfirmasi password tidak cocok") + } + + newPasswordHash, err := s.hash.GenerateHash(newPassword) + if err != nil { + return errors.New("gagal melakukan hash password baru") + } + + err = s.repo.ResetPassword(email, newPasswordHash) + if err != nil { + return errors.New("gagal reset pass: ") + } + return nil +} + +func (s *AuthService) VerifyOTP(email, otp string) (string, error) { + user, err := s.userService.GetUsersByEmail(email) + if err != nil { + return "", err + } + if user == nil { + return "", errors.New("user tidak ditemukan") + } + + isValidOTP, err := s.repo.FindValidOTP(int(user.ID), otp) + if err != nil { + return "", err + } + + if isValidOTP.ID == 0 { + return "", errors.New("Invalid atau OTP telah kadaluarsa") + } + + user.IsVerified = true + + _, errUpdate := s.repo.UpdateUser(user) + if errUpdate != nil { + return "", errors.New("Gagal verifikasi email") + } + + errDeleteOTP := s.repo.DeleteOTP(isValidOTP) + if errDeleteOTP != nil { + return "", errors.New("Gagal delete OTP") + } + + accessToken, err := s.jwt.GenerateJWT(user.ID, user.Role, user.Email) + if err != nil { + return "", errors.New("Gagal generate access token") + } + + return accessToken, nil +} diff --git a/routes/routes.go b/routes/routes.go index fa922c6..c89f072 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -14,11 +14,14 @@ import ( "github.com/labstack/echo/v4" ) -func RouteAuth(e *echo.Echo, h auth.HandlerAuthInterface) { +func RouteAuth(e *echo.Echo, h auth.HandlerAuthInterface, jwtService utils.JWTInterface, userService users.ServiceUserInterface) { e.POST("api/v1/auth/register", h.Register()) e.POST("api/v1/auth/login", h.Login()) e.POST("/api/v1/auth/verify", h.VerifyEmail()) e.POST("/api/v1/auth/resend-otp", h.ResendOTP()) + e.POST("/api/v1/auth/forgot-password", h.ForgotPassword()) + e.POST("/api/v1/auth/forgot-password/verify", h.VerifyOTP()) + e.POST("/api/v1/auth/forgot-password/reset", h.ResetPassword(), middlewares.AuthMiddleware(jwtService, userService)) } func RouteUser(e *echo.Echo, h users.HandlerUserInterface, jwtService utils.JWTInterface, userService users.ServiceUserInterface) {