tailly_back_v2/internal/http/graph/message_resolvers.go
madipo2611 6f5298d420 v0.0.3
2025-05-03 02:37:08 +03:00

207 lines
6.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package graph
import (
"context"
"errors"
"fmt"
"tailly_back_v2/internal/domain"
"tailly_back_v2/internal/ws"
"time"
)
type messageResolver struct{ *Resolver }
// GetChatHistory - возвращает историю сообщений
func (r *queryResolver) GetChatHistory(ctx context.Context, userID int) ([]*domain.Message, error) {
currentUserID, err := getUserIDFromContext(ctx)
if err != nil {
return nil, errors.New("не авторизован")
}
chat, err := r.Services.Chat.GetOrCreateChat(ctx, currentUserID, userID)
if err != nil {
return nil, fmt.Errorf("ошибка получения чата: %v", err)
}
messages, err := r.Services.Chat.GetChatMessages(ctx, chat.ID, currentUserID, 50, 0)
if err != nil {
return nil, fmt.Errorf("ошибка получения сообщений: %v", err)
}
return messages, nil
}
// GetUserChats - возвращает чаты пользователя
func (r *queryResolver) GetUserChats(ctx context.Context) ([]*ChatSession, error) {
userID, err := getUserIDFromContext(ctx)
if err != nil {
return nil, errors.New("не авторизован")
}
// Получаем чаты пользователя
chats, err := r.Services.Chat.GetUserChats(ctx, userID)
if err != nil {
return nil, fmt.Errorf("ошибка получения чатов: %v", err)
}
var sessions []*ChatSession
for _, chat := range chats {
// Определяем другого участника чата
otherUserID := chat.User1ID
if userID == chat.User1ID {
otherUserID = chat.User2ID
}
// Получаем данные другого пользователя
otherUser, err := r.Services.User.GetByID(ctx, otherUserID)
if err != nil {
return nil, fmt.Errorf("ошибка получения пользователя %d: %v", otherUserID, err)
}
// Получаем последнее сообщение
messages, err := r.Services.Chat.GetChatMessages(ctx, chat.ID, userID, 1, 0)
if err != nil {
return nil, fmt.Errorf("ошибка получения сообщений: %v", err)
}
var lastMessage *domain.Message
if len(messages) > 0 {
lastMessage = messages[0]
} else {
// Если нет сообщений, возвращаем ошибку, так как в схеме lastMessage обязательное поле
continue
}
// Получаем количество непрочитанных сообщений
unreadCount, err := r.chatRepo.GetUnreadCount(ctx, chat.ID, userID)
if err != nil {
return nil, fmt.Errorf("ошибка получения количества непрочитанных: %v", err)
}
sessions = append(sessions, &ChatSession{
User: otherUser,
LastMessage: lastMessage,
UnreadCount: unreadCount,
})
}
return sessions, nil
}
// Sender - возвращает отправителя сообщения
func (r *messageResolver) Sender(ctx context.Context, obj *domain.Message) (*domain.User, error) {
user, err := r.Services.User.GetByID(ctx, obj.SenderID)
if err != nil {
return nil, fmt.Errorf("ошибка получения отправителя: %v", err)
}
return user, nil
}
// Receiver - возвращает получателя сообщения
func (r *messageResolver) Receiver(ctx context.Context, obj *domain.Message) (*domain.User, error) {
chat, err := r.chatRepo.GetChatByID(ctx, obj.ChatID)
if err != nil {
return nil, fmt.Errorf("ошибка получения чата: %v", err)
}
receiverID := chat.User1ID
if obj.SenderID == chat.User1ID {
receiverID = chat.User2ID
}
user, err := r.Services.User.GetByID(ctx, receiverID)
if err != nil {
return nil, fmt.Errorf("ошибка получения получателя: %v", err)
}
return user, nil
}
// CreatedAt - форматирует время сообщения
func (r *messageResolver) CreatedAt(ctx context.Context, obj *domain.Message) (string, error) {
return obj.CreatedAt.Format(time.RFC3339), nil
}
// SendMessage - отправляет сообщение
func (r *mutationResolver) SendMessage(ctx context.Context, receiverID int, content string) (*domain.Message, error) {
senderID, err := getUserIDFromContext(ctx)
if err != nil {
return nil, errors.New("не авторизован")
}
chat, err := r.Services.Chat.GetOrCreateChat(ctx, senderID, receiverID)
if err != nil {
return nil, fmt.Errorf("ошибка создания чата: %v", err)
}
message, err := r.Services.Chat.SendMessage(ctx, senderID, chat.ID, content)
if err != nil {
return nil, fmt.Errorf("ошибка отправки сообщения: %v", err)
}
return message, nil
}
// MarkAsRead - помечает сообщение как прочитанное
func (r *mutationResolver) MarkAsRead(ctx context.Context, messageID int) (bool, error) {
userID, err := getUserIDFromContext(ctx)
if err != nil {
return false, errors.New("не авторизован")
}
// Получаем сообщение напрямую из репозитория
message, err := r.chatRepo.GetMessageByID(ctx, messageID)
if err != nil {
return false, fmt.Errorf("ошибка получения сообщения: %v", err)
}
// Проверяем доступ к сообщению
chat, err := r.chatRepo.GetChatByID(ctx, message.ChatID)
if err != nil {
return false, fmt.Errorf("ошибка получения чата: %v", err)
}
if userID != chat.User1ID && userID != chat.User2ID {
return false, errors.New("нет доступа к сообщению")
}
err = r.Services.Chat.MarkAsRead(ctx, messageID)
if err != nil {
return false, fmt.Errorf("ошибка обновления статуса: %v", err)
}
return true, nil
}
type subscriptionResolver struct{ *Resolver }
// Subscription returns SubscriptionResolver implementation.
func (r *Resolver) Subscription() SubscriptionResolver { return &subscriptionResolver{r} }
// MessageReceived - подписка на новые сообщения
func (r *subscriptionResolver) MessageReceived(ctx context.Context) (<-chan *domain.Message, error) {
userID, err := getUserIDFromContext(ctx)
if err != nil {
return nil, errors.New("не авторизован")
}
messageChan := make(chan *domain.Message, 1)
// Создаем клиента для хаба
client := &ws.Client{
UserID: userID,
Send: messageChan,
}
// Регистрируем клиента в хабе
r.Services.ChatHub.Register(client)
// Горутина для обработки отключения
go func() {
<-ctx.Done()
r.Services.ChatHub.Unregister(client)
close(messageChan)
}()
return messageChan, nil
}