fix: sync linked discussion guest support

This commit is contained in:
A 2026-07-11 23:18:24 +08:00
parent 5f7c0b9804
commit 9f73dc20da
27 changed files with 1004 additions and 30 deletions

View file

@ -25,6 +25,77 @@ func (s *ChannelStore) getChannelForMember(ctx context.Context, db sqlcgen.DBTX,
return ch, member, nil
}
func (s *ChannelStore) getChannelForMemberOrLinkedGuest(ctx context.Context, db sqlcgen.DBTX, viewerUserID, channelID int64) (domain.Channel, domain.ChannelMember, error) {
channel, member, err := s.getChannelForMember(ctx, db, viewerUserID, channelID)
if !errors.Is(err, domain.ErrChannelPrivate) {
return channel, member, err
}
target, targetErr := s.channelByID(ctx, db, channelID)
if targetErr != nil {
return domain.Channel{}, domain.ChannelMember{}, targetErr
}
guest, allowed, guestErr := s.getLinkedDiscussionGuest(ctx, db, viewerUserID, target)
if guestErr != nil {
return domain.Channel{}, domain.ChannelMember{}, guestErr
}
if !allowed {
return domain.Channel{}, domain.ChannelMember{}, err
}
return target, guest, nil
}
// getLinkedDiscussionGuest authorizes a private discussion group through an
// active membership in its bidirectionally linked broadcast. The returned
// member is computed only and must never be persisted. An explicit target ban
// or kick takes precedence over the source-channel membership.
func (s *ChannelStore) getLinkedDiscussionGuest(ctx context.Context, db sqlcgen.DBTX, viewerUserID int64, target domain.Channel) (domain.ChannelMember, bool, error) {
if target.Broadcast || !target.Megagroup || target.LinkedChatID == 0 {
return domain.ChannelMember{}, false, nil
}
existing, err := s.getChannelMember(ctx, db, target.ID, viewerUserID)
if err == nil {
if existing.Status == domain.ChannelMemberBanned || existing.Status == domain.ChannelMemberKicked || existing.BannedRights.ViewMessages {
return domain.ChannelMember{}, false, domain.ErrChannelUserBanned
}
if existing.Status == domain.ChannelMemberActive {
return existing, false, nil
}
} else if !errors.Is(err, domain.ErrChannelPrivate) {
return domain.ChannelMember{}, false, err
}
source, err := s.channelByID(ctx, db, target.LinkedChatID)
if err != nil {
if errors.Is(err, domain.ErrChannelInvalid) {
return domain.ChannelMember{}, false, nil
}
return domain.ChannelMember{}, false, err
}
if !source.Broadcast || source.LinkedChatID != target.ID {
return domain.ChannelMember{}, false, nil
}
sourceMember, err := s.getChannelMember(ctx, db, source.ID, viewerUserID)
if err != nil {
if errors.Is(err, domain.ErrChannelPrivate) {
return domain.ChannelMember{}, false, nil
}
return domain.ChannelMember{}, false, err
}
if err := validateChannelMemberVisible(sourceMember); err != nil {
return domain.ChannelMember{}, false, err
}
guest := domain.ChannelMember{
ChannelID: target.ID,
UserID: viewerUserID,
Status: domain.ChannelMemberLeft,
Role: domain.ChannelRoleMember,
Guest: true,
}
if s.memberCacheActive(db) {
s.memberCache.put(guest)
}
return guest, true, nil
}
func (s *ChannelStore) getPublicPreviewMember(ctx context.Context, db sqlcgen.DBTX, viewerUserID int64, ch domain.Channel) (domain.ChannelMember, error) {
member, err := s.getChannelMember(ctx, db, ch.ID, viewerUserID)
if err != nil {