fix: sync latest channel and contact fixes

This commit is contained in:
A 2026-07-03 13:26:33 +08:00
parent e83650b9fd
commit 35e5d38f4d
11 changed files with 255 additions and 81 deletions

View file

@ -421,20 +421,38 @@ func (s *Service) GetPeerSettings(ctx context.Context, userID int64, peer domain
return domain.PeerSettings{}, err
}
shareContact := found && !contact.Mutual
needContactsException := false
if s.privacy != nil {
peerCanSeePhone, err := s.privacy.CanSee(ctx, userID, peer.ID, domain.PrivacyKeyPhoneNumber)
peerCanSeePhone, err := s.peerCanSeeCurrentUserPhone(ctx, userID, peer.ID)
if err != nil {
return domain.PeerSettings{}, err
}
needContactsException = !peerCanSeePhone
shareContact = found && !peerCanSeePhone
}
return domain.PeerSettings{
AddContact: !found,
BlockContact: !blocked,
ShareContact: shareContact,
AddContact: !found,
BlockContact: !blocked,
ShareContact: shareContact,
NeedContactsException: needContactsException,
}, nil
}
func (s *Service) peerCanSeeCurrentUserPhone(ctx context.Context, ownerUserID, viewerUserID int64) (bool, error) {
allowed, err := s.privacy.CanSee(ctx, ownerUserID, viewerUserID, domain.PrivacyKeyPhoneNumber)
if err != nil || allowed {
return allowed, err
}
if s.contacts == nil {
return false, nil
}
_, found, err := s.contacts.Get(ctx, viewerUserID, ownerUserID)
if err != nil {
return false, err
}
return found, nil
}
// BlockContact adds peer to the current user's blocklist.
func (s *Service) BlockContact(ctx context.Context, userID, peerUserID int64, date int) (bool, error) {
if s == nil || s.contacts == nil || userID == 0 || peerUserID == 0 || peerUserID == userID {

View file

@ -6,6 +6,7 @@ import (
"reflect"
"testing"
privacyapp "telesrv/internal/app/privacy"
"telesrv/internal/domain"
"telesrv/internal/store"
"telesrv/internal/store/memory"
@ -391,6 +392,94 @@ func TestAddContactNormalizesPhoneToDigits(t *testing.T) {
}
}
func TestAddContactPhonePrivacyExceptionPeerSettings(t *testing.T) {
ctx := context.Background()
users := memory.NewUserStore()
contactsStore := memory.NewContactStore()
privacySvc := privacyapp.NewService(memory.NewPrivacyStore(), contactsStore)
alice, err := users.Create(ctx, domain.User{Phone: "15550000101", FirstName: "Alice", LastName: "A"})
if err != nil {
t.Fatalf("create alice: %v", err)
}
bob, err := users.Create(ctx, domain.User{Phone: "15550000102", FirstName: "Bob", LastName: "B"})
if err != nil {
t.Fatalf("create bob: %v", err)
}
carol, err := users.Create(ctx, domain.User{Phone: "15550000103", FirstName: "Carol", LastName: "C"})
if err != nil {
t.Fatalf("create carol: %v", err)
}
dave, err := users.Create(ctx, domain.User{Phone: "15550000104", FirstName: "Dave", LastName: "D"})
if err != nil {
t.Fatalf("create dave: %v", err)
}
svc := NewService(contactsStore, users).Configure(WithPrivacyEvaluator(privacySvc))
bobSettings, err := svc.GetPeerSettings(ctx, alice.ID, domain.Peer{Type: domain.PeerTypeUser, ID: bob.ID})
if err != nil {
t.Fatalf("bob peer settings before add: %v", err)
}
if !bobSettings.AddContact || bobSettings.ShareContact || !bobSettings.NeedContactsException {
t.Fatalf("bob settings before add = %+v, want add + need exception only", bobSettings)
}
if _, err := svc.AddContact(ctx, alice.ID, domain.ContactInput{
ContactUserID: bob.ID,
Phone: bob.Phone,
FirstName: "Bobby",
}); err != nil {
t.Fatalf("alice add bob: %v", err)
}
bobSettings, err = svc.GetPeerSettings(ctx, alice.ID, domain.Peer{Type: domain.PeerTypeUser, ID: bob.ID})
if err != nil {
t.Fatalf("bob peer settings after add without exception: %v", err)
}
if bobSettings.AddContact || !bobSettings.ShareContact || !bobSettings.NeedContactsException {
t.Fatalf("bob settings after add without exception = %+v, want share + need exception", bobSettings)
}
if allowed, err := privacySvc.CanSee(ctx, alice.ID, bob.ID, domain.PrivacyKeyPhoneNumber); err != nil {
t.Fatalf("bob can see alice phone: %v", err)
} else if allowed {
t.Fatalf("bob can see alice phone = true, want false before exception")
}
if _, err := svc.AddContact(ctx, alice.ID, domain.ContactInput{
ContactUserID: carol.ID,
Phone: carol.Phone,
FirstName: "Carol",
AddPhonePrivacyException: true,
}); err != nil {
t.Fatalf("alice add carol with exception: %v", err)
}
carolSettings, err := svc.GetPeerSettings(ctx, alice.ID, domain.Peer{Type: domain.PeerTypeUser, ID: carol.ID})
if err != nil {
t.Fatalf("carol peer settings after exception: %v", err)
}
if carolSettings.AddContact || carolSettings.ShareContact || carolSettings.NeedContactsException {
t.Fatalf("carol settings after exception = %+v, want no add/share/need exception", carolSettings)
}
if allowed, err := privacySvc.CanSee(ctx, alice.ID, carol.ID, domain.PrivacyKeyPhoneNumber); err != nil {
t.Fatalf("carol can see alice phone: %v", err)
} else if !allowed {
t.Fatalf("carol can see alice phone = false, want true after exception")
}
if _, err := contactsStore.Upsert(ctx, dave.ID, domain.ContactInput{
ContactUserID: alice.ID,
Phone: alice.Phone,
FirstName: alice.FirstName,
LastName: alice.LastName,
}); err != nil {
t.Fatalf("dave add alice: %v", err)
}
daveSettings, err := svc.GetPeerSettings(ctx, alice.ID, domain.Peer{Type: domain.PeerTypeUser, ID: dave.ID})
if err != nil {
t.Fatalf("dave peer settings before alice add: %v", err)
}
if !daveSettings.AddContact || daveSettings.ShareContact || daveSettings.NeedContactsException {
t.Fatalf("dave settings with reverse contact = %+v, want add only", daveSettings)
}
}
func TestAcceptContactRequiresExistingContactRequest(t *testing.T) {
ctx := context.Background()
users := memory.NewUserStore()