[BE-API-006] be-api: Implement chat stats endpoint
- Added GetStats method to ChatService with database access - Returns active_users (distinct users who sent messages in last 24h) - Returns total_messages (non-deleted messages count) - Returns rooms_active (rooms with messages in last 24h) - Added GetStats handler and GET /chat/stats route - Updated ChatService to use NewChatServiceWithDB for database access Phase: PHASE-2 Priority: P1 Progress: 15/267 (5.6%)
This commit is contained in:
parent
6960d666e6
commit
36548a32cf
4 changed files with 93 additions and 2 deletions
|
|
@ -1378,7 +1378,19 @@
|
|||
"description": "GET /api/v1/chat/stats returns active_users, total_messages, rooms_active",
|
||||
"owner": "backend",
|
||||
"estimated_hours": 2,
|
||||
"status": "todo",
|
||||
"status": "completed",
|
||||
"completion": {
|
||||
"completed_at": "2025-12-23T00:51:44Z",
|
||||
"actual_hours": 0.5,
|
||||
"commits": [],
|
||||
"files_changed": [
|
||||
"veza-backend-api/internal/services/chat_service.go",
|
||||
"veza-backend-api/internal/handlers/chat_handler.go",
|
||||
"veza-backend-api/internal/api/router.go"
|
||||
],
|
||||
"notes": "Added GetStats method to ChatService with database access. Returns active_users (distinct users who sent messages in last 24h), total_messages (non-deleted messages), and rooms_active (rooms with messages in last 24h). Added GetStats handler and GET /chat/stats route. Updated ChatService to use NewChatServiceWithDB for database access.",
|
||||
"issues_encountered": []
|
||||
},
|
||||
"files_involved": [],
|
||||
"implementation_steps": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -500,7 +500,8 @@ func (r *APIRouter) setupTrackRoutes(router *gin.RouterGroup) {
|
|||
|
||||
// setupChatRoutes configure les routes de chat
|
||||
func (r *APIRouter) setupChatRoutes(router *gin.RouterGroup) {
|
||||
chatService := services.NewChatService(r.config.ChatJWTSecret, r.logger)
|
||||
// BE-API-006: Use NewChatServiceWithDB to enable stats functionality
|
||||
chatService := services.NewChatServiceWithDB(r.config.ChatJWTSecret, r.db.GormDB, r.logger)
|
||||
userRepo := repositories.NewGormUserRepository(r.db.GormDB)
|
||||
userService := services.NewUserServiceWithDB(userRepo, r.db.GormDB)
|
||||
|
||||
|
|
@ -511,6 +512,7 @@ func (r *APIRouter) setupChatRoutes(router *gin.RouterGroup) {
|
|||
if r.config.AuthMiddleware != nil {
|
||||
chat.Use(r.config.AuthMiddleware.RequireAuth())
|
||||
chat.POST("/token", chatHandler.GetToken)
|
||||
chat.GET("/stats", chatHandler.GetStats) // BE-API-006: Chat stats endpoint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
apperrors "veza-backend-api/internal/errors"
|
||||
"veza-backend-api/internal/services"
|
||||
)
|
||||
|
||||
|
|
@ -66,3 +67,16 @@ func (h *ChatHandler) GetToken(c *gin.Context) {
|
|||
|
||||
RespondSuccess(c, http.StatusOK, token)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
|
|
@ -8,11 +9,14 @@ import (
|
|||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
"veza-backend-api/internal/models"
|
||||
)
|
||||
|
||||
type ChatService struct {
|
||||
jwtSecret string
|
||||
logger *zap.Logger
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewChatService(jwtSecret string, logger *zap.Logger) *ChatService {
|
||||
|
|
@ -25,6 +29,18 @@ func NewChatService(jwtSecret string, logger *zap.Logger) *ChatService {
|
|||
}
|
||||
}
|
||||
|
||||
// NewChatServiceWithDB crée un nouveau ChatService avec accès à la base de données
|
||||
func NewChatServiceWithDB(jwtSecret string, db *gorm.DB, logger *zap.Logger) *ChatService {
|
||||
if logger == nil {
|
||||
logger = zap.NewNop()
|
||||
}
|
||||
return &ChatService{
|
||||
jwtSecret: jwtSecret,
|
||||
logger: logger,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
type ChatTokenResponse struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresIn int64 `json:"expires_in"`
|
||||
|
|
@ -61,3 +77,50 @@ func (s *ChatService) GenerateToken(userID uuid.UUID, username string) (*ChatTok
|
|||
WSUrl: "/ws", // Relative path, frontend appends base URL
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ChatStats représente les statistiques du chat
|
||||
type ChatStats struct {
|
||||
ActiveUsers int64 `json:"active_users"`
|
||||
TotalMessages int64 `json:"total_messages"`
|
||||
RoomsActive int64 `json:"rooms_active"`
|
||||
}
|
||||
|
||||
// GetStats récupère les statistiques du chat
|
||||
// BE-API-006: Implement chat stats endpoint
|
||||
func (s *ChatService) GetStats(ctx context.Context) (*ChatStats, error) {
|
||||
if s.db == nil {
|
||||
return nil, errors.New("database connection not available")
|
||||
}
|
||||
|
||||
stats := &ChatStats{}
|
||||
|
||||
// Total messages (non supprimés)
|
||||
if err := s.db.WithContext(ctx).Model(&models.Message{}).
|
||||
Where("is_deleted = ?", false).
|
||||
Count(&stats.TotalMessages).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to count total messages: %w", err)
|
||||
}
|
||||
|
||||
// Active users: utilisateurs distincts qui ont envoyé des messages dans les dernières 24h
|
||||
activeSince := time.Now().Add(-24 * time.Hour)
|
||||
var activeUsersCount int64
|
||||
if err := s.db.WithContext(ctx).Model(&models.Message{}).
|
||||
Where("is_deleted = ? AND created_at >= ?", false, activeSince).
|
||||
Distinct("user_id").
|
||||
Count(&activeUsersCount).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to count active users: %w", err)
|
||||
}
|
||||
stats.ActiveUsers = activeUsersCount
|
||||
|
||||
// Rooms actives: rooms qui ont eu des messages dans les dernières 24h
|
||||
var roomsActiveCount int64
|
||||
if err := s.db.WithContext(ctx).Model(&models.Message{}).
|
||||
Where("is_deleted = ? AND created_at >= ?", false, activeSince).
|
||||
Distinct("room_id").
|
||||
Count(&roomsActiveCount).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to count active rooms: %w", err)
|
||||
}
|
||||
stats.RoomsActive = roomsActiveCount
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue