2023-03-13 09:24:59 +07:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"net/http"
|
2023-03-16 12:21:41 +07:00
|
|
|
"time"
|
2023-03-13 09:24:59 +07:00
|
|
|
|
|
|
|
db "git.nochill.in/nochill/naice_pos/db/sqlc"
|
2023-03-14 12:04:03 +07:00
|
|
|
"git.nochill.in/nochill/naice_pos/util"
|
2023-03-13 09:24:59 +07:00
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/lib/pq"
|
|
|
|
)
|
|
|
|
|
2023-03-14 12:04:03 +07:00
|
|
|
type createUserMerchantRequest struct {
|
2023-03-13 09:24:59 +07:00
|
|
|
Email string `json:"email" binding:"required,email"`
|
2023-03-14 17:39:40 +07:00
|
|
|
Fullname string `json:"fullname" binding:"required,alphanum"`
|
2023-03-13 09:24:59 +07:00
|
|
|
Password string `json:"password" binding:"required"`
|
2023-03-21 13:15:14 +07:00
|
|
|
OutletName string `json:"outlet_name" binding:"required"`
|
2023-03-13 09:24:59 +07:00
|
|
|
}
|
|
|
|
|
2023-03-14 17:39:40 +07:00
|
|
|
type userMerchantResponse struct {
|
2023-03-19 18:55:55 +07:00
|
|
|
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"`
|
|
|
|
OutletID uuid.UUID `json:"outlet_id"`
|
|
|
|
OutletIndexID int64 `json:"outlet_index_id"`
|
|
|
|
OutletName string `json:"outlet_name"`
|
|
|
|
OutletOwnerID uuid.UUID `json:"outlet_owner_id"`
|
2023-03-13 09:24:59 +07:00
|
|
|
}
|
|
|
|
|
2023-03-19 18:55:55 +07:00
|
|
|
func newUserMerchantResponse(user db.GetUserByEmailRow) userMerchantResponse {
|
2023-03-14 17:39:40 +07:00
|
|
|
return userMerchantResponse{
|
2023-03-19 18:55:55 +07:00
|
|
|
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},
|
|
|
|
OutletID: user.ID_2,
|
|
|
|
OutletIndexID: user.IndexID_2,
|
|
|
|
OutletName: user.Name,
|
|
|
|
OutletOwnerID: user.OwnerID,
|
2023-03-14 17:39:40 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-14 12:04:03 +07:00
|
|
|
func (server *Server) createUserMerchant(ctx *gin.Context) {
|
|
|
|
var req createUserMerchantRequest
|
2023-03-13 09:24:59 +07:00
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
2023-03-22 12:06:09 +07:00
|
|
|
ctx.JSON(http.StatusBadRequest, errorResponse(err, ""))
|
2023-03-13 09:24:59 +07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-14 12:04:03 +07:00
|
|
|
hashedPassword, err := util.HashPassword(req.Password)
|
|
|
|
if err != nil {
|
2023-03-22 12:06:09 +07:00
|
|
|
ctx.JSON(http.StatusInternalServerError, errorResponse(err, ""))
|
2023-03-14 12:04:03 +07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-13 09:24:59 +07:00
|
|
|
arg := db.UserMerchantTxParams{
|
|
|
|
Email: req.Email,
|
|
|
|
Fullname: req.Fullname,
|
2023-03-14 12:04:03 +07:00
|
|
|
Password: hashedPassword,
|
2023-03-13 09:24:59 +07:00
|
|
|
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":
|
2023-03-22 12:06:09 +07:00
|
|
|
ctx.JSON(http.StatusConflict, errorResponse(err, ""))
|
2023-03-13 09:24:59 +07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2023-03-22 12:06:09 +07:00
|
|
|
ctx.JSON(http.StatusInternalServerError, errorResponse(err, ""))
|
2023-03-13 09:24:59 +07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-14 17:39:40 +07:00
|
|
|
res := userMerchantResponse{
|
2023-03-19 18:55:55 +07:00
|
|
|
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},
|
|
|
|
OutletID: user.OutletProfile.ID,
|
|
|
|
OutletIndexID: user.OutletProfile.IndexID,
|
|
|
|
OutletName: user.OutletProfile.Name,
|
|
|
|
OutletOwnerID: user.OutletProfile.OwnerID,
|
2023-03-13 09:24:59 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx.JSON(http.StatusOK, res)
|
|
|
|
}
|
2023-03-14 17:39:40 +07:00
|
|
|
|
|
|
|
type userLoginRequest struct {
|
|
|
|
Email string `json:"email" binding:"required,email"`
|
|
|
|
Password string `json:"password" binding:"required"`
|
|
|
|
}
|
|
|
|
|
2023-03-19 18:55:55 +07:00
|
|
|
type userTokenResponse struct {
|
2023-03-16 12:21:41 +07:00
|
|
|
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"`
|
2023-03-19 18:55:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
type userLoginResponse struct {
|
|
|
|
UserTokenResponse userTokenResponse `json:"user_token"`
|
|
|
|
UserMerchantResponse userMerchantResponse `json:"user"`
|
2023-03-14 17:39:40 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (server *Server) loginUser(ctx *gin.Context) {
|
|
|
|
var req userLoginRequest
|
|
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
2023-03-22 12:06:09 +07:00
|
|
|
ctx.JSON(http.StatusBadRequest, errorResponse(err, ""))
|
2023-03-14 17:39:40 +07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
user, err := server.store.GetUserByEmail(ctx, req.Email)
|
|
|
|
if err != nil {
|
|
|
|
if err == sql.ErrNoRows {
|
2023-03-22 12:06:09 +07:00
|
|
|
ctx.JSON(http.StatusNotFound, errorResponse(err, ""))
|
2023-03-14 17:39:40 +07:00
|
|
|
return
|
|
|
|
}
|
2023-03-22 12:06:09 +07:00
|
|
|
ctx.JSON(http.StatusInternalServerError, errorResponse(err, ""))
|
2023-03-14 17:39:40 +07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = util.CheckPassword(req.Password, user.Password)
|
|
|
|
if err != nil {
|
2023-03-22 12:06:09 +07:00
|
|
|
ctx.JSON(http.StatusUnauthorized, errorResponse(err, ""))
|
2023-03-14 17:39:40 +07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-16 12:21:41 +07:00
|
|
|
accessToken, accessPayload, err := server.tokenMaker.CreateToken(
|
2023-03-14 17:39:40 +07:00
|
|
|
user.Email,
|
2023-03-19 18:55:55 +07:00
|
|
|
user.ID_2.String(),
|
2023-03-14 17:39:40 +07:00
|
|
|
server.config.TokenDuration,
|
|
|
|
)
|
|
|
|
|
|
|
|
if err != nil {
|
2023-03-22 12:06:09 +07:00
|
|
|
ctx.JSON(http.StatusInternalServerError, errorResponse(err, ""))
|
2023-03-14 17:39:40 +07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-03-16 12:21:41 +07:00
|
|
|
refreshToken, refreshTokenPayload, err := server.tokenMaker.CreateToken(
|
|
|
|
user.Email,
|
2023-03-19 18:55:55 +07:00
|
|
|
user.ID_2.String(),
|
2023-03-16 12:21:41 +07:00
|
|
|
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 {
|
2023-03-22 12:06:09 +07:00
|
|
|
ctx.JSON(http.StatusInternalServerError, errorResponse(err, ""))
|
2023-03-16 12:21:41 +07:00
|
|
|
return
|
|
|
|
}
|
2023-03-14 17:39:40 +07:00
|
|
|
|
2023-03-19 18:55:55 +07:00
|
|
|
tokenResponse := userTokenResponse{
|
2023-03-16 12:21:41 +07:00
|
|
|
SessionID: session.ID,
|
|
|
|
AccesToken: accessToken,
|
|
|
|
AccessTokenExpiresAt: accessPayload.ExpiredAt,
|
|
|
|
RefreshToken: refreshToken,
|
|
|
|
RefreshTokenExpiresAt: refreshTokenPayload.ExpiredAt,
|
2023-03-19 18:55:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
res := userLoginResponse{
|
|
|
|
UserTokenResponse: tokenResponse,
|
|
|
|
UserMerchantResponse: newUserMerchantResponse(user),
|
2023-03-14 17:39:40 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx.JSON(http.StatusOK, res)
|
|
|
|
}
|