fix: sync latest Android and langpack updates

This commit is contained in:
A 2026-07-02 14:09:24 +08:00
parent 20b388eeaa
commit 4570df5939
20 changed files with 12384 additions and 27 deletions

View file

@ -80,6 +80,96 @@ func TestChannelStoreEditAboutPersistsAndChecksPermission(t *testing.T) {
}
}
func TestChannelStoreCreatorCanEditOwnAdminRights(t *testing.T) {
pool := testPool(t)
ctx := context.Background()
suffix := randomSuffix(t)
users := NewUserStore(pool)
owner, err := users.Create(ctx, domain.User{
AccessHash: 141,
Phone: "+1888" + suffix + "11",
FirstName: "CreatorSelfOwner",
})
if err != nil {
t.Fatalf("create owner: %v", err)
}
admin, err := users.Create(ctx, domain.User{
AccessHash: 142,
Phone: "+1888" + suffix + "12",
FirstName: "CreatorSelfAdmin",
})
if err != nil {
t.Fatalf("create admin: %v", err)
}
var channelID int64
t.Cleanup(func() {
if channelID != 0 {
_, _ = pool.Exec(ctx, "DELETE FROM channels WHERE id = $1", channelID)
}
_, _ = pool.Exec(ctx, "DELETE FROM users WHERE id = ANY($1::bigint[])", []int64{owner.ID, admin.ID})
})
channels := NewChannelStore(pool)
created, err := channels.CreateChannel(ctx, domain.CreateChannelRequest{
CreatorUserID: owner.ID,
Title: "Creator Self " + suffix,
Megagroup: true,
MemberUserIDs: []int64{admin.ID},
Date: 1700000610,
})
if err != nil {
t.Fatalf("create channel: %v", err)
}
channelID = created.Channel.ID
edited, err := channels.EditChannelAdmin(ctx, domain.EditChannelAdminRequest{
UserID: owner.ID,
ChannelID: channelID,
MemberID: owner.ID,
AdminRights: domain.ChannelAdminRights{
Anonymous: true,
},
Date: 1700000611,
})
if err != nil {
t.Fatalf("creator edits own admin rights: %v", err)
}
if edited.Participant.Role != domain.ChannelRoleCreator || !edited.Participant.AdminRights.Anonymous || !edited.Participant.AdminRights.ChangeInfo || !edited.Participant.AdminRights.AddAdmins {
t.Fatalf("edited creator = %+v, want creator with anonymous plus full creator projection", edited.Participant)
}
persisted, err := channels.GetParticipant(ctx, owner.ID, channelID, owner.ID)
if err != nil {
t.Fatalf("get creator participant: %v", err)
}
if persisted.Role != domain.ChannelRoleCreator || !persisted.AdminRights.Anonymous || !persisted.AdminRights.ChangeInfo || !persisted.AdminRights.AddAdmins {
t.Fatalf("persisted creator = %+v, want creator with anonymous plus full creator projection", persisted)
}
if _, err := channels.EditChannelAdmin(ctx, domain.EditChannelAdminRequest{
UserID: owner.ID,
ChannelID: channelID,
MemberID: admin.ID,
AdminRights: domain.ChannelAdminRights{
ChangeInfo: true,
AddAdmins: true,
},
Date: 1700000612,
}); err != nil {
t.Fatalf("promote admin: %v", err)
}
if _, err := channels.EditChannelAdmin(ctx, domain.EditChannelAdminRequest{
UserID: admin.ID,
ChannelID: channelID,
MemberID: owner.ID,
AdminRights: domain.ChannelAdminRights{
ChangeInfo: true,
},
Date: 1700000613,
}); !errors.Is(err, domain.ErrChannelUserCreator) {
t.Fatalf("admin edits creator err = %v, want ErrChannelUserCreator", err)
}
}
func TestChannelStoreAdminLogFiltersAndSearch(t *testing.T) {
pool := testPool(t)
ctx := context.Background()

View file

@ -783,7 +783,8 @@ func adminRightsSubset(want, have domain.ChannelAdminRights) bool {
(!want.AddAdmins || have.AddAdmins) &&
(!want.ManageCall || have.ManageCall) &&
(!want.Anonymous || have.Anonymous) &&
(!want.ManageRanks || have.ManageRanks)
(!want.ManageRanks || have.ManageRanks) &&
(!want.ManageDirectMessages || have.ManageDirectMessages)
}
// checkEditMemberRank validates a rank-only (member tag) edit: creator edits

View file

@ -35,9 +35,6 @@ func (s *ChannelStore) EditChannelAdmin(ctx context.Context, req domain.EditChan
if !canAddChannelAdmins(actor) {
return domain.EditChannelAdminResult{}, domain.ErrChannelAdminRequired
}
if actor.Role != domain.ChannelRoleCreator && !adminRightsSubset(req.AdminRights, actor.AdminRights) {
return domain.EditChannelAdminResult{}, domain.ErrChannelRightForbidden
}
previous, err := s.getChannelMember(ctx, tx, req.ChannelID, req.MemberID)
if err != nil {
if !errors.Is(err, domain.ErrChannelPrivate) {
@ -56,13 +53,52 @@ func (s *ChannelStore) EditChannelAdmin(ctx context.Context, req domain.EditChan
}
}
if previous.Role == domain.ChannelRoleCreator {
return domain.EditChannelAdminResult{}, domain.ErrChannelUserCreator
if req.MemberID != req.UserID || channel.CreatorUserID != req.UserID || actor.Role != domain.ChannelRoleCreator {
return domain.EditChannelAdminResult{}, domain.ErrChannelUserCreator
}
member := previous
member.Status = domain.ChannelMemberActive
member.LeftAt = 0
member.AdminRights = domain.CreatorProjectionAdminRights(req.AdminRights)
if req.HasRank() {
member.Rank = req.Rank
}
if err := upsertChannelMemberTx(ctx, tx, channel, member); err != nil {
return domain.EditChannelAdminResult{}, err
}
if err := s.insertChannelAdminLogTx(ctx, tx, domain.ChannelAdminLogEvent{
ChannelID: req.ChannelID,
UserID: req.UserID,
Date: req.Date,
Type: domain.ChannelAdminLogParticipantPromote,
PrevParticipant: &previous,
NewParticipant: &member,
}); err != nil {
return domain.EditChannelAdminResult{}, err
}
channel, err = refreshChannelCountsTx(ctx, tx, channel)
if err != nil {
return domain.EditChannelAdminResult{}, err
}
event := transientChannelParticipantEvent(channel.ID, req.UserID, previous, member, req.Date)
if err := tx.Commit(ctx); err != nil {
return domain.EditChannelAdminResult{}, fmt.Errorf("commit edit channel creator admin: %w", err)
}
committed = true
recipients, _ := s.ListActiveChannelMemberIDs(ctx, req.UserID, req.ChannelID, 0)
recipients = append(recipients, req.MemberID)
return domain.EditChannelAdminResult{Channel: channel, Previous: previous, Participant: member, Event: event, Recipients: recipients, Date: req.Date}, nil
}
if actor.Role != domain.ChannelRoleCreator && !adminRightsSubset(req.AdminRights, actor.AdminRights) {
return domain.EditChannelAdminResult{}, domain.ErrChannelRightForbidden
}
member := previous
member.InviterUserID = req.UserID
member.Status = domain.ChannelMemberActive
member.LeftAt = 0
member.Rank = req.Rank
if req.HasRank() {
member.Rank = req.Rank
}
if previous.Status != domain.ChannelMemberActive {
if minPts := channelInitialAvailableMinPts(channel); minPts > member.AvailableMinPts {
member.AvailableMinPts = minPts