asd
This commit is contained in:
@@ -3,6 +3,7 @@ package socialrating
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
@@ -26,10 +27,79 @@ type ChangeResponse struct {
|
||||
CurrentRating models.UserSocialRating `json:"currentRating"`
|
||||
}
|
||||
|
||||
type UsersResponse struct {
|
||||
Users []UserWithRating `json:"users"`
|
||||
}
|
||||
|
||||
type UserRatingResponse struct {
|
||||
User UserWithRating `json:"user"`
|
||||
}
|
||||
|
||||
type HistoryResponse struct {
|
||||
Operations []models.SocialRatingOperation `json:"operations"`
|
||||
}
|
||||
|
||||
func NewHandler(service Service) Handler {
|
||||
return Handler{Service: service}
|
||||
}
|
||||
|
||||
func (h Handler) ListUsers(ctx *gin.Context) {
|
||||
limit := parsePositiveLimit(ctx.Query("limit"), 50)
|
||||
|
||||
users, err := h.Service.ListUsersWithRatings(limit)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load users"})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, UsersResponse{Users: users})
|
||||
}
|
||||
|
||||
func (h Handler) GetUser(ctx *gin.Context) {
|
||||
userID, err := parseUintParam(ctx.Param("userId"))
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.Service.GetUserRating(userID)
|
||||
if err != nil {
|
||||
handleApplyChangeError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, UserRatingResponse{User: user})
|
||||
}
|
||||
|
||||
func (h Handler) GetUserHistory(ctx *gin.Context) {
|
||||
userID, err := parseUintParam(ctx.Param("userId"))
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
limit := parsePositiveLimit(ctx.Query("limit"), 50)
|
||||
operations, err := h.Service.GetUserHistory(userID, limit)
|
||||
if err != nil {
|
||||
handleApplyChangeError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, HistoryResponse{Operations: operations})
|
||||
}
|
||||
|
||||
func (h Handler) GetRecentOperations(ctx *gin.Context) {
|
||||
limit := parsePositiveLimit(ctx.Query("limit"), 50)
|
||||
|
||||
operations, err := h.Service.GetRecentOperations(limit)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load operations"})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, HistoryResponse{Operations: operations})
|
||||
}
|
||||
|
||||
func (h Handler) Increase(ctx *gin.Context) {
|
||||
h.applySignedChange(ctx, "increase", 1)
|
||||
}
|
||||
@@ -97,3 +167,12 @@ func handleApplyChangeError(ctx *gin.Context, err error) {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
}
|
||||
}
|
||||
|
||||
func parseUintParam(raw string) (uint, error) {
|
||||
value, err := strconv.ParseUint(raw, 10, 64)
|
||||
if err != nil || value == 0 {
|
||||
return 0, errors.New("invalid user id")
|
||||
}
|
||||
|
||||
return uint(value), nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package socialrating
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
@@ -22,6 +24,16 @@ type ChangeInput struct {
|
||||
Source string
|
||||
}
|
||||
|
||||
type UserWithRating struct {
|
||||
ID uint `json:"id"`
|
||||
Email string `json:"email"`
|
||||
IsAdmin bool `json:"isAdmin"`
|
||||
Score int `json:"score"`
|
||||
LastOperationID *uint `json:"lastOperationId,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func NewService(db *gorm.DB) Service {
|
||||
return Service{DB: db}
|
||||
}
|
||||
@@ -95,3 +107,131 @@ func ensureUserExists(tx *gorm.DB, userID uint) error {
|
||||
var user models.User
|
||||
return tx.First(&user, "id = ?", userID).Error
|
||||
}
|
||||
|
||||
func (s Service) ListUsersWithRatings(limit int) ([]UserWithRating, error) {
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
}
|
||||
|
||||
var rows []struct {
|
||||
ID uint
|
||||
Email string
|
||||
IsAdmin bool
|
||||
Score int
|
||||
LastOperationID *uint
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
err := s.DB.
|
||||
Table("users").
|
||||
Select(
|
||||
"users.id, users.email, users.is_admin, COALESCE(user_social_ratings.score, 0) AS score, user_social_ratings.last_operation_id, users.created_at, users.updated_at",
|
||||
).
|
||||
Joins("LEFT JOIN user_social_ratings ON user_social_ratings.user_id = users.id").
|
||||
Order("score DESC, users.id ASC").
|
||||
Limit(limit).
|
||||
Scan(&rows).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]UserWithRating, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
result = append(result, UserWithRating{
|
||||
ID: row.ID,
|
||||
Email: row.Email,
|
||||
IsAdmin: row.IsAdmin,
|
||||
Score: row.Score,
|
||||
LastOperationID: row.LastOperationID,
|
||||
CreatedAt: row.CreatedAt,
|
||||
UpdatedAt: row.UpdatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s Service) GetUserRating(userID uint) (UserWithRating, error) {
|
||||
var row struct {
|
||||
ID uint
|
||||
Email string
|
||||
IsAdmin bool
|
||||
Score int
|
||||
LastOperationID *uint
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
err := s.DB.
|
||||
Table("users").
|
||||
Select(
|
||||
"users.id, users.email, users.is_admin, COALESCE(user_social_ratings.score, 0) AS score, user_social_ratings.last_operation_id, users.created_at, users.updated_at",
|
||||
).
|
||||
Joins("LEFT JOIN user_social_ratings ON user_social_ratings.user_id = users.id").
|
||||
Where("users.id = ?", userID).
|
||||
Take(&row).Error
|
||||
if err != nil {
|
||||
return UserWithRating{}, err
|
||||
}
|
||||
|
||||
return UserWithRating{
|
||||
ID: row.ID,
|
||||
Email: row.Email,
|
||||
IsAdmin: row.IsAdmin,
|
||||
Score: row.Score,
|
||||
LastOperationID: row.LastOperationID,
|
||||
CreatedAt: row.CreatedAt,
|
||||
UpdatedAt: row.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s Service) GetUserHistory(userID uint, limit int) ([]models.SocialRatingOperation, error) {
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
}
|
||||
|
||||
if err := ensureUserExists(s.DB, userID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var operations []models.SocialRatingOperation
|
||||
err := s.DB.
|
||||
Where("target_user_id = ?", userID).
|
||||
Order("created_at DESC, id DESC").
|
||||
Limit(limit).
|
||||
Find(&operations).Error
|
||||
|
||||
return operations, err
|
||||
}
|
||||
|
||||
func (s Service) GetRecentOperations(limit int) ([]models.SocialRatingOperation, error) {
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
}
|
||||
|
||||
var operations []models.SocialRatingOperation
|
||||
err := s.DB.
|
||||
Order("created_at DESC, id DESC").
|
||||
Limit(limit).
|
||||
Find(&operations).Error
|
||||
|
||||
return operations, err
|
||||
}
|
||||
|
||||
func parsePositiveLimit(raw string, fallback int) int {
|
||||
if raw == "" {
|
||||
return fallback
|
||||
}
|
||||
|
||||
value, err := strconv.Atoi(raw)
|
||||
if err != nil || value <= 0 {
|
||||
return fallback
|
||||
}
|
||||
|
||||
if value > 200 {
|
||||
return 200
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user