naise_pos/api/user.go

176 lines
4.8 KiB
Go

package api
import (
"database/sql"
"net/http"
"time"
db "git.nochill.in/nochill/naice_pos/db/sqlc"
"git.nochill.in/nochill/naice_pos/util"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/lib/pq"
)
type createUserMerchantRequest struct {
Email string `json:"email" binding:"required,email"`
Fullname string `json:"fullname" binding:"required,alphanum"`
Password string `json:"password" binding:"required"`
OutletName string `json:"outlet_name" binding:"required,alphanum"`
}
type userMerchantResponse struct {
ID uuid.UUID `json:"id"`
IndexID int64 `json:"index_id"`
Email string `json:"email"`
Fullname string `json:"fullname"`
CreatedAt sql.NullTime `json:"created_at"`
UpdatedAt sql.NullTime `json:"updated_at"`
Outlet db.Merchant `json:"outlet"`
}
func newUserMerchantResponse(user db.GetUserByEmailRow, merchant db.Merchant) userMerchantResponse {
return userMerchantResponse{
ID: user.ID,
IndexID: user.IndexID,
Email: user.Email,
Fullname: user.Fullname,
CreatedAt: sql.NullTime{Valid: true, Time: user.CreatedAt.Time},
UpdatedAt: sql.NullTime{Valid: true, Time: user.UpdatedAt.Time},
Outlet: merchant,
}
}
func (server *Server) createUserMerchant(ctx *gin.Context) {
var req createUserMerchantRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
hashedPassword, err := util.HashPassword(req.Password)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
arg := db.UserMerchantTxParams{
Email: req.Email,
Fullname: req.Fullname,
Password: hashedPassword,
OutletName: req.OutletName,
}
user, err := server.store.CreateUserMerchantTx(ctx, arg)
if err != nil {
if pqErr, ok := err.(*pq.Error); ok {
switch pqErr.Code.Name() {
case "foreign_key_violation", "unique_violation":
ctx.JSON(http.StatusConflict, errorResponse(err))
return
}
}
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
res := userMerchantResponse{
ID: user.OwnerProfile.ID,
IndexID: user.OwnerProfile.IndexID,
Email: user.OwnerProfile.Email,
Fullname: user.OwnerProfile.Fullname,
CreatedAt: sql.NullTime{Valid: true, Time: user.OwnerProfile.CreatedAt.Time},
UpdatedAt: sql.NullTime{Valid: true, Time: user.OwnerProfile.UpdatedAt.Time},
Outlet: user.OutletProfile,
}
ctx.JSON(http.StatusOK, res)
}
type userLoginRequest struct {
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required"`
}
type userLoginResponse struct {
SessionID uuid.UUID `json:"session_id"`
AccesToken string `json:"access_token"`
AccessTokenExpiresAt time.Time `json:"access_token_expires_at"`
RefreshToken string `json:"refresh_token"`
RefreshTokenExpiresAt time.Time `json:"refresh_token_expires_at"`
UserMerchantResponse userMerchantResponse
}
func (server *Server) loginUser(ctx *gin.Context) {
var req userLoginRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
user, err := server.store.GetUserByEmail(ctx, req.Email)
if err != nil {
if err == sql.ErrNoRows {
ctx.JSON(http.StatusNotFound, errorResponse(err))
return
}
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
outlet, err := server.store.GetMerchantByUserId(ctx, user.ID)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
err = util.CheckPassword(req.Password, user.Password)
if err != nil {
ctx.JSON(http.StatusUnauthorized, errorResponse(err))
return
}
accessToken, accessPayload, err := server.tokenMaker.CreateToken(
user.Email,
outlet.ID.String(),
server.config.TokenDuration,
)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
refreshToken, refreshTokenPayload, err := server.tokenMaker.CreateToken(
user.Email,
outlet.ID.String(),
server.config.RefreshTokenDuration,
)
session, err := server.store.CreateSession(ctx, db.CreateSessionParams{
ID: refreshTokenPayload.ID,
Email: user.Email,
RefreshToken: refreshToken,
UserAgent: ctx.Request.UserAgent(),
ClientIp: ctx.ClientIP(),
IsBlocked: false,
ExpiresAt: refreshTokenPayload.ExpiredAt,
})
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
res := userLoginResponse{
SessionID: session.ID,
AccesToken: accessToken,
AccessTokenExpiresAt: accessPayload.ExpiredAt,
RefreshToken: refreshToken,
RefreshTokenExpiresAt: refreshTokenPayload.ExpiredAt,
UserMerchantResponse: newUserMerchantResponse(user, outlet),
}
ctx.JSON(http.StatusOK, res)
}