owpengram-server/internal/rpc/privacy_voice.go
2026-07-24 11:56:59 +08:00

83 lines
2.1 KiB
Go

package rpc
import (
"context"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)
func (r *Router) ensureVoiceMessagesAllowed(ctx context.Context, senderUserID int64, peer domain.Peer, voiceOrRound bool) error {
if !voiceOrRound || peer.Type != domain.PeerTypeUser || peer.ID == 0 || peer.ID == senderUserID || r.deps.Privacy == nil {
return nil
}
allowed, err := r.deps.Privacy.CanSee(ctx, peer.ID, senderUserID, domain.PrivacyKeyVoiceMessages)
if err != nil {
return internalErr()
}
if !allowed {
return chatSendVoicesForbiddenErr()
}
return nil
}
// preflightVoiceOrRound inspects upload attributes and referenced documents
// before resolveInputMedia materializes any uploaded blob. Referenced document
// misses are loaded in one bounded read-model batch.
func (r *Router) preflightVoiceOrRound(ctx context.Context, inputs []tg.InputMediaClass) (bool, error) {
documentIDs := make([]int64, 0)
seen := make(map[int64]struct{})
for _, input := range inputs {
switch media := input.(type) {
case *tg.InputMediaUploadedDocument:
if documentAttributesVoiceOrRound(domainDocumentAttributes(media.Attributes)) {
return true, nil
}
case *tg.InputMediaDocument:
ids, ok := inputDocumentCandidateIDs(media.ID)
if !ok {
continue // resolveInputMedia retains MEDIA_INVALID precedence.
}
for _, id := range ids {
if id == 0 {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
documentIDs = append(documentIDs, id)
}
}
}
if len(documentIDs) == 0 || r.deps.Files == nil {
return false, nil
}
documents, err := r.deps.Files.GetDocuments(ctx, documentIDs)
if err != nil {
return false, internalErr()
}
for _, document := range documents {
if documentAttributesVoiceOrRound(document.Attributes) {
return true, nil
}
}
return false, nil
}
func documentAttributesVoiceOrRound(attributes []domain.DocumentAttribute) bool {
for _, attribute := range attributes {
switch attribute.Kind {
case domain.DocAttrAudio:
if attribute.Voice {
return true
}
case domain.DocAttrVideo:
if attribute.RoundMessage {
return true
}
}
}
return false
}