2025-12-03 19:29:37 +00:00
|
|
|
package handlers
|
|
|
|
|
|
|
|
|
|
import (
|
2026-01-03 17:48:45 +00:00
|
|
|
"context"
|
2025-12-03 19:29:37 +00:00
|
|
|
"fmt"
|
|
|
|
|
"net/http"
|
|
|
|
|
|
2025-12-23 00:51:49 +00:00
|
|
|
apperrors "veza-backend-api/internal/errors"
|
2026-01-03 17:48:45 +00:00
|
|
|
"veza-backend-api/internal/models"
|
2025-12-03 19:29:37 +00:00
|
|
|
"veza-backend-api/internal/services"
|
2026-01-03 17:48:45 +00:00
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
"go.uber.org/zap"
|
2025-12-03 19:29:37 +00:00
|
|
|
)
|
|
|
|
|
|
2026-01-03 17:48:45 +00:00
|
|
|
// ChatServiceInterfaceForChatHandler defines methods needed for chat handler
|
|
|
|
|
type ChatServiceInterfaceForChatHandler interface {
|
|
|
|
|
GenerateToken(userID uuid.UUID, username string) (*services.ChatTokenResponse, error)
|
|
|
|
|
GetStats(ctx context.Context) (*services.ChatStats, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UserServiceInterfaceForChatHandler defines methods needed for chat handler
|
|
|
|
|
type UserServiceInterfaceForChatHandler interface {
|
|
|
|
|
GetByID(userID uuid.UUID) (*models.User, error)
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-03 19:29:37 +00:00
|
|
|
type ChatHandler struct {
|
2026-01-03 17:48:45 +00:00
|
|
|
chatService ChatServiceInterfaceForChatHandler
|
|
|
|
|
userService UserServiceInterfaceForChatHandler
|
2025-12-03 19:29:37 +00:00
|
|
|
logger *zap.Logger
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewChatHandler(chatService *services.ChatService, userService *services.UserService, logger *zap.Logger) *ChatHandler {
|
2026-01-03 17:48:45 +00:00
|
|
|
return &ChatHandler{
|
|
|
|
|
chatService: &chatServiceWrapper{chatService: chatService},
|
|
|
|
|
userService: &userServiceWrapper{userService: userService},
|
|
|
|
|
logger: logger,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// chatServiceWrapper wraps *services.ChatService to implement ChatServiceInterfaceForChatHandler
|
|
|
|
|
type chatServiceWrapper struct {
|
|
|
|
|
chatService *services.ChatService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *chatServiceWrapper) GenerateToken(userID uuid.UUID, username string) (*services.ChatTokenResponse, error) {
|
|
|
|
|
return w.chatService.GenerateToken(userID, username)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *chatServiceWrapper) GetStats(ctx context.Context) (*services.ChatStats, error) {
|
|
|
|
|
return w.chatService.GetStats(ctx)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// userServiceWrapper wraps *services.UserService to implement UserServiceInterfaceForChatHandler
|
|
|
|
|
type userServiceWrapper struct {
|
|
|
|
|
userService *services.UserService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *userServiceWrapper) GetByID(userID uuid.UUID) (*models.User, error) {
|
|
|
|
|
return w.userService.GetByID(userID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewChatHandlerWithInterface creates a new chat handler with interfaces (for testing)
|
|
|
|
|
func NewChatHandlerWithInterface(chatService ChatServiceInterfaceForChatHandler, userService UserServiceInterfaceForChatHandler, logger *zap.Logger) *ChatHandler {
|
2025-12-03 19:29:37 +00:00
|
|
|
return &ChatHandler{
|
|
|
|
|
chatService: chatService,
|
|
|
|
|
userService: userService,
|
|
|
|
|
logger: logger,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-06 16:34:18 +00:00
|
|
|
// GetToken generates a JWT token for the chat service
|
|
|
|
|
// @Summary Get Chat Token
|
|
|
|
|
// @Description Generate a short-lived token for chat authentication
|
|
|
|
|
// @Tags Chat
|
|
|
|
|
// @Accept json
|
|
|
|
|
// @Produce json
|
|
|
|
|
// @Security BearerAuth
|
|
|
|
|
// @Success 200 {object} APIResponse{data=object{token=string}}
|
|
|
|
|
// @Failure 401 {object} APIResponse "Unauthorized"
|
|
|
|
|
// @Failure 500 {object} APIResponse "Internal Error"
|
|
|
|
|
// @Router /chat/token [get]
|
2025-12-03 19:29:37 +00:00
|
|
|
func (h *ChatHandler) GetToken(c *gin.Context) {
|
2025-12-06 16:21:59 +00:00
|
|
|
userIDVal, exists := c.Get("user_id")
|
|
|
|
|
if !exists {
|
|
|
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
userID, ok := userIDVal.(uuid.UUID)
|
|
|
|
|
if !ok || userID == uuid.Nil {
|
2025-12-03 19:29:37 +00:00
|
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get username from DB
|
|
|
|
|
user, err := h.userService.GetByID(userID)
|
|
|
|
|
username := "user"
|
|
|
|
|
if err == nil && user != nil {
|
|
|
|
|
username = user.Username
|
|
|
|
|
} else {
|
|
|
|
|
// Fallback
|
2025-12-06 16:21:59 +00:00
|
|
|
username = fmt.Sprintf("user_%s", userID)
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
token, err := h.chatService.GenerateToken(userID, username)
|
|
|
|
|
if err != nil {
|
|
|
|
|
h.logger.Error("Failed to generate chat token", zap.Error(err))
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate token"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-06 16:21:59 +00:00
|
|
|
RespondSuccess(c, http.StatusOK, token)
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
2025-12-23 00:51:49 +00:00
|
|
|
|
|
|
|
|
// GetStats returns chat statistics
|
|
|
|
|
// BE-API-006: Implement chat stats endpoint
|
|
|
|
|
func (h *ChatHandler) GetStats(c *gin.Context) {
|
|
|
|
|
stats, err := h.chatService.GetStats(c.Request.Context())
|
|
|
|
|
if err != nil {
|
|
|
|
|
h.logger.Error("Failed to get chat stats", zap.Error(err))
|
|
|
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to get chat stats", err))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RespondSuccess(c, http.StatusOK, stats)
|
|
|
|
|
}
|