channels: force pre-history visible when a group gets a public username
New supergroups are created with "chat history for new members" hidden (the client sets this right after creation, matching official Telegram). The official server then forces it back to visible when the group is made public; owpengram's UpdateUsername left the flag alone, leaving public groups in a state where non-members (and post-join members) see no history at all. UpdateUsername now clears pre_history_hidden whenever a non-empty username is assigned, in the same transaction, with a matching admin-log event. Removing the username leaves the flag untouched, so the creator can hide history again once the group is private.
This commit is contained in:
parent
7daaaf164f
commit
879ff48b49
3 changed files with 90 additions and 1 deletions
|
|
@ -2761,6 +2761,61 @@ func TestChannelUsernameAndSignatures(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateUsernameForcesPreHistoryVisible(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
const ownerID int64 = 1001
|
||||||
|
service := NewService(memory.NewChannelStore())
|
||||||
|
created, err := service.CreateMegagroupFromCreateChat(ctx, ownerID, domain.CreateChannelRequest{
|
||||||
|
Title: "Private First",
|
||||||
|
MemberUserIDs: []int64{1002},
|
||||||
|
Date: 10,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("CreateMegagroupFromCreateChat: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hidden, err := service.SetPreHistoryHidden(ctx, ownerID, created.Channel.ID, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SetPreHistoryHidden: %v", err)
|
||||||
|
}
|
||||||
|
if !hidden.PreHistoryHidden {
|
||||||
|
t.Fatalf("hidden channel = %+v, want pre-history hidden", hidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assigning a public username must force pre-history back to visible.
|
||||||
|
public, err := service.UpdateUsername(ctx, ownerID, domain.UpdateChannelUsernameRequest{
|
||||||
|
ChannelID: created.Channel.ID,
|
||||||
|
Username: "private_first_pub",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("UpdateUsername: %v", err)
|
||||||
|
}
|
||||||
|
if public.PreHistoryHidden {
|
||||||
|
t.Fatalf("public channel = %+v, want pre-history visible after publish", public)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removing the username leaves the flag alone (still visible).
|
||||||
|
private, err := service.UpdateUsername(ctx, ownerID, domain.UpdateChannelUsernameRequest{
|
||||||
|
ChannelID: created.Channel.ID,
|
||||||
|
Username: "",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("UpdateUsername clear: %v", err)
|
||||||
|
}
|
||||||
|
if private.PreHistoryHidden {
|
||||||
|
t.Fatalf("re-privated channel = %+v, want pre-history still visible", private)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...and the creator can hide it again once private.
|
||||||
|
rehidden, err := service.SetPreHistoryHidden(ctx, ownerID, created.Channel.ID, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SetPreHistoryHidden after re-privating: %v", err)
|
||||||
|
}
|
||||||
|
if !rehidden.PreHistoryHidden {
|
||||||
|
t.Fatalf("re-hidden channel = %+v, want pre-history hidden again", rehidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestListStoryPostableChannelsFiltersPostStoryRights(t *testing.T) {
|
func TestListStoryPostableChannelsFiltersPostStoryRights(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
service := NewService(memory.NewChannelStore())
|
service := NewService(memory.NewChannelStore())
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,13 @@ func (s *ChannelStore) UpdateUsername(ctx context.Context, req domain.UpdateChan
|
||||||
}
|
}
|
||||||
prevUsername := channel.Username
|
prevUsername := channel.Username
|
||||||
channel.Username = username
|
channel.Username = username
|
||||||
|
// A public group cannot keep pre-history hidden: assigning a username forces
|
||||||
|
// "chat history for new members" back to visible (matches the official
|
||||||
|
// server). Removing the username leaves the flag untouched.
|
||||||
|
clearedPrehistory := username != "" && channel.PreHistoryHidden
|
||||||
|
if clearedPrehistory {
|
||||||
|
channel.PreHistoryHidden = false
|
||||||
|
}
|
||||||
s.channels[req.ChannelID] = channel
|
s.channels[req.ChannelID] = channel
|
||||||
s.appendChannelAdminLogLocked(domain.ChannelAdminLogEvent{
|
s.appendChannelAdminLogLocked(domain.ChannelAdminLogEvent{
|
||||||
ChannelID: req.ChannelID,
|
ChannelID: req.ChannelID,
|
||||||
|
|
@ -184,6 +191,16 @@ func (s *ChannelStore) UpdateUsername(ctx context.Context, req domain.UpdateChan
|
||||||
PrevString: prevUsername,
|
PrevString: prevUsername,
|
||||||
NewString: username,
|
NewString: username,
|
||||||
})
|
})
|
||||||
|
if clearedPrehistory {
|
||||||
|
s.appendChannelAdminLogLocked(domain.ChannelAdminLogEvent{
|
||||||
|
ChannelID: req.ChannelID,
|
||||||
|
UserID: req.UserID,
|
||||||
|
Date: int(time.Now().Unix()),
|
||||||
|
Type: domain.ChannelAdminLogTogglePreHistoryHidden,
|
||||||
|
PrevBool: true,
|
||||||
|
NewBool: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
return channel, nil
|
return channel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -241,12 +241,29 @@ func (s *ChannelStore) UpdateUsername(ctx context.Context, req domain.UpdateChan
|
||||||
if err := replacePeerUsernameTx(ctx, tx, peerUsernameTypeChannel, req.ChannelID, username, usernameLower); err != nil {
|
if err := replacePeerUsernameTx(ctx, tx, peerUsernameTypeChannel, req.ChannelID, username, usernameLower); err != nil {
|
||||||
return domain.Channel{}, err
|
return domain.Channel{}, err
|
||||||
}
|
}
|
||||||
if _, err := tx.Exec(ctx, `UPDATE channels SET username = NULLIF($2,''), updated_at = now() WHERE id = $1`, req.ChannelID, username); err != nil {
|
// A public group cannot keep pre-history hidden: assigning a username forces
|
||||||
|
// "chat history for new members" back to visible (matches the official
|
||||||
|
// server). Removing the username leaves the flag untouched, so the creator
|
||||||
|
// can hide history again once the group is private.
|
||||||
|
if _, err := tx.Exec(ctx, `UPDATE channels SET username = NULLIF($2,''), pre_history_hidden = (pre_history_hidden AND $2 = ''), updated_at = now() WHERE id = $1`, req.ChannelID, username); err != nil {
|
||||||
return domain.Channel{}, fmt.Errorf("update channel username: %w", err)
|
return domain.Channel{}, fmt.Errorf("update channel username: %w", err)
|
||||||
}
|
}
|
||||||
if err := markUserChannelMemberIndexPublicTx(ctx, tx, req.ChannelID, username != ""); err != nil {
|
if err := markUserChannelMemberIndexPublicTx(ctx, tx, req.ChannelID, username != ""); err != nil {
|
||||||
return domain.Channel{}, err
|
return domain.Channel{}, err
|
||||||
}
|
}
|
||||||
|
if username != "" && channel.PreHistoryHidden {
|
||||||
|
if err := s.insertChannelAdminLogTx(ctx, tx, domain.ChannelAdminLogEvent{
|
||||||
|
ChannelID: req.ChannelID,
|
||||||
|
UserID: req.UserID,
|
||||||
|
Date: nowUnix(),
|
||||||
|
Type: domain.ChannelAdminLogTogglePreHistoryHidden,
|
||||||
|
PrevBool: true,
|
||||||
|
NewBool: false,
|
||||||
|
}); err != nil {
|
||||||
|
return domain.Channel{}, err
|
||||||
|
}
|
||||||
|
channel.PreHistoryHidden = false
|
||||||
|
}
|
||||||
prevUsername := channel.Username
|
prevUsername := channel.Username
|
||||||
channel.Username = username
|
channel.Username = username
|
||||||
if err := s.insertChannelAdminLogTx(ctx, tx, domain.ChannelAdminLogEvent{
|
if err := s.insertChannelAdminLogTx(ctx, tx, domain.ChannelAdminLogEvent{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue