fix error at route
This commit is contained in:
1 parent
ed6776df74
commit
ad8a9c2fa3
8 files changed
+217
-126
No files matched your search
@@ -1 +1,100 @@
|
||||
package controler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"linhdevtran99/rest-api/models"
|
||||
"linhdevtran99/rest-api/rest-api/services"
|
||||
"linhdevtran99/rest-api/utils"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RegisterNewAccount(w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method == http.MethodPost {
|
||||
var registerInfo models.CreateUser
|
||||
|
||||
// get data from body
|
||||
_ = json.NewDecoder(r.Body).Decode(®isterInfo)
|
||||
|
||||
//call function check info user type in
|
||||
_, responseAPI := services.CheckAndValidRegisterFiled(®isterInfo, w)
|
||||
//[fairy ok]
|
||||
|
||||
if responseAPI != nil {
|
||||
return utils.WriteJSON(w, responseAPI.Code, responseAPI.Err)
|
||||
}
|
||||
|
||||
//call function check data user use in past or not
|
||||
isError, responseAPI := services.CheckAccountValid(registerInfo.Username, registerInfo.Email)
|
||||
|
||||
if isError == true {
|
||||
return utils.WriteJSON(w, responseAPI.Code, responseAPI.Err)
|
||||
}
|
||||
|
||||
preUserData := &models.PreusersMongo{
|
||||
Username: registerInfo.Username,
|
||||
Email: registerInfo.Email,
|
||||
PhoneNumber: registerInfo.PhoneNumber,
|
||||
HashPassword: registerInfo.Password,
|
||||
UUID: registerInfo.UUID,
|
||||
CreatedDate: time.Now(),
|
||||
UpdateDate: time.Now(),
|
||||
VerifySentCount: 1,
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
//otpChannel := make(chan models.OtpGenerate, 1)
|
||||
//mailChannel := make(chan models.MailVefiry, 1)
|
||||
done := make(chan struct{})
|
||||
|
||||
var pipelineError error
|
||||
|
||||
wg.Add(1)
|
||||
counter, timerCreate := services.CheckAndWritePreuser(preUserData, &wg, cancel, pipelineError)
|
||||
fmt.Println("counter", counter)
|
||||
fmt.Println("timerCreate", timerCreate)
|
||||
time.Sleep(20 * time.Second)
|
||||
cancel()
|
||||
//wg.Add(1)
|
||||
//go utils.GenOTP(preUserData, counter, 6, w, otpChannel, pipelineError, cancel, &wg)
|
||||
//wg.Add(1)
|
||||
////go utils.EncryptAESMailLink(preUserData, w, mailChannel, &wg, timerCreate)
|
||||
////wg.Add(1)
|
||||
////go services.CreateMailVerify(preUserData, otpChannel, mailChannel, w, errChan)
|
||||
////go services.WriteOTPInRedis(counter, preUserData, otpChannel, w)
|
||||
////wg.Done()
|
||||
////err := <-errChan
|
||||
////close(errChan)
|
||||
////if err != nil {
|
||||
//// fmt.Println("Internal Log: Fail to send email check smtp")
|
||||
//// return err
|
||||
////}
|
||||
////if err == nil {
|
||||
//// _ = utils.WriteJSON(w, http.StatusOK, models.SuccessAPI{
|
||||
//// Message: "Success register account please verify your account",
|
||||
//// })
|
||||
////}
|
||||
////
|
||||
wg.Wait()
|
||||
////create dummy error
|
||||
//err = fmt.Errorf("dummy error")
|
||||
select {
|
||||
case <-done:
|
||||
// Error occurred, wait for all goroutines to finish
|
||||
wg.Wait()
|
||||
case <-ctx.Done():
|
||||
// Context cancelled, wait for all goroutines to finish
|
||||
wg.Wait()
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+2
-52
@@ -6,62 +6,12 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
"linhdevtran99/rest-api/models"
|
||||
"linhdevtran99/rest-api/rest-api/controler"
|
||||
"linhdevtran99/rest-api/rest-api/services"
|
||||
"linhdevtran99/rest-api/utils"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RegisterNewAccount(w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method == http.MethodPost {
|
||||
var registerInfo models.CreateUser
|
||||
|
||||
_ = json.NewDecoder(r.Body).Decode(®isterInfo)
|
||||
//[ok]
|
||||
|
||||
//call function check info user type in
|
||||
validRegisterInfo, responseAPI := services.CheckAndValidRegisterFiled(®isterInfo)
|
||||
//[fairy ok]
|
||||
|
||||
if responseAPI != nil {
|
||||
return utils.WriteJSON(w, responseAPI.Code, responseAPI.Err)
|
||||
}
|
||||
|
||||
fmt.Println(validRegisterInfo)
|
||||
|
||||
//call function check data user use in past or not
|
||||
|
||||
isValidData, responseAPI := services.CheckAccountValid(registerInfo.Username, registerInfo.Email)
|
||||
|
||||
fmt.Println(isValidData)
|
||||
|
||||
if isValidData != true {
|
||||
return utils.WriteJSON(w, responseAPI.Code, responseAPI.Err)
|
||||
}
|
||||
|
||||
preUserData := &models.PreusersMongo{
|
||||
Username: registerInfo.Username,
|
||||
Email: registerInfo.Email,
|
||||
PhoneNumber: registerInfo.PhoneNumber,
|
||||
HashPassword: registerInfo.Password,
|
||||
UUID: registerInfo.UUID,
|
||||
CreatedDate: time.Now(),
|
||||
UpdateDate: time.Now(),
|
||||
VerifySentCount: 1,
|
||||
}
|
||||
|
||||
services.GenerateVerifyAccount(preUserData, w)
|
||||
|
||||
//debug
|
||||
//if isValidData == true || validRegisterInfo == true {
|
||||
// return utils.WriteJSON(w, http.StatusOK, "USER HAVE VALID INFO FOR REGISTER ACCOUNT")
|
||||
//}
|
||||
//debug
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyWithOTP(w http.ResponseWriter, r *http.Request) error {
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
@@ -103,7 +53,7 @@ func VerifyWithJWT(w http.ResponseWriter, r *http.Request) error {
|
||||
}
|
||||
func AuthRouterSetup(router *mux.Router) {
|
||||
authRouter := router.PathPrefix("/account").Subrouter()
|
||||
authRouter.Handle("/register", utils.MakeHTTPHandlerFn(RegisterNewAccount)).Methods("POST")
|
||||
authRouter.Handle("/register", utils.MakeHTTPHandlerFn(controler.RegisterNewAccount)).Methods("POST")
|
||||
authRouter.Handle("/register/verifyAccountOTP", utils.MakeHTTPHandlerFn(VerifyWithOTP)).Methods("POST")
|
||||
authRouter.Handle("/register/verifyAccountJWT", utils.MakeHTTPHandlerFn(VerifyWithJWT)).Methods("POST")
|
||||
}
|
||||
+104
-65
@@ -4,11 +4,13 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-mail/mail"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/google/uuid"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"linhdevtran99/rest-api/models"
|
||||
"linhdevtran99/rest-api/utils"
|
||||
@@ -16,12 +18,13 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CheckAndValidRegisterFiled Check the user register field is valid or not
|
||||
func CheckAndValidRegisterFiled(registerData *models.CreateUser) (bool, *models.ResponseError) {
|
||||
func CheckAndValidRegisterFiled(registerData *models.CreateUser, w http.ResponseWriter) (bool, *models.ResponseError) {
|
||||
_ = models.Validate.RegisterValidation("customPassword", models.PasswordValidator)
|
||||
errs := models.Validate.Struct(registerData)
|
||||
type errStack []string
|
||||
@@ -61,20 +64,25 @@ func CheckAndValidRegisterFiled(registerData *models.CreateUser) (bool, *models.
|
||||
}
|
||||
}
|
||||
//handle repose error
|
||||
return false, &models.ResponseError{Code: http.StatusTooManyRequests, Err: errorAPI}
|
||||
return false, &models.ResponseError{Code: http.StatusBadRequest, Err: errorAPI}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
// CheckAccountExist Checking in db is user input same data in
|
||||
// CheckAccountExist Checking in db is user input same data in add time to resend verify mail
|
||||
func CheckAccountValid(userName string, email string) (bool, *models.ResponseError) {
|
||||
//filter in mongodb
|
||||
var isValid bool
|
||||
var isError bool
|
||||
var errAPI *models.ResponseError
|
||||
var dataRedisRetrive models.RedisOTP
|
||||
|
||||
//create context handler with timeout
|
||||
timeout := 2 * time.Second
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
filter := bson.D{
|
||||
{"$or", bson.A{
|
||||
bson.D{{"username", userName}},
|
||||
@@ -82,13 +90,25 @@ func CheckAccountValid(userName string, email string) (bool, *models.ResponseErr
|
||||
}},
|
||||
}
|
||||
|
||||
_, err := utils.User.FindOne(context.TODO(), filter).Raw()
|
||||
cursor, err := utils.User.Find(ctx, filter)
|
||||
|
||||
if err != nil {
|
||||
isValid = true
|
||||
errAPI = nil
|
||||
} else {
|
||||
fmt.Println("Internal Log: Internal error")
|
||||
isError = true
|
||||
errAPI = &models.ResponseError{
|
||||
Code: http.StatusInternalServerError,
|
||||
Err: models.ErrorAPI{
|
||||
Errors: []string{"Internal error"},
|
||||
Message: "Internal error please try again later",
|
||||
Type: "InternalError",
|
||||
},
|
||||
}
|
||||
return isError, errAPI
|
||||
}
|
||||
|
||||
if cursor.Next(ctx) {
|
||||
fmt.Println("Internal Log: Email or username already had register")
|
||||
isValid = false
|
||||
isError = true
|
||||
errAPI = &models.ResponseError{
|
||||
Code: http.StatusBadRequest,
|
||||
Err: models.ErrorAPI{
|
||||
@@ -98,16 +118,34 @@ func CheckAccountValid(userName string, email string) (bool, *models.ResponseErr
|
||||
},
|
||||
}
|
||||
}
|
||||
retrievedValue, err := utils.Redis.Get(context.Background(), "otp:"+email).Result()
|
||||
err = json.Unmarshal([]byte(retrievedValue), &dataRedisRetrive)
|
||||
|
||||
retrievedValue, err := utils.Redis.Get(ctx, "otp:"+email).Result()
|
||||
if err != nil {
|
||||
fmt.Println("Internal Log: Can't get data from redis")
|
||||
|
||||
if strings.Contains(err.Error(), "dial tcp 10.10.0.217:6391: connect: connection refused") {
|
||||
fmt.Println("Internal Log: Can not connect to redis server")
|
||||
isError = true
|
||||
errAPI = &models.ResponseError{
|
||||
Code: http.StatusInternalServerError,
|
||||
Err: models.ErrorAPI{
|
||||
Errors: []string{"Internal error"},
|
||||
Message: "Internal error please try again later",
|
||||
Type: "InternalError",
|
||||
},
|
||||
}
|
||||
return isError, errAPI
|
||||
}
|
||||
|
||||
if err.Error() == "redis: nil" {
|
||||
fmt.Println("Internal Log: Can't get data from redis or data not exist or first time register")
|
||||
}
|
||||
}
|
||||
err = json.Unmarshal([]byte(retrievedValue), &dataRedisRetrive)
|
||||
|
||||
timeDiff := time.Now().Unix() - dataRedisRetrive.CreatedDate
|
||||
|
||||
if timeDiff < 30 {
|
||||
isValid = false
|
||||
isError = true
|
||||
fmt.Println("Internal Log: Rate limit send verify mail")
|
||||
errAPI = &models.ResponseError{
|
||||
Code: http.StatusBadRequest,
|
||||
@@ -120,7 +158,7 @@ func CheckAccountValid(userName string, email string) (bool, *models.ResponseErr
|
||||
|
||||
}
|
||||
|
||||
return isValid, errAPI
|
||||
return isError, errAPI
|
||||
}
|
||||
|
||||
// GeneratorOtp Generate OTP Verify Link and Qr Link
|
||||
@@ -129,30 +167,8 @@ const (
|
||||
otpDigits = 6
|
||||
)
|
||||
|
||||
func GenerateVerifyAccount(registerInfo *models.PreusersMongo, w http.ResponseWriter) error {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
otpChannel := make(chan models.OtpGenerate, 1)
|
||||
mailChannel := make(chan models.MailVefiry, 1)
|
||||
|
||||
counter, timerCreate := CheckAndWritePreuser(registerInfo, w)
|
||||
wg.Add(1)
|
||||
go utils.GenOTP(registerInfo, counter, otpDigits, w, otpChannel, &wg)
|
||||
wg.Add(1)
|
||||
go utils.EncryptAESMailLink(registerInfo, w, mailChannel, &wg, timerCreate)
|
||||
go createMailVerify(registerInfo, otpChannel, mailChannel, w)
|
||||
go writeOTPInRedis(counter, registerInfo, otpChannel, w)
|
||||
|
||||
wg.Wait()
|
||||
err := utils.WriteJSON(w, http.StatusOK, models.SuccessAPI{
|
||||
Message: "Success register account please verify your account",
|
||||
})
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
// CreateLinkVerify Create a alternative verify link
|
||||
func createMailVerify(registerInfo *models.PreusersMongo, otpChan chan models.OtpGenerate, mailChan chan models.MailVefiry, w http.ResponseWriter) {
|
||||
func CreateMailVerify(registerInfo *models.PreusersMongo, otpChan chan models.OtpGenerate, mailChan chan models.MailVefiry, w http.ResponseWriter, errChan chan error) {
|
||||
smtpPass := os.Getenv("SMTP_PASS")
|
||||
m := mail.NewMessage()
|
||||
|
||||
@@ -179,64 +195,87 @@ func createMailVerify(registerInfo *models.PreusersMongo, otpChan chan models.Ot
|
||||
|
||||
// Send the email to Bob, Cora and Dan.
|
||||
if err := d.DialAndSend(m); err != nil {
|
||||
fmt.Println("Internal Log: Fail to send email check smtp")
|
||||
_ = utils.WriteJSONInternalError(w, "Fail to send email check smtp")
|
||||
panic(err)
|
||||
errChan <- err
|
||||
defer func() {
|
||||
_ = os.Remove("./temp/" + qrFileName)
|
||||
}()
|
||||
return
|
||||
}
|
||||
errChan <- nil
|
||||
|
||||
defer func() {
|
||||
_ = os.Remove("./temp/" + qrFileName)
|
||||
}()
|
||||
}
|
||||
|
||||
// check and write pre use into mongo db
|
||||
func CheckAndWritePreuser(registerInfo *models.PreusersMongo, w http.ResponseWriter) (uint64, time.Time) {
|
||||
// check and write pre use into mongodb
|
||||
func CheckAndWritePreuser(registerInfo *models.PreusersMongo, wg *sync.WaitGroup, ctxCancel context.CancelFunc, errorChan error) (uint64, time.Time) {
|
||||
//generate timestamp
|
||||
timeCreate := time.Now()
|
||||
registerInfo.CreatedDate = timeCreate
|
||||
//create context handler with timeout
|
||||
timeout := 2 * time.Second
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
//checking
|
||||
email := registerInfo.Email
|
||||
count := 1
|
||||
filter := bson.D{{"email", email}}
|
||||
raw, err := utils.PreUserData.FindOne(context.Background(), filter).Raw()
|
||||
if err != nil {
|
||||
|
||||
raw, err := utils.PreUserData.FindOne(ctx, filter).Raw()
|
||||
|
||||
if errors.Is(err, mongo.ErrClientDisconnected) {
|
||||
errorChan = errors.New("can't connect to mongodb")
|
||||
ctxCancel()
|
||||
wg.Done()
|
||||
fmt.Println("Internal Log: Can't connect to mongodb")
|
||||
}
|
||||
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
hashed, err := bcrypt.GenerateFromPassword([]byte(registerInfo.HashPassword), 10)
|
||||
if err != nil {
|
||||
errorChan = errors.New("fail to hash password")
|
||||
ctxCancel()
|
||||
wg.Done()
|
||||
fmt.Println("Internal Log :Fail to hash password")
|
||||
_ = utils.WriteJSONInternalError(w, "Fail to hash password")
|
||||
}
|
||||
registerInfo.HashPassword = string(hashed)
|
||||
_, err = utils.PreUserData.InsertOne(context.Background(), registerInfo)
|
||||
if err != nil {
|
||||
errorChan = errors.New("can't insert data to PreUser")
|
||||
ctxCancel()
|
||||
wg.Done()
|
||||
fmt.Println("Internal Log: Can't Insert Data To PreUser")
|
||||
_ = utils.WriteJSONInternalError(w, "Can't Insert Data To PreUser")
|
||||
}
|
||||
return uint64(count), timeCreate
|
||||
} else {
|
||||
update := bson.D{
|
||||
{"$inc", bson.D{
|
||||
{"verify_sent_count", 1},
|
||||
}},
|
||||
{"$set", bson.D{
|
||||
{"update_date", timeCreate},
|
||||
},
|
||||
}}
|
||||
|
||||
_, err := utils.PreUserData.UpdateOne(context.Background(), filter, update)
|
||||
if err != nil {
|
||||
fmt.Println("Internal log: Update document fail")
|
||||
_ = utils.WriteJSONInternalError(w, "Update document fail")
|
||||
}
|
||||
fmt.Println()
|
||||
count = int(raw.Lookup("verify_sent_count").Int32() + 1)
|
||||
wg.Done()
|
||||
return uint64(count), timeCreate
|
||||
}
|
||||
|
||||
update := bson.D{
|
||||
{"$inc", bson.D{
|
||||
{"verify_sent_count", 1},
|
||||
}},
|
||||
{"$set", bson.D{
|
||||
{"update_date", timeCreate},
|
||||
},
|
||||
}}
|
||||
|
||||
_, err = utils.PreUserData.UpdateOne(context.Background(), filter, update)
|
||||
if err != nil {
|
||||
errorChan = errors.New("update document fail")
|
||||
ctxCancel()
|
||||
wg.Done()
|
||||
fmt.Println("Internal log: Update document fail")
|
||||
}
|
||||
count = int(raw.Lookup("verify_sent_count").Int32() + 1)
|
||||
wg.Done()
|
||||
return uint64(count), timeCreate
|
||||
|
||||
}
|
||||
|
||||
//write otp in redis for valid if otp expired
|
||||
|
||||
func writeOTPInRedis(counter uint64, registerInfo *models.PreusersMongo, otpChan chan models.OtpGenerate, w http.ResponseWriter) {
|
||||
func WriteOTPInRedis(counter uint64, registerInfo *models.PreusersMongo, otpChan chan models.OtpGenerate, w http.ResponseWriter) {
|
||||
|
||||
otp := <-otpChan
|
||||
|
||||
|
||||
Reference in new issue
Block a user