fix: emit channel avatar service messages
This commit is contained in:
parent
4d9f1e271d
commit
c38dd73fdd
14 changed files with 346 additions and 27 deletions
|
|
@ -1206,6 +1206,10 @@ func TestTDesktopPassiveChannelStubs(t *testing.T) {
|
|||
}); err != nil {
|
||||
t.Fatalf("messages.addChatUser legacy wrapper: %v", err)
|
||||
}
|
||||
seedPhoto := domain.Photo{ID: 7701, AccessHash: 7702, DCID: 2}
|
||||
if _, err := f.channels.SetChannelPhoto(f.ctx, owner.ID, channel.ID, &seedPhoto, 1700007701); err != nil {
|
||||
t.Fatalf("seed channel photo before legacy clear: %v", err)
|
||||
}
|
||||
if _, err := r.onMessagesEditChatPhoto(ownerCtx, &tg.MessagesEditChatPhotoRequest{
|
||||
ChatID: channel.ID,
|
||||
Photo: &tg.InputChatPhotoEmpty{},
|
||||
|
|
|
|||
|
|
@ -372,11 +372,24 @@ func (r *Router) onChannelsEditPhoto(ctx context.Context, req *tg.ChannelsEditPh
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
channel, err := r.deps.Channels.SetPhoto(ctx, userID, channelID, photo)
|
||||
res, err := r.deps.Channels.SetPhoto(ctx, userID, channelID, photo, int(r.clock.Now().Unix()))
|
||||
if err != nil {
|
||||
return nil, channelAdminErr(err)
|
||||
}
|
||||
return r.channelStateMutationUpdates(ctx, userID, channel), nil
|
||||
r.invalidateRPCProjectionForChannel(res.Channel.ID)
|
||||
updates := r.channelPhotoUpdates(ctx, userID, res)
|
||||
r.pushChannelUpdates(ctx, userID, res.Channel.ID, res.Recipients, func(viewerUserID int64) *tg.Updates {
|
||||
return r.channelStateUpdates(viewerUserID, res.Channel)
|
||||
})
|
||||
if res.Event.Pts != 0 {
|
||||
r.enqueueChannelMessageFanout(ctx, userID, domain.SendChannelMessageResult{
|
||||
Channel: res.Channel,
|
||||
Message: res.Message,
|
||||
Event: res.Event,
|
||||
Recipients: res.Recipients,
|
||||
}, nil)
|
||||
}
|
||||
return updates, nil
|
||||
}
|
||||
|
||||
func (r *Router) channelTitleUpdates(ctx context.Context, viewerUserID int64, res domain.EditChannelTitleResult) *tg.Updates {
|
||||
|
|
@ -395,6 +408,22 @@ func (r *Router) channelTitleUpdates(ctx context.Context, viewerUserID int64, re
|
|||
}
|
||||
}
|
||||
|
||||
func (r *Router) channelPhotoUpdates(ctx context.Context, viewerUserID int64, res domain.SetChannelPhotoResult) *tg.Updates {
|
||||
updates := []tg.UpdateClass{&tg.UpdateChannel{ChannelID: res.Channel.ID}}
|
||||
if res.Event.Pts != 0 {
|
||||
if update := tgChannelUpdate(viewerUserID, res.Event); update != nil {
|
||||
updates = append(updates, update)
|
||||
}
|
||||
}
|
||||
return &tg.Updates{
|
||||
Updates: updates,
|
||||
Users: r.tgUsersForIDs(ctx, viewerUserID, []int64{res.Message.SenderUserID}),
|
||||
Chats: []tg.ChatClass{tgChannelChatMin(viewerUserID, res.Channel)},
|
||||
Date: int(r.clock.Now().Unix()),
|
||||
Seq: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func validChannelTitle(title string) bool {
|
||||
n := utf8.RuneCountInString(title)
|
||||
return n > 0 && n <= maxChannelTitleLength
|
||||
|
|
|
|||
|
|
@ -255,6 +255,113 @@ func TestMessagesGetChatsUsesBatchServiceRPC(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestChannelsEditPhotoReturnsServiceMessageUpdatesRPC(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
userStore := memory.NewUserStore()
|
||||
owner, err := userStore.Create(ctx, domain.User{AccessHash: 91, Phone: "15550009101", FirstName: "Owner"})
|
||||
if err != nil {
|
||||
t.Fatalf("create owner: %v", err)
|
||||
}
|
||||
member, err := userStore.Create(ctx, domain.User{AccessHash: 92, Phone: "15550009102", FirstName: "Member"})
|
||||
if err != nil {
|
||||
t.Fatalf("create member: %v", err)
|
||||
}
|
||||
channelStore := memory.NewChannelStore()
|
||||
channelService := appchannels.NewService(channelStore)
|
||||
created, err := channelService.CreateChannel(ctx, owner.ID, domain.CreateChannelRequest{
|
||||
Title: "Photo RPC",
|
||||
Megagroup: true,
|
||||
MemberUserIDs: []int64{member.ID},
|
||||
Date: 1700001900,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create channel: %v", err)
|
||||
}
|
||||
files := &fakeFiles{}
|
||||
photo := files.putPhoto(domain.Photo{
|
||||
ID: 9901,
|
||||
AccessHash: 9902,
|
||||
DCID: 2,
|
||||
Date: 1700001901,
|
||||
Sizes: []domain.PhotoSize{
|
||||
{Kind: domain.PhotoSizeKindStripped, Type: "i", Bytes: []byte{4, 5, 6}},
|
||||
{Kind: domain.PhotoSizeKindDefault, Type: "m", W: 160, H: 160, Size: 4096},
|
||||
},
|
||||
})
|
||||
r := New(Config{}, Deps{
|
||||
Users: appusers.NewService(userStore),
|
||||
Channels: channelService,
|
||||
Files: files,
|
||||
}, zaptest.NewLogger(t), clock.System)
|
||||
input := &tg.InputChannel{ChannelID: created.Channel.ID, AccessHash: created.Channel.AccessHash}
|
||||
|
||||
setResult, err := r.onChannelsEditPhoto(WithUserID(ctx, owner.ID), &tg.ChannelsEditPhotoRequest{
|
||||
Channel: input,
|
||||
Photo: &tg.InputChatPhoto{ID: &tg.InputPhoto{ID: photo.ID, AccessHash: photo.AccessHash}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("channels.editPhoto set: %v", err)
|
||||
}
|
||||
setAction := requireChannelPhotoServiceAction(t, setResult, created.Channel.ID)
|
||||
editPhoto, ok := setAction.(*tg.MessageActionChatEditPhoto)
|
||||
if !ok {
|
||||
t.Fatalf("set action = %T, want MessageActionChatEditPhoto", setAction)
|
||||
}
|
||||
tgPhoto, ok := editPhoto.Photo.(*tg.Photo)
|
||||
if !ok || tgPhoto.ID != photo.ID {
|
||||
t.Fatalf("set action photo = %#v, want tg.Photo id %d", editPhoto.Photo, photo.ID)
|
||||
}
|
||||
|
||||
clearResult, err := r.onChannelsEditPhoto(WithUserID(ctx, owner.ID), &tg.ChannelsEditPhotoRequest{
|
||||
Channel: input,
|
||||
Photo: &tg.InputChatPhotoEmpty{},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("channels.editPhoto clear: %v", err)
|
||||
}
|
||||
clearAction := requireChannelPhotoServiceAction(t, clearResult, created.Channel.ID)
|
||||
if _, ok := clearAction.(*tg.MessageActionChatDeletePhoto); !ok {
|
||||
t.Fatalf("clear action = %T, want MessageActionChatDeletePhoto", clearAction)
|
||||
}
|
||||
}
|
||||
|
||||
func requireChannelPhotoServiceAction(t *testing.T, updatesClass tg.UpdatesClass, channelID int64) tg.MessageActionClass {
|
||||
t.Helper()
|
||||
updates, ok := updatesClass.(*tg.Updates)
|
||||
if !ok {
|
||||
t.Fatalf("updates = %T, want *tg.Updates", updatesClass)
|
||||
}
|
||||
hasUpdateChannel := false
|
||||
var action tg.MessageActionClass
|
||||
for _, update := range updates.Updates {
|
||||
switch item := update.(type) {
|
||||
case *tg.UpdateChannel:
|
||||
if item.ChannelID == channelID {
|
||||
hasUpdateChannel = true
|
||||
}
|
||||
case *tg.UpdateNewChannelMessage:
|
||||
service, ok := item.Message.(*tg.MessageService)
|
||||
if !ok {
|
||||
t.Fatalf("new channel message = %T, want MessageService", item.Message)
|
||||
}
|
||||
action = service.Action
|
||||
}
|
||||
}
|
||||
if !hasUpdateChannel {
|
||||
t.Fatalf("updates = %+v, want UpdateChannel for %d", updates.Updates, channelID)
|
||||
}
|
||||
if action == nil {
|
||||
t.Fatalf("updates = %+v, want UpdateNewChannelMessage service action", updates.Updates)
|
||||
}
|
||||
if len(updates.Chats) == 0 {
|
||||
t.Fatalf("updates chats empty, want channel projection")
|
||||
}
|
||||
if len(updates.Users) == 0 {
|
||||
t.Fatalf("updates users empty, want service sender projection")
|
||||
}
|
||||
return action
|
||||
}
|
||||
|
||||
func TestMessagesGetPeerSettingsUsesResolveChannelForAccessCheck(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
userStore := memory.NewUserStore()
|
||||
|
|
|
|||
|
|
@ -205,6 +205,17 @@ func tgChannelMessageAction(action domain.ChannelMessageAction) tg.MessageAction
|
|||
userID = action.UserIDs[0]
|
||||
}
|
||||
return &tg.MessageActionChatDeleteUser{UserID: userID}
|
||||
case domain.ChannelActionChatEditPhoto:
|
||||
if action.Photo == nil {
|
||||
return nil
|
||||
}
|
||||
photo := tgPhoto(*action.Photo)
|
||||
if _, empty := photo.(*tg.PhotoEmpty); empty {
|
||||
return nil
|
||||
}
|
||||
return &tg.MessageActionChatEditPhoto{Photo: photo}
|
||||
case domain.ChannelActionChatDeletePhoto:
|
||||
return &tg.MessageActionChatDeletePhoto{}
|
||||
case domain.ChannelActionEditTitle:
|
||||
return &tg.MessageActionChatEditTitle{Title: action.Title}
|
||||
case domain.ChannelActionTopicCreate:
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ type ChannelsService interface {
|
|||
ResolvePublicUsername(ctx context.Context, userID int64, username string) (domain.Channel, bool, error)
|
||||
SearchPublicChannels(ctx context.Context, userID int64, query string, limit int) (domain.PublicChannelSearchResult, error)
|
||||
SetSignatures(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
|
||||
SetPhoto(ctx context.Context, userID, channelID int64, photo *domain.Photo) (domain.Channel, error)
|
||||
SetPhoto(ctx context.Context, userID, channelID int64, photo *domain.Photo, date int) (domain.SetChannelPhotoResult, error)
|
||||
SetPreHistoryHidden(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
|
||||
SetParticipantsHidden(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error)
|
||||
SetForum(ctx context.Context, userID, channelID int64, enabled, tabs bool) (domain.Channel, error)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue