fix: sync latest channel and contact fixes
This commit is contained in:
parent
e83650b9fd
commit
35e5d38f4d
11 changed files with 255 additions and 81 deletions
|
|
@ -2748,8 +2748,8 @@ func TestPublicChannelPreviewAllowsNonMemberHistory(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("non-member GetDifference public preview: %v", err)
|
||||
}
|
||||
if !diff.Final || diff.Pts != sent.Event.Pts || len(diff.NewMessages) != 1 || diff.NewMessages[0].Body != "public preview post" {
|
||||
t.Fatalf("preview diff = %+v, want public preview post at current pts", diff)
|
||||
if !diff.Final || diff.Pts != sent.Event.Pts || len(diff.Events) != 0 || len(diff.NewMessages) != 0 || len(diff.OtherUpdates) != 0 {
|
||||
t.Fatalf("preview diff = %+v, want empty public preview difference at current pts", diff)
|
||||
}
|
||||
if diff.Dialog.UnreadCount != 0 || diff.Dialog.ReadInboxMaxID < sent.Message.ID {
|
||||
t.Fatalf("preview diff dialog = %+v, want read-only public preview dialog", diff.Dialog)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -336,6 +336,9 @@ func (s *Service) appendMissingChannelPeerPreviews(ctx context.Context, userID i
|
|||
if !ok || view.Forbidden {
|
||||
continue
|
||||
}
|
||||
if view.Self.Status != domain.ChannelMemberActive {
|
||||
continue
|
||||
}
|
||||
history, err := s.channels.ListChannelHistory(ctx, userID, domain.ChannelHistoryFilter{
|
||||
ChannelID: channelID,
|
||||
Limit: 1,
|
||||
|
|
|
|||
|
|
@ -695,7 +695,7 @@ func TestGetPeerDialogsRejectsHugeVector(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetPeerDialogsIncludesPublicChannelPreviewForNonMember(t *testing.T) {
|
||||
func TestGetPeerDialogsSkipsPublicChannelPreviewForNonMember(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
channelStore := memory.NewChannelStore()
|
||||
channels := appchannels.NewService(channelStore)
|
||||
|
|
@ -716,13 +716,12 @@ func TestGetPeerDialogsIncludesPublicChannelPreviewForNonMember(t *testing.T) {
|
|||
}); err != nil {
|
||||
t.Fatalf("UpdateUsername public: %v", err)
|
||||
}
|
||||
sent, err := channels.SendMessage(ctx, 1001, domain.SendChannelMessageRequest{
|
||||
if _, err := channels.SendMessage(ctx, 1001, domain.SendChannelMessageRequest{
|
||||
ChannelID: public.Channel.ID,
|
||||
RandomID: 99,
|
||||
Message: "public peer dialog top",
|
||||
Date: 1700002010,
|
||||
})
|
||||
if err != nil {
|
||||
}); err != nil {
|
||||
t.Fatalf("SendMessage public: %v", err)
|
||||
}
|
||||
private, err := channels.CreateChannel(ctx, 1001, domain.CreateChannelRequest{
|
||||
|
|
@ -741,28 +740,12 @@ func TestGetPeerDialogsIncludesPublicChannelPreviewForNonMember(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetPeerDialogs public preview: %v", err)
|
||||
}
|
||||
if len(list.Dialogs) != 1 {
|
||||
t.Fatalf("dialogs = %+v, want only public preview dialog", list.Dialogs)
|
||||
}
|
||||
dialog := findChannelDialog(t, list, public.Channel.ID)
|
||||
if dialog.TopMessage != sent.Message.ID || dialog.TopMessageDate != sent.Message.Date {
|
||||
t.Fatalf("preview dialog top = id %d date %d, want %d/%d", dialog.TopMessage, dialog.TopMessageDate, sent.Message.ID, sent.Message.Date)
|
||||
}
|
||||
if !dialog.ChannelLeft {
|
||||
t.Fatalf("preview dialog ChannelLeft = false, want read-only left preview")
|
||||
}
|
||||
if dialog.UnreadCount != 0 || dialog.ReadInboxMaxID < sent.Message.ID || dialog.ReadOutboxMaxID < sent.Message.ID {
|
||||
t.Fatalf("preview dialog read/unread = %+v, want read through top and no unread", dialog)
|
||||
}
|
||||
if len(list.ChannelMessages) != 1 || list.ChannelMessages[0].Body != "public peer dialog top" {
|
||||
t.Fatalf("channel messages = %+v, want public top message", list.ChannelMessages)
|
||||
}
|
||||
if len(list.Channels) != 1 || list.Channels[0].ID != public.Channel.ID {
|
||||
t.Fatalf("channels = %+v, want public channel shell", list.Channels)
|
||||
if len(list.Dialogs) != 0 || len(list.ChannelMessages) != 0 || len(list.Channels) != 0 || list.Count != 0 {
|
||||
t.Fatalf("peer dialogs = %+v, want no materialized public preview dialog", list)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPeerDialogsBatchesMissingChannelPreviews(t *testing.T) {
|
||||
func TestGetPeerDialogsBatchesMissingChannelVisibilityChecks(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
channelStore := &countingDialogChannelStore{ChannelStore: memory.NewChannelStore()}
|
||||
channels := appchannels.NewService(channelStore)
|
||||
|
|
@ -783,13 +766,12 @@ func TestGetPeerDialogsBatchesMissingChannelPreviews(t *testing.T) {
|
|||
}); err != nil {
|
||||
t.Fatalf("UpdateUsername first: %v", err)
|
||||
}
|
||||
firstMsg, err := channels.SendMessage(ctx, 1001, domain.SendChannelMessageRequest{
|
||||
if _, err := channels.SendMessage(ctx, 1001, domain.SendChannelMessageRequest{
|
||||
ChannelID: first.Channel.ID,
|
||||
RandomID: 101,
|
||||
Message: "first public preview",
|
||||
Date: 1700002110,
|
||||
})
|
||||
if err != nil {
|
||||
}); err != nil {
|
||||
t.Fatalf("SendMessage first: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -808,13 +790,12 @@ func TestGetPeerDialogsBatchesMissingChannelPreviews(t *testing.T) {
|
|||
}); err != nil {
|
||||
t.Fatalf("UpdateUsername second: %v", err)
|
||||
}
|
||||
secondMsg, err := channels.SendMessage(ctx, 1001, domain.SendChannelMessageRequest{
|
||||
if _, err := channels.SendMessage(ctx, 1001, domain.SendChannelMessageRequest{
|
||||
ChannelID: second.Channel.ID,
|
||||
RandomID: 102,
|
||||
Message: "second public preview",
|
||||
Date: 1700002130,
|
||||
})
|
||||
if err != nil {
|
||||
}); err != nil {
|
||||
t.Fatalf("SendMessage second: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -839,19 +820,10 @@ func TestGetPeerDialogsBatchesMissingChannelPreviews(t *testing.T) {
|
|||
t.Fatalf("GetPeerDialogs batch previews: %v", err)
|
||||
}
|
||||
if channelStore.getChannelsCalls != 1 || channelStore.getChannelCalls != 0 {
|
||||
t.Fatalf("preview channel calls: GetChannels=%d GetChannel=%d, want one batch call only", channelStore.getChannelsCalls, channelStore.getChannelCalls)
|
||||
t.Fatalf("visibility channel calls: GetChannels=%d GetChannel=%d, want one batch call only", channelStore.getChannelsCalls, channelStore.getChannelCalls)
|
||||
}
|
||||
if len(list.Dialogs) != 2 {
|
||||
t.Fatalf("dialogs = %+v, want two public previews", list.Dialogs)
|
||||
}
|
||||
if got := findChannelDialog(t, list, first.Channel.ID); got.TopMessage != firstMsg.Message.ID {
|
||||
t.Fatalf("first preview top = %d, want %d", got.TopMessage, firstMsg.Message.ID)
|
||||
}
|
||||
if got := findChannelDialog(t, list, second.Channel.ID); got.TopMessage != secondMsg.Message.ID {
|
||||
t.Fatalf("second preview top = %d, want %d", got.TopMessage, secondMsg.Message.ID)
|
||||
}
|
||||
if len(list.ChannelMessages) != 2 {
|
||||
t.Fatalf("channel messages = %+v, want two top messages", list.ChannelMessages)
|
||||
if len(list.Dialogs) != 0 || len(list.ChannelMessages) != 0 || len(list.Channels) != 0 || list.Count != 0 {
|
||||
t.Fatalf("peer dialogs = %+v, want no public preview dialogs", list)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,20 +135,9 @@ func TestPublicChannelPreviewRPCsAllowNonMember(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("non-member getChannelDifference public preview: %v", err)
|
||||
}
|
||||
fullDiff, ok := diff.(*tg.UpdatesChannelDifference)
|
||||
if !ok || !fullDiff.Final || fullDiff.Pts != sent.Event.Pts || len(fullDiff.NewMessages) != 1 {
|
||||
t.Fatalf("channel difference = %T %+v, want one public preview message at current pts", diff, diff)
|
||||
}
|
||||
diffMsg, ok := fullDiff.NewMessages[0].(*tg.Message)
|
||||
if !ok || diffMsg.Message != "public preview rpc post" {
|
||||
t.Fatalf("channel difference message = %T %+v, want public preview rpc post", fullDiff.NewMessages[0], fullDiff.NewMessages[0])
|
||||
}
|
||||
if len(fullDiff.Chats) != 1 {
|
||||
t.Fatalf("channel difference chats = %d, want public channel chat", len(fullDiff.Chats))
|
||||
}
|
||||
diffChat, ok := fullDiff.Chats[0].(*tg.Channel)
|
||||
if !ok || !diffChat.Left || diffChat.ID != public.Channel.ID {
|
||||
t.Fatalf("channel difference chat = %T %+v, want left public channel", fullDiff.Chats[0], fullDiff.Chats[0])
|
||||
emptyDiff, ok := diff.(*tg.UpdatesChannelDifferenceEmpty)
|
||||
if !ok || !emptyDiff.Final || emptyDiff.Pts != sent.Event.Pts {
|
||||
t.Fatalf("channel difference = %T %+v, want empty public preview difference at current pts", diff, diff)
|
||||
}
|
||||
|
||||
domainPeers, err := r.dialogPeersFromInput(WithUserID(ctx, viewer.ID), viewer.ID, []tg.InputDialogPeerClass{&tg.InputDialogPeer{Peer: peer}})
|
||||
|
|
@ -162,8 +151,8 @@ func TestPublicChannelPreviewRPCsAllowNonMember(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("dialog service public preview: %v", err)
|
||||
}
|
||||
if len(directPeerDialogs.Dialogs) != 1 || len(directPeerDialogs.ChannelMessages) != 1 || len(directPeerDialogs.Channels) != 1 {
|
||||
t.Fatalf("direct peer dialogs = %+v, want one dialog/message/channel", directPeerDialogs)
|
||||
if len(directPeerDialogs.Dialogs) != 0 || len(directPeerDialogs.ChannelMessages) != 0 || len(directPeerDialogs.Channels) != 0 {
|
||||
t.Fatalf("direct peer dialogs = %+v, want no public preview dialog/message/channel", directPeerDialogs)
|
||||
}
|
||||
|
||||
peerDialogsReq := &tg.MessagesGetPeerDialogsRequest{
|
||||
|
|
@ -181,20 +170,8 @@ func TestPublicChannelPreviewRPCsAllowNonMember(t *testing.T) {
|
|||
if !ok {
|
||||
t.Fatalf("getPeerDialogs response = %T, want peer dialogs", peerDialogsEnc)
|
||||
}
|
||||
if len(peerDialogs.Dialogs) != 1 || len(peerDialogs.Messages) != 1 || len(peerDialogs.Chats) != 1 {
|
||||
t.Fatalf("peer dialogs = %+v, want one dialog/message/channel", peerDialogs)
|
||||
}
|
||||
tgDialog, ok := peerDialogs.Dialogs[0].(*tg.Dialog)
|
||||
if !ok || tgDialog.TopMessage <= 0 || tgDialog.UnreadCount != 0 {
|
||||
t.Fatalf("peer dialog = %T %+v, want read-only public preview dialog", peerDialogs.Dialogs[0], peerDialogs.Dialogs[0])
|
||||
}
|
||||
tgMessage, ok := peerDialogs.Messages[0].(*tg.Message)
|
||||
if !ok || tgMessage.Message != "public preview rpc post" {
|
||||
t.Fatalf("peer dialog message = %T %+v, want public preview rpc post", peerDialogs.Messages[0], peerDialogs.Messages[0])
|
||||
}
|
||||
peerDialogChat, ok := peerDialogs.Chats[0].(*tg.Channel)
|
||||
if !ok || !peerDialogChat.Left || peerDialogChat.ID != public.Channel.ID {
|
||||
t.Fatalf("peer dialog chat = %T %+v, want left public channel", peerDialogs.Chats[0], peerDialogs.Chats[0])
|
||||
if len(peerDialogs.Dialogs) != 0 || len(peerDialogs.Messages) != 0 || len(peerDialogs.Chats) != 0 {
|
||||
t.Fatalf("peer dialogs = %+v, want no public preview dialog/message/channel", peerDialogs)
|
||||
}
|
||||
|
||||
if _, err := channelService.JoinChannel(ctx, viewer.ID, public.Channel.ID, 1700010120); err != nil {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
appchannels "telesrv/internal/app/channels"
|
||||
appcontacts "telesrv/internal/app/contacts"
|
||||
appprivacy "telesrv/internal/app/privacy"
|
||||
appstories "telesrv/internal/app/stories"
|
||||
appupdates "telesrv/internal/app/updates"
|
||||
appusers "telesrv/internal/app/users"
|
||||
|
|
@ -1057,6 +1058,84 @@ func TestContactsAcceptContactReturnsSettingsAndReset(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestContactsAddContactPhonePrivacyExceptionUpdatesPeerSettings(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
userStore := memory.NewUserStore()
|
||||
contactsStore := memory.NewContactStore()
|
||||
privacySvc := appprivacy.NewService(memory.NewPrivacyStore(), contactsStore)
|
||||
alice, err := userStore.Create(ctx, domain.User{AccessHash: 31, Phone: "2001", FirstName: "Alice", LastName: "A"})
|
||||
if err != nil {
|
||||
t.Fatalf("create alice: %v", err)
|
||||
}
|
||||
bob, err := userStore.Create(ctx, domain.User{AccessHash: 32, Phone: "2002", FirstName: "Bob", LastName: "B"})
|
||||
if err != nil {
|
||||
t.Fatalf("create bob: %v", err)
|
||||
}
|
||||
carol, err := userStore.Create(ctx, domain.User{AccessHash: 33, Phone: "2003", FirstName: "Carol", LastName: "C"})
|
||||
if err != nil {
|
||||
t.Fatalf("create carol: %v", err)
|
||||
}
|
||||
contactsSvc := appcontacts.NewService(contactsStore, userStore).Configure(appcontacts.WithPrivacyEvaluator(privacySvc))
|
||||
usersSvc := appusers.NewService(userStore, appusers.WithContactStore(contactsStore), appusers.WithPrivacyEvaluator(privacySvc))
|
||||
r := New(Config{}, Deps{
|
||||
Contacts: contactsSvc,
|
||||
Users: usersSvc,
|
||||
}, zaptest.NewLogger(t), fixedClock{now: time.Unix(1700000410, 0)})
|
||||
|
||||
withoutException, err := r.onContactsAddContact(WithUserID(ctx, alice.ID), &tg.ContactsAddContactRequest{
|
||||
ID: &tg.InputUser{UserID: bob.ID, AccessHash: bob.AccessHash},
|
||||
Phone: bob.Phone,
|
||||
FirstName: "Bobby",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("contacts.addContact without exception: %v", err)
|
||||
}
|
||||
bobSettings := firstPeerSettingsUpdate(t, withoutException)
|
||||
if bobSettings.Settings.AddContact || !bobSettings.Settings.ShareContact || !bobSettings.Settings.NeedContactsException {
|
||||
t.Fatalf("bob peer settings = %+v, want share + need exception", bobSettings.Settings)
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
withException, err := r.onContactsAddContact(WithUserID(ctx, alice.ID), &tg.ContactsAddContactRequest{
|
||||
AddPhonePrivacyException: true,
|
||||
ID: &tg.InputUser{UserID: carol.ID, AccessHash: carol.AccessHash},
|
||||
Phone: carol.Phone,
|
||||
FirstName: "Carol",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("contacts.addContact with exception: %v", err)
|
||||
}
|
||||
carolSettings := firstPeerSettingsUpdate(t, withException)
|
||||
if carolSettings.Settings.AddContact || carolSettings.Settings.ShareContact || carolSettings.Settings.NeedContactsException {
|
||||
t.Fatalf("carol peer settings = %+v, want no add/share/need exception", carolSettings.Settings)
|
||||
}
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
func firstPeerSettingsUpdate(t *testing.T, updates tg.UpdatesClass) *tg.UpdatePeerSettings {
|
||||
t.Helper()
|
||||
got, ok := updates.(*tg.Updates)
|
||||
if !ok {
|
||||
t.Fatalf("updates = %T, want *tg.Updates", updates)
|
||||
}
|
||||
if len(got.Updates) == 0 {
|
||||
t.Fatalf("updates = %+v, want UpdatePeerSettings", got.Updates)
|
||||
}
|
||||
settings, ok := got.Updates[0].(*tg.UpdatePeerSettings)
|
||||
if !ok {
|
||||
t.Fatalf("update[0] = %T, want UpdatePeerSettings", got.Updates[0])
|
||||
}
|
||||
return settings
|
||||
}
|
||||
|
||||
func TestContactsStatusesUsesOnlineSessionFallback(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
alice := domain.User{ID: 1000000001, AccessHash: 11, FirstName: "Alice"}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package memory
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sort"
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
@ -119,8 +120,23 @@ func (s *ChannelStore) GetChannelDialogs(_ context.Context, viewerUserID int64,
|
|||
continue
|
||||
}
|
||||
seen[channelID] = struct{}{}
|
||||
channel, member, _, err := s.channelForViewerLocked(viewerUserID, channelID)
|
||||
channel, member, err := s.channelAndMemberLocked(viewerUserID, channelID)
|
||||
if err != nil {
|
||||
if !errors.Is(err, domain.ErrChannelPrivate) && !errors.Is(err, domain.ErrChannelInvalid) {
|
||||
continue
|
||||
}
|
||||
var ok bool
|
||||
channel, ok = s.channels[channelID]
|
||||
if !ok || channel.Deleted || !channel.Monoforum || channel.LinkedMonoforumID == 0 {
|
||||
continue
|
||||
}
|
||||
parentMember, ok := s.members[channel.LinkedMonoforumID][viewerUserID]
|
||||
if !ok || parentMember.Status != domain.ChannelMemberActive || !isChannelAdmin(parentMember) {
|
||||
continue
|
||||
}
|
||||
member = syntheticMonoforumAdminMember(channel, parentMember)
|
||||
}
|
||||
if member.Status != domain.ChannelMemberActive {
|
||||
continue
|
||||
}
|
||||
dialog := channelDialogToDialog(s.dialogForMemberLocked(viewerUserID, channel, member), channel.Pts, member.Status)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,16 @@ func (s *ChannelStore) ListChannelDifference(_ context.Context, req domain.Chann
|
|||
if preview {
|
||||
dialog = previewChannelDialog(req.UserID, channel, member)
|
||||
}
|
||||
if preview && member.Status != domain.ChannelMemberActive {
|
||||
return domain.ChannelDifference{
|
||||
Channel: channel,
|
||||
Self: member,
|
||||
Pts: channel.Pts,
|
||||
Final: true,
|
||||
Timeout: 30,
|
||||
Dialog: dialog,
|
||||
}, nil
|
||||
}
|
||||
if channel.Pts-req.Pts > limit {
|
||||
messages := make([]domain.ChannelMessage, 0, domain.MaxChannelDifferenceTooLongMessages)
|
||||
for i := len(s.messages[req.ChannelID]) - 1; i >= 0 && len(messages) < domain.MaxChannelDifferenceTooLongMessages; i-- {
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ func TestChannelStoreDifferenceStartsAtMemberAvailableMinPts(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestChannelStorePublicPreviewDifferenceAllowsNonMember(t *testing.T) {
|
||||
func TestChannelStorePublicPreviewDifferenceSkipsNonMemberMessages(t *testing.T) {
|
||||
pool := testPool(t)
|
||||
ctx := context.Background()
|
||||
suffix := randomSuffix(t)
|
||||
|
|
@ -183,8 +183,8 @@ func TestChannelStorePublicPreviewDifferenceAllowsNonMember(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("list public preview difference: %v", err)
|
||||
}
|
||||
if !diff.Final || diff.Pts != sent.Event.Pts || len(diff.NewMessages) != 1 || diff.NewMessages[0].Body != "public preview difference" {
|
||||
t.Fatalf("preview diff = %+v, want one public preview message at current pts", diff)
|
||||
if !diff.Final || diff.Pts != sent.Event.Pts || len(diff.Events) != 0 || len(diff.NewMessages) != 0 || len(diff.OtherUpdates) != 0 {
|
||||
t.Fatalf("preview diff = %+v, want empty public preview difference at current pts", diff)
|
||||
}
|
||||
if diff.Dialog.UnreadCount != 0 || diff.Dialog.ReadInboxMaxID < sent.Message.ID {
|
||||
t.Fatalf("preview diff dialog = %+v, want read-only public preview dialog", diff.Dialog)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,16 @@ func (s *ChannelStore) ListChannelDifference(ctx context.Context, req domain.Cha
|
|||
if limit <= 0 || limit > domain.MaxChannelDifferenceLimit {
|
||||
limit = domain.MaxChannelDifferenceLimit
|
||||
}
|
||||
if preview && member.Status != domain.ChannelMemberActive {
|
||||
return domain.ChannelDifference{
|
||||
Channel: channel,
|
||||
Self: member,
|
||||
Pts: channel.Pts,
|
||||
Final: true,
|
||||
Timeout: 30,
|
||||
Dialog: previewChannelDialog(req.UserID, channel, member),
|
||||
}, nil
|
||||
}
|
||||
if channel.Pts-req.Pts > limit {
|
||||
args := []any{req.ChannelID}
|
||||
where := "channel_id = $1 AND NOT deleted"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue