769e76313f
- Recovery middleware (no more crash-on-panic), request metrics/monitoring store + admin API, in-memory TTL caching for read-heavy option/question/ category lookups, gzip + rate-limiting middleware, sanitized chat message encoding, and pg_dump-based database backups with an admin API. - Fix N+1 queries in the discover feed, candidate detail, and match list endpoints by batching selection/photo/user/last-message lookups into single queries instead of one-per-item loops. - Tune DB connection pooling and add HTTP server timeouts + graceful shutdown so the API degrades gracefully instead of falling over under load. - Fix a null (vs empty array) JSON response for candidates/matches without photos or interests, which crashed the web app's swipe card.
92 lines
2.3 KiB
Go
92 lines
2.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"dating-app/internal/dto"
|
|
"dating-app/internal/service"
|
|
"dating-app/internal/utils"
|
|
)
|
|
|
|
type ChatHandler struct {
|
|
chatService *service.ChatService
|
|
}
|
|
|
|
func NewChatHandler(chatService *service.ChatService) *ChatHandler {
|
|
return &ChatHandler{chatService: chatService}
|
|
}
|
|
|
|
// ListMatches GET /matches
|
|
func (h *ChatHandler) ListMatches(c *gin.Context) {
|
|
user, ok := currentUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
matches, err := h.chatService.ListMatches(user.ID)
|
|
if err != nil {
|
|
utils.Fail(c, http.StatusInternalServerError, "خطا در دریافت مچها", nil)
|
|
return
|
|
}
|
|
utils.Success(c, http.StatusOK, "", matches)
|
|
}
|
|
|
|
// ListMessages GET /matches/:id/messages
|
|
func (h *ChatHandler) ListMessages(c *gin.Context) {
|
|
user, ok := currentUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
matchID, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
utils.Fail(c, http.StatusBadRequest, "شناسه نامعتبر است", nil)
|
|
return
|
|
}
|
|
messages, err := h.chatService.ListMessages(user.ID, uint(matchID))
|
|
if err != nil {
|
|
h.handleError(c, err)
|
|
return
|
|
}
|
|
utils.Success(c, http.StatusOK, "", messages)
|
|
}
|
|
|
|
// SendMessage POST /matches/:id/messages body: {text}
|
|
func (h *ChatHandler) SendMessage(c *gin.Context) {
|
|
user, ok := currentUser(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
matchID, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
utils.Fail(c, http.StatusBadRequest, "شناسه نامعتبر است", nil)
|
|
return
|
|
}
|
|
var req dto.SendMessageRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
utils.Fail(c, http.StatusBadRequest, "متن پیام نمیتونه خالی باشه", err.Error())
|
|
return
|
|
}
|
|
msg, err := h.chatService.SendMessage(user.ID, uint(matchID), req.Text)
|
|
if err != nil {
|
|
h.handleError(c, err)
|
|
return
|
|
}
|
|
utils.Success(c, http.StatusCreated, "", msg)
|
|
}
|
|
|
|
func (h *ChatHandler) handleError(c *gin.Context, err error) {
|
|
switch {
|
|
case errors.Is(err, service.ErrNotMatchMember):
|
|
utils.Fail(c, http.StatusForbidden, err.Error(), nil)
|
|
case errors.Is(err, utils.ErrInvalidMessageEncoding),
|
|
errors.Is(err, utils.ErrMessageEmpty),
|
|
errors.Is(err, utils.ErrMessageTooLong):
|
|
utils.Fail(c, http.StatusBadRequest, err.Error(), nil)
|
|
default:
|
|
utils.Fail(c, http.StatusNotFound, "گفتگو یافت نشد", nil)
|
|
}
|
|
}
|