222 lines
5.7 KiB
Go
222 lines
5.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"git.itzana.me/strafesnet/go-grpc/ranks"
|
|
"git.itzana.me/strafesnet/go-grpc/users"
|
|
"git.itzana.me/strafesnet/public-api/pkg/api/dto"
|
|
"github.com/gin-gonic/gin"
|
|
log "github.com/sirupsen/logrus"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
"net/http"
|
|
"strconv"
|
|
)
|
|
|
|
// UserHandler handles HTTP requests related to users.
|
|
type UserHandler struct {
|
|
*Handler
|
|
}
|
|
|
|
// NewUserHandler creates a new UserHandler with the provided options.
|
|
func NewUserHandler(options ...HandlerOption) (*UserHandler, error) {
|
|
baseHandler, err := NewHandler(options...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &UserHandler{
|
|
Handler: baseHandler,
|
|
}, nil
|
|
}
|
|
|
|
// @Summary Get user by ID
|
|
// @Description Get a specific user by their ID
|
|
// @Tags users
|
|
// @Produce json
|
|
// @Security ApiKeyAuth
|
|
// @Param id path int true "User ID"
|
|
// @Success 200 {object} dto.Response[dto.User]
|
|
// @Failure 404 {object} dto.Error "User not found"
|
|
// @Failure default {object} dto.Error "General error response"
|
|
// @Router /user/{id} [get]
|
|
func (h *UserHandler) Get(ctx *gin.Context) {
|
|
// Extract user ID from path parameter
|
|
id := ctx.Param("id")
|
|
userID, err := strconv.ParseInt(id, 10, 64)
|
|
if err != nil {
|
|
ctx.JSON(http.StatusBadRequest, dto.Error{
|
|
Error: "Invalid user ID format",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Call the gRPC service
|
|
userData, err := users.NewUsersServiceClient(h.dataClient).Get(ctx, &users.IdMessage{
|
|
ID: userID,
|
|
})
|
|
if err != nil {
|
|
statusCode := http.StatusInternalServerError
|
|
errorMessage := "Failed to get user"
|
|
|
|
// Check if it's a "not found" error
|
|
if status.Code(err) == codes.NotFound {
|
|
statusCode = http.StatusNotFound
|
|
errorMessage = "User not found"
|
|
}
|
|
|
|
ctx.JSON(statusCode, dto.Error{
|
|
Error: errorMessage,
|
|
})
|
|
log.WithError(err).Error(
|
|
"Failed to get user",
|
|
)
|
|
return
|
|
}
|
|
|
|
// Convert gRPC UserResponse object to dto.UserData object
|
|
var user dto.User
|
|
result := user.FromGRPC(userData)
|
|
|
|
// Return the user data
|
|
ctx.JSON(http.StatusOK, dto.Response[dto.User]{
|
|
Data: *result,
|
|
})
|
|
}
|
|
|
|
// @Summary Get rank by user ID
|
|
// @Description Get a specific rank for a user by their ID
|
|
// @Tags users
|
|
// @Produce json
|
|
// @Security ApiKeyAuth
|
|
// @Param id path int true "User ID"
|
|
// @Param filter query dto.UserRankFilter true "Rank query parameters"
|
|
// @Success 200 {object} dto.Response[dto.Rank]
|
|
// @Failure 404 {object} dto.Error "User not found"
|
|
// @Failure default {object} dto.Error "General error response"
|
|
// @Router /user/{id}/rank [get]
|
|
func (h *UserHandler) GetRank(ctx *gin.Context) {
|
|
// Extract user ID from path parameter
|
|
id := ctx.Param("id")
|
|
userID, err := strconv.ParseInt(id, 10, 64)
|
|
if err != nil {
|
|
ctx.JSON(http.StatusBadRequest, dto.Error{
|
|
Error: "Invalid user ID format",
|
|
})
|
|
return
|
|
}
|
|
|
|
var filter dto.RankFilter
|
|
if err := ctx.ShouldBindQuery(&filter); err != nil {
|
|
ctx.JSON(http.StatusBadRequest, dto.Error{
|
|
Error: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Call the gRPC service
|
|
rankItem, err := ranks.NewRanksServiceClient(h.dataClient).Get(ctx, &ranks.GetRequest{
|
|
UserID: userID,
|
|
StyleID: filter.StyleID,
|
|
GameID: filter.GameID,
|
|
ModeID: filter.ModeID,
|
|
StateID: []int32{0, 1},
|
|
})
|
|
if err != nil {
|
|
statusCode := http.StatusInternalServerError
|
|
errorMessage := "Failed to get rank"
|
|
|
|
// Check if it's a "not found" error
|
|
if status.Code(err) == codes.NotFound {
|
|
statusCode = http.StatusNotFound
|
|
errorMessage = "Rank not found"
|
|
}
|
|
|
|
ctx.JSON(statusCode, dto.Error{
|
|
Error: errorMessage,
|
|
})
|
|
log.WithError(err).Error(
|
|
"Failed to get rank",
|
|
)
|
|
return
|
|
}
|
|
|
|
// Convert gRPC Rank object to dto.Rank object
|
|
var rank dto.Rank
|
|
result := rank.FromGRPC(rankItem)
|
|
|
|
// Return the user data
|
|
ctx.JSON(http.StatusOK, dto.Response[dto.Rank]{
|
|
Data: *result,
|
|
})
|
|
}
|
|
|
|
// @Summary List users
|
|
// @Description Get a list of users
|
|
// @Tags users
|
|
// @Produce json
|
|
// @Security ApiKeyAuth
|
|
// @Param page_size query int false "Page size (max 100)" default(10) minimum(1) maximum(100)
|
|
// @Param page_number query int false "Page number" default(1) minimum(1)
|
|
// @Param filter query dto.UserFilter false "User filter parameters"
|
|
// @Success 200 {object} dto.PagedResponse[dto.User]
|
|
// @Failure default {object} dto.Error "General error response"
|
|
// @Router /user [get]
|
|
func (h *UserHandler) List(ctx *gin.Context) {
|
|
// Extract and constrain pagination parameters
|
|
query := struct {
|
|
PageSize int `form:"page_size,default=10" binding:"min=1,max=100"`
|
|
PageNumber int `form:"page_number,default=1" binding:"min=1"`
|
|
SortBy int `form:"sort_by,default=0" binding:"min=0,max=3"`
|
|
}{}
|
|
if err := ctx.ShouldBindQuery(&query); err != nil {
|
|
ctx.JSON(http.StatusBadRequest, dto.Error{
|
|
Error: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Get list filter
|
|
var filter dto.UserFilter
|
|
if err := ctx.ShouldBindQuery(&filter); err != nil {
|
|
ctx.JSON(http.StatusBadRequest, dto.Error{
|
|
Error: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Call the gRPC service
|
|
userList, err := users.NewUsersServiceClient(h.dataClient).List(ctx, &users.ListRequest{
|
|
Filter: &users.UserFilter{
|
|
StateID: filter.StateID,
|
|
},
|
|
Page: &users.Pagination{
|
|
Size: int32(query.PageSize),
|
|
Number: int32(query.PageNumber),
|
|
},
|
|
})
|
|
if err != nil {
|
|
ctx.JSON(http.StatusInternalServerError, dto.Error{
|
|
Error: "Failed to list users",
|
|
})
|
|
log.WithError(err).Error(
|
|
"Failed to list users",
|
|
)
|
|
return
|
|
}
|
|
|
|
// Convert gRPC UserResponse objects to dto.UserData objects
|
|
dtoUsers := make([]dto.User, len(userList.Users))
|
|
for i, u := range userList.Users {
|
|
var user dto.User
|
|
dtoUsers[i] = *user.FromGRPC(u)
|
|
}
|
|
|
|
// Return the paged response
|
|
ctx.JSON(http.StatusOK, dto.PagedResponse[dto.User]{
|
|
Data: dtoUsers,
|
|
Pagination: dto.Pagination{
|
|
Page: query.PageNumber,
|
|
PageSize: query.PageSize,
|
|
},
|
|
})
|
|
}
|