130 lines
3.4 KiB
Go
130 lines
3.4 KiB
Go
package user
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jinzhu/copier"
|
|
"go.uber.org/fx"
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
"payouts/internal/api/common"
|
|
"payouts/internal/config"
|
|
"payouts/internal/models"
|
|
"payouts/internal/service/cache"
|
|
"payouts/internal/service/database"
|
|
"payouts/internal/service/database/orm"
|
|
)
|
|
|
|
const (
|
|
BaseRoute = "/user"
|
|
RegisterRoute = "/register"
|
|
LoginRoute = "/login"
|
|
)
|
|
|
|
type userHandler struct {
|
|
ttl time.Duration
|
|
dbService database.Service
|
|
cacheService cache.Service
|
|
}
|
|
|
|
// Params represents the module input params
|
|
type Params struct {
|
|
fx.In
|
|
|
|
AppConfig *config.App
|
|
DbService database.Service
|
|
CacheService cache.Service
|
|
}
|
|
|
|
func NewUserHandler(p Params) (Handler, error) {
|
|
return &userHandler{
|
|
ttl: p.AppConfig.Cache.TTL,
|
|
dbService: p.DbService,
|
|
cacheService: p.CacheService,
|
|
}, nil
|
|
}
|
|
|
|
// UserRegister implements [Handler].
|
|
func (u *userHandler) UserRegister(w http.ResponseWriter, r *http.Request) {
|
|
defer r.Body.Close()
|
|
|
|
user := models.UserRegister{}
|
|
err := json.NewDecoder(r.Body).Decode(&user)
|
|
if err != nil {
|
|
common.ErrorResponse(w, "failed to decode request body", err, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if user.Passwd != user.PasswdCfm || len(user.Passwd) == 0 || len(user.Phone) == 0 || len(user.TIN) == 0 {
|
|
common.ErrorResponse(w, "invalid parameters", nil, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Passwd), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
common.ErrorResponse(w, "internal error", nil, http.StatusInternalServerError, common.Reason("failed to get password hash: %v", err))
|
|
return
|
|
}
|
|
user.PasswdHash = string(hashedPassword)
|
|
|
|
ormUser := orm.User{}
|
|
copier.Copy(&ormUser, user)
|
|
|
|
// todo: add data validation
|
|
err = u.dbService.CreateUser(&ormUser, database.WithContext(r.Context()))
|
|
if err != nil {
|
|
common.ErrorResponse(w, "failed to create user", err, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusCreated)
|
|
}
|
|
|
|
// UserLogin implements [Handler].
|
|
func (u *userHandler) UserLogin(w http.ResponseWriter, r *http.Request) {
|
|
defer r.Body.Close()
|
|
|
|
user := models.UserLoginReq{}
|
|
err := json.NewDecoder(r.Body).Decode(&user)
|
|
if err != nil {
|
|
common.ErrorResponse(w, "failed to decode request body", err, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if len(user.Phone) == 0 || len(user.Passwd) == 0 {
|
|
common.ErrorResponse(w, "invalid parameters", nil, http.StatusBadRequest, common.Reason("no user or password passed"))
|
|
return
|
|
}
|
|
|
|
ormUser, err := u.dbService.GetUser(&orm.User{Phone: user.Phone}, database.WithContext(r.Context()))
|
|
if err != nil {
|
|
common.ErrorResponse(w, "invalid credentials", nil, http.StatusUnauthorized, common.Reason("no user found by number %s", user.Phone))
|
|
return
|
|
}
|
|
|
|
err = bcrypt.CompareHashAndPassword([]byte(ormUser.PasswdHash), []byte(user.Passwd))
|
|
if err != nil {
|
|
common.ErrorResponse(w, "invalid credentials", nil, http.StatusUnauthorized, common.Reason("password does not match"))
|
|
return
|
|
}
|
|
|
|
sessionId := uuid.New().String()
|
|
|
|
u.cacheService.PutSession(sessionId, ormUser)
|
|
|
|
resp := models.UserLoginResp{
|
|
Token: sessionId,
|
|
TokenTtl: time.Now().Add(u.ttl).Unix(),
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
err = json.NewEncoder(w).Encode(resp)
|
|
if err != nil {
|
|
common.ErrorResponse(w, "failed to encode response", err, http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|