chore: refresh gramsrv public release

This commit is contained in:
A 2026-06-30 14:37:43 +08:00
parent 75cebe8dbf
commit 70b6820474
1274 changed files with 378751 additions and 59919 deletions

View file

@ -0,0 +1,169 @@
package postgres
import (
"context"
"fmt"
"telesrv/internal/domain"
"telesrv/internal/store/postgres/sqlcgen"
"time"
)
func cloneMessageForward(forward *domain.MessageForward) *domain.MessageForward {
if forward == nil {
return nil
}
clone := *forward
return &clone
}
func (s *MessageStore) ForwardPrivateMessages(ctx context.Context, req domain.ForwardPrivateMessagesRequest) (domain.ForwardPrivateMessagesResult, error) {
res := domain.ForwardPrivateMessagesResult{OwnerUserID: req.OwnerUserID}
if req.OwnerUserID == 0 || req.ToUserID == 0 {
return res, fmt.Errorf("forward private messages: missing user id")
}
if req.FromPeer.Type != domain.PeerTypeUser || req.FromPeer.ID == 0 {
return res, fmt.Errorf("forward private messages: invalid source peer")
}
if len(req.MessageIDs) == 0 || len(req.MessageIDs) != len(req.RandomIDs) {
return res, domain.ErrMessageIDInvalid
}
if len(req.MessageIDs) > domain.MaxForwardMessageIDs {
return res, fmt.Errorf("forward private messages: too many ids: %d > %d", len(req.MessageIDs), domain.MaxForwardMessageIDs)
}
if req.Date == 0 {
req.Date = int(time.Now().Unix())
}
boxIDs := make([]int32, 0, len(req.MessageIDs))
for i, id := range req.MessageIDs {
if id <= 0 || id > domain.MaxMessageBoxID || req.RandomIDs[i] == 0 {
return res, domain.ErrMessageIDInvalid
}
boxIDs = append(boxIDs, int32(id))
}
rows, err := s.q.GetMessageBoxesForForward(ctx, sqlcgen.GetMessageBoxesForForwardParams{
OwnerUserID: req.OwnerUserID,
PeerType: string(req.FromPeer.Type),
PeerID: req.FromPeer.ID,
BoxIds: boxIDs,
})
if err != nil {
return res, fmt.Errorf("get forward messages: %w", err)
}
if len(rows) != len(req.MessageIDs) {
return res, domain.ErrMessageIDInvalid
}
res.SenderMessages = make([]domain.Message, 0, len(rows))
res.RecipientMessages = make([]domain.Message, 0, len(rows))
res.SenderEvents = make([]domain.UpdateEvent, 0, len(rows))
res.RecipientEvents = make([]domain.UpdateEvent, 0, len(rows))
res.Duplicates = make([]bool, 0, len(rows))
for i, row := range rows {
if int(row.BoxID) != req.MessageIDs[i] {
return res, domain.ErrMessageIDInvalid
}
source, err := messageFromForwardRow(row)
if err != nil {
return res, err
}
if source.NoForwards {
return res, domain.ErrChatForwardsRestricted
}
var forward *domain.MessageForward
if !req.DropAuthor {
forward = cloneMessageForward(source.Forward)
if forward == nil {
forward = &domain.MessageForward{From: source.From, Date: source.Date}
}
// 转发进 Saved Messages 必须带 saved_from_peer/msg_id 成对字段,
// 客户端靠它提供"跳回原会话"。
if req.ToUserID == req.OwnerUserID {
forward.SavedFrom = req.FromPeer
forward.SavedFromMsgID = req.MessageIDs[i]
}
}
sent, err := s.SendPrivateText(ctx, domain.SendPrivateTextRequest{
SenderUserID: req.OwnerUserID,
RecipientUserID: req.ToUserID,
RandomID: req.RandomIDs[i],
Message: source.Body,
Entities: append([]domain.MessageEntity(nil), source.Entities...),
Media: source.Media,
Silent: req.Silent,
NoForwards: req.NoForwards,
ReplyTo: req.ReplyTo,
Forward: forward,
Date: req.Date,
OriginAuthKeyID: req.OriginAuthKeyID,
OriginSessionID: req.OriginSessionID,
RecipientBlocked: req.RecipientBlocked,
})
if err != nil {
return res, err
}
res.SenderMessages = append(res.SenderMessages, sent.SenderMessage)
res.RecipientMessages = append(res.RecipientMessages, sent.RecipientMessage)
res.SenderEvents = append(res.SenderEvents, sent.SenderEvent)
res.RecipientEvents = append(res.RecipientEvents, sent.RecipientEvent)
res.Duplicates = append(res.Duplicates, sent.Duplicate)
}
return res, nil
}
func messageFromForwardRow(row sqlcgen.GetMessageBoxesForForwardRow) (domain.Message, error) {
entities, err := decodeMessageEntities(row.EntitiesJson)
if err != nil {
return domain.Message{}, fmt.Errorf("decode forward message entities: %w", err)
}
silent, noforwards, reply, forward, err := messageMetadataFromFields(
row.Silent,
row.Noforwards,
row.ReplyToMsgID,
row.ReplyToPeerType,
row.ReplyToPeerID,
row.ReplyToTopID,
row.ReplyToStoryID,
row.QuoteText,
row.QuoteEntitiesJson,
row.QuoteOffset,
row.FwdFromPeerType,
row.FwdFromPeerID,
row.FwdFromName,
row.FwdDate,
row.FwdSavedFromPeerType,
row.FwdSavedFromPeerID,
row.FwdSavedFromMsgID,
)
if err != nil {
return domain.Message{}, fmt.Errorf("decode forward message metadata: %w", err)
}
media, err := decodeMessageMedia(row.MediaJson)
if err != nil {
return domain.Message{}, fmt.Errorf("decode forward message media: %w", err)
}
return domain.Message{
Media: media,
ID: int(row.BoxID),
UID: row.PrivateMessageID,
OwnerUserID: row.OwnerUserID,
Peer: domain.Peer{Type: domain.PeerType(row.PeerType), ID: row.PeerID},
From: domain.Peer{Type: domain.PeerTypeUser, ID: row.FromUserID},
Date: int(row.MessageDate),
EditDate: int(row.EditDate),
Out: row.Outgoing,
Silent: silent,
NoForwards: noforwards,
Body: row.Body,
Entities: entities,
ReplyTo: reply,
Forward: forward,
Pts: int(row.Pts),
TTLPeriod: int(row.TtlPeriod),
ExpiresAt: int(row.ExpiresAt),
MediaUnread: row.MediaUnread,
ReactionUnread: row.ReactionUnread,
ViaBotID: row.ViaBotID,
GroupedID: row.GroupedID,
Pinned: row.Pinned,
SavedPeer: savedPeerFromFields(row.SavedPeerType, row.SavedPeerID),
}, nil
}