diff --git a/internal/domain/chat.go b/internal/domain/chat.go index c7f3aa3..48453b5 100644 --- a/internal/domain/chat.go +++ b/internal/domain/chat.go @@ -12,12 +12,13 @@ type Chat struct { } type Message struct { - ID int `json:"id"` - ChatID int `json:"chatId"` - SenderID int `json:"senderId"` - Content string `json:"content"` - Status string `json:"status"` // "sent", "delivered", "read" - CreatedAt time.Time `json:"createdAt"` + ID int `json:"id"` + ChatID int `json:"chatId"` + SenderID int `json:"senderId"` + ReceiverID int `json:"receiverId"` + Content string `json:"content"` + Status string `json:"status"` // "sent", "delivered", "read" + CreatedAt time.Time `json:"createdAt"` } type ChatSession struct { diff --git a/internal/http/graph/generated.go b/internal/http/graph/generated.go index 2cb19cb..176c26d 100644 --- a/internal/http/graph/generated.go +++ b/internal/http/graph/generated.go @@ -92,12 +92,13 @@ type ComplexityRoot struct { } Message struct { - ChatID func(childComplexity int) int - Content func(childComplexity int) int - CreatedAt func(childComplexity int) int - ID func(childComplexity int) int - SenderID func(childComplexity int) int - Status func(childComplexity int) int + ChatID func(childComplexity int) int + Content func(childComplexity int) int + CreatedAt func(childComplexity int) int + ID func(childComplexity int) int + ReceiverID func(childComplexity int) int + SenderID func(childComplexity int) int + Status func(childComplexity int) int } Mutation struct { @@ -114,7 +115,7 @@ type ComplexityRoot struct { RenameDevice func(childComplexity int, deviceID int, name string) int RequestEmailConfirmation func(childComplexity int) int ResendEmailConfirmation func(childComplexity int) int - SendMessage func(childComplexity int, chatID int, senderID int, content string) int + SendMessage func(childComplexity int, chatID int, content string) int TerminateSession func(childComplexity int, sessionID int) int UnlikePost func(childComplexity int, postID int) int UpdateMessageStatus func(childComplexity int, messageID int, status MessageStatus) int @@ -215,7 +216,7 @@ type MutationResolver interface { RenameDevice(ctx context.Context, deviceID int, name string) (*domain.Device, error) RequestEmailConfirmation(ctx context.Context) (bool, error) CreateChat(ctx context.Context, user1Id int, user2Id int) (*domain.Chat, error) - SendMessage(ctx context.Context, chatID int, senderID int, content string) (*domain.Message, error) + SendMessage(ctx context.Context, chatID int, content string) (*domain.Message, error) UpdateMessageStatus(ctx context.Context, messageID int, status MessageStatus) (*domain.Message, error) ConfirmEmail(ctx context.Context, token string) (bool, error) ResendEmailConfirmation(ctx context.Context) (bool, error) @@ -454,6 +455,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Message.ID(childComplexity), true + case "Message.receiverId": + if e.complexity.Message.ReceiverID == nil { + break + } + + return e.complexity.Message.ReceiverID(childComplexity), true + case "Message.senderId": if e.complexity.Message.SenderID == nil { break @@ -624,7 +632,7 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Mutation.SendMessage(childComplexity, args["chatId"].(int), args["senderId"].(int), args["content"].(string)), true + return e.complexity.Mutation.SendMessage(childComplexity, args["chatId"].(int), args["content"].(string)), true case "Mutation.terminateSession": if e.complexity.Mutation.TerminateSession == nil { @@ -1304,16 +1312,11 @@ func (ec *executionContext) field_Mutation_sendMessage_args(ctx context.Context, return nil, err } args["chatId"] = arg0 - arg1, err := processArgField(ctx, rawArgs, "senderId", ec.unmarshalNInt2int) + arg1, err := processArgField(ctx, rawArgs, "content", ec.unmarshalNString2string) if err != nil { return nil, err } - args["senderId"] = arg1 - arg2, err := processArgField(ctx, rawArgs, "content", ec.unmarshalNString2string) - if err != nil { - return nil, err - } - args["content"] = arg2 + args["content"] = arg1 return args, nil } @@ -1804,6 +1807,8 @@ func (ec *executionContext) fieldContext_Chat_lastMessage(_ context.Context, fie return ec.fieldContext_Message_chatId(ctx, field) case "senderId": return ec.fieldContext_Message_senderId(ctx, field) + case "receiverId": + return ec.fieldContext_Message_receiverId(ctx, field) case "content": return ec.fieldContext_Message_content(ctx, field) case "status": @@ -2685,6 +2690,50 @@ func (ec *executionContext) fieldContext_Message_senderId(_ context.Context, fie return fc, nil } +func (ec *executionContext) _Message_receiverId(ctx context.Context, field graphql.CollectedField, obj *domain.Message) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Message_receiverId(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.ReceiverID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Message_receiverId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Message", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Message_content(ctx context.Context, field graphql.CollectedField, obj *domain.Message) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Message_content(ctx, field) if err != nil { @@ -3663,7 +3712,7 @@ func (ec *executionContext) _Mutation_sendMessage(ctx context.Context, field gra }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().SendMessage(rctx, fc.Args["chatId"].(int), fc.Args["senderId"].(int), fc.Args["content"].(string)) + return ec.resolvers.Mutation().SendMessage(rctx, fc.Args["chatId"].(int), fc.Args["content"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -3694,6 +3743,8 @@ func (ec *executionContext) fieldContext_Mutation_sendMessage(ctx context.Contex return ec.fieldContext_Message_chatId(ctx, field) case "senderId": return ec.fieldContext_Message_senderId(ctx, field) + case "receiverId": + return ec.fieldContext_Message_receiverId(ctx, field) case "content": return ec.fieldContext_Message_content(ctx, field) case "status": @@ -3763,6 +3814,8 @@ func (ec *executionContext) fieldContext_Mutation_updateMessageStatus(ctx contex return ec.fieldContext_Message_chatId(ctx, field) case "senderId": return ec.fieldContext_Message_senderId(ctx, field) + case "receiverId": + return ec.fieldContext_Message_receiverId(ctx, field) case "content": return ec.fieldContext_Message_content(ctx, field) case "status": @@ -4932,6 +4985,8 @@ func (ec *executionContext) fieldContext_Query_getChatMessages(ctx context.Conte return ec.fieldContext_Message_chatId(ctx, field) case "senderId": return ec.fieldContext_Message_senderId(ctx, field) + case "receiverId": + return ec.fieldContext_Message_receiverId(ctx, field) case "content": return ec.fieldContext_Message_content(ctx, field) case "status": @@ -5572,6 +5627,8 @@ func (ec *executionContext) fieldContext_Subscription_messageStream(ctx context. return ec.fieldContext_Message_chatId(ctx, field) case "senderId": return ec.fieldContext_Message_senderId(ctx, field) + case "receiverId": + return ec.fieldContext_Message_receiverId(ctx, field) case "content": return ec.fieldContext_Message_content(ctx, field) case "status": @@ -8729,6 +8786,11 @@ func (ec *executionContext) _Message(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } + case "receiverId": + out.Values[i] = ec._Message_receiverId(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } case "content": out.Values[i] = ec._Message_content(ctx, field, obj) if out.Values[i] == graphql.Null { diff --git a/internal/http/graph/messages_resolvers.go b/internal/http/graph/messages_resolvers.go index eb0de9a..dbedac2 100644 --- a/internal/http/graph/messages_resolvers.go +++ b/internal/http/graph/messages_resolvers.go @@ -31,10 +31,16 @@ func (r *mutationResolver) CreateChat(ctx context.Context, user1Id int, user2Id } // SendMessage реализация мутации для отправки сообщения -func (r *mutationResolver) SendMessage(ctx context.Context, chatID int, senderID int, content string) (*domain.Message, error) { +func (r *mutationResolver) SendMessage(ctx context.Context, chatID int, content string) (*domain.Message, error) { + // Получаем senderID из контекста + senderID, err := getUserIDFromContext(ctx) + if err != nil { + return nil, fmt.Errorf("authentication required: %w", err) + } + res, err := r.MessageClient.SendMessage(ctx, &proto.SendMessageRequest{ ChatId: int32(chatID), - SenderId: int32(senderID), + SenderId: int32(senderID), // Теперь senderId берется из контекста Content: content, }) if err != nil { @@ -143,12 +149,13 @@ func (r *subscriptionResolver) MessageStream(ctx context.Context, userID int) (< // Преобразование proto-сообщения в domain-модель func protoMessageToDomain(msg *proto.Message) *domain.Message { return &domain.Message{ - ID: int(msg.Id), - ChatID: int(msg.ChatId), - SenderID: int(msg.SenderId), - Content: msg.Content, - Status: msg.Status, - CreatedAt: msg.CreatedAt.AsTime(), + ID: int(msg.Id), + ChatID: int(msg.ChatId), + SenderID: int(msg.SenderId), + ReceiverID: int(msg.ReceiverId), + Content: msg.Content, + Status: msg.Status, + CreatedAt: msg.CreatedAt.AsTime(), } } diff --git a/internal/http/graph/schema.graphql b/internal/http/graph/schema.graphql index be82952..93224ed 100644 --- a/internal/http/graph/schema.graphql +++ b/internal/http/graph/schema.graphql @@ -66,6 +66,7 @@ type Message { id: Int! chatId: Int! senderId: Int! + receiverId: Int! content: String! status: MessageStatus! createdAt: String! @@ -147,7 +148,7 @@ type Mutation { # Запрос на подтверждение email requestEmailConfirmation: Boolean! createChat(user1Id: Int!, user2Id: Int!): Chat! - sendMessage(chatId: Int!, senderId: Int!, content: String!): Message! + sendMessage(chatId: Int!, content: String!): Message! updateMessageStatus(messageId: Int!, status: MessageStatus!): Message! # Подтверждение email по токену confirmEmail(token: String!): Boolean! diff --git a/proto/messages.pb.go b/proto/messages.pb.go index 4ba56cd..9042144 100644 --- a/proto/messages.pb.go +++ b/proto/messages.pb.go @@ -391,9 +391,10 @@ type Message struct { Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` ChatId int32 `protobuf:"varint,2,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"` SenderId int32 `protobuf:"varint,3,opt,name=sender_id,json=senderId,proto3" json:"sender_id,omitempty"` - Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"` - Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + ReceiverId int32 `protobuf:"varint,4,opt,name=receiver_id,json=receiverId,proto3" json:"receiver_id,omitempty"` + Content string `protobuf:"bytes,5,opt,name=content,proto3" json:"content,omitempty"` + Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -449,6 +450,13 @@ func (x *Message) GetSenderId() int32 { return 0 } +func (x *Message) GetReceiverId() int32 { + if x != nil { + return x.ReceiverId + } + return 0 +} + func (x *Message) GetContent() string { if x != nil { return x.Content @@ -756,15 +764,17 @@ const file_messages_proto_rawDesc = "" + "message_id\x18\x01 \x01(\x05R\tmessageId\x12\x16\n" + "\x06status\x18\x02 \x01(\tR\x06status\"0\n" + "\x15StreamMessagesRequest\x12\x17\n" + - "\auser_id\x18\x01 \x01(\x05R\x06userId\"\xbc\x01\n" + + "\auser_id\x18\x01 \x01(\x05R\x06userId\"\xdd\x01\n" + "\aMessage\x12\x0e\n" + "\x02id\x18\x01 \x01(\x05R\x02id\x12\x17\n" + "\achat_id\x18\x02 \x01(\x05R\x06chatId\x12\x1b\n" + - "\tsender_id\x18\x03 \x01(\x05R\bsenderId\x12\x18\n" + - "\acontent\x18\x04 \x01(\tR\acontent\x12\x16\n" + - "\x06status\x18\x05 \x01(\tR\x06status\x129\n" + + "\tsender_id\x18\x03 \x01(\x05R\bsenderId\x12\x1f\n" + + "\vreceiver_id\x18\x04 \x01(\x05R\n" + + "receiverId\x12\x18\n" + + "\acontent\x18\x05 \x01(\tR\acontent\x12\x16\n" + + "\x06status\x18\x06 \x01(\tR\x06status\x129\n" + "\n" + - "created_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"\xf5\x01\n" + + "created_at\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"\xf5\x01\n" + "\x04Chat\x12\x0e\n" + "\x02id\x18\x01 \x01(\x05R\x02id\x12\x19\n" + "\buser1_id\x18\x02 \x01(\x05R\auser1Id\x12\x19\n" + diff --git a/proto/messages.proto b/proto/messages.proto index 28a69a1..0a824d0 100644 --- a/proto/messages.proto +++ b/proto/messages.proto @@ -55,9 +55,10 @@ message Message { int32 id = 1; int32 chat_id = 2; int32 sender_id = 3; - string content = 4; - string status = 5; - google.protobuf.Timestamp created_at = 6; + int32 receiver_id = 4; + string content = 5; + string status = 6; + google.protobuf.Timestamp created_at = 7; } message Chat {