Ctrl K
ComunidadGuías…

internal/store/postgres/channel_member_join_requests.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package postgres

import (
	"context"
	"errors"
	"fmt"
	"github.com/jackc/pgx/v5"
	"strings"
	"telesrv/internal/domain"
)

func (s *ChannelStore) SetParticipantsHidden(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error) {
	if userID == 0 || channelID == 0 {
		return domain.Channel{}, domain.ErrChannelInvalid
	}
	var channel domain.Channel
	if err := withTx(ctx, s.db, "toggle channel participants hidden", func(tx pgx.Tx) error {
		var err error
		var member domain.ChannelMember
		channel, member, err = s.getChannelForMember(ctx, tx, userID, channelID)
		if err != nil {
			return err
		}
		if !channel.Megagroup || !canBanChannelUsers(member) {
			return domain.ErrChannelAdminRequired
		}
		if _, err := tx.Exec(ctx, `UPDATE channels SET participants_hidden = $2, updated_at = now() WHERE id = $1`, channelID, enabled); err != nil {
			return fmt.Errorf("update channel participants hidden: %w", err)
		}
		channel.ParticipantsHidden = enabled
		return nil
	}); err != nil {
		return domain.Channel{}, err
	}
	return channel, nil
}

func (s *ChannelStore) SetJoinToSend(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error) {
	if userID == 0 || channelID == 0 {
		return domain.Channel{}, domain.ErrChannelInvalid
	}
	var channel domain.Channel
	if err := withTx(ctx, s.db, "toggle channel join_to_send", func(tx pgx.Tx) error {
		var err error
		var member domain.ChannelMember
		channel, member, err = s.getChannelForMember(ctx, tx, userID, channelID)
		if err != nil {
			return err
		}
		if !channel.Megagroup || !canExportChannelInvite(member) {
			return domain.ErrChannelAdminRequired
		}
		if _, err := tx.Exec(ctx, `UPDATE channels SET join_to_send = $2, updated_at = now() WHERE id = $1`, channelID, enabled); err != nil {
			return fmt.Errorf("update channel join_to_send: %w", err)
		}
		channel.JoinToSend = enabled
		return nil
	}); err != nil {
		return domain.Channel{}, err
	}
	return channel, nil
}

func (s *ChannelStore) SetJoinRequest(ctx context.Context, userID, channelID int64, enabled bool) (domain.Channel, error) {
	if userID == 0 || channelID == 0 {
		return domain.Channel{}, domain.ErrChannelInvalid
	}
	var channel domain.Channel
	if err := withTx(ctx, s.db, "toggle channel join_request", func(tx pgx.Tx) error {
		var err error
		var member domain.ChannelMember
		channel, member, err = s.getChannelForMember(ctx, tx, userID, channelID)
		if err != nil {
			return err
		}
		if !channel.Megagroup || !canExportChannelInvite(member) {
			return domain.ErrChannelAdminRequired
		}
		if enabled && strings.TrimSpace(channel.Username) == "" {
			return domain.ErrChatPublicRequired
		}
		if _, err := tx.Exec(ctx, `UPDATE channels SET join_request = $2, updated_at = now() WHERE id = $1`, channelID, enabled); err != nil {
			return fmt.Errorf("update channel join_request: %w", err)
		}
		channel.JoinRequest = enabled
		return nil
	}); err != nil {
		return domain.Channel{}, err
	}
	return channel, nil
}

func (s *ChannelStore) recordPublicJoinRequestTx(ctx context.Context, tx pgx.Tx, channel domain.Channel, userID int64, date int) error {
	if existing, err := s.getChannelMember(ctx, tx, channel.ID, userID); err == nil {
		if existing.Status == domain.ChannelMemberActive {
			return domain.ErrUserAlreadyParticipant
		}
		if existing.Status == domain.ChannelMemberKicked || existing.Status == domain.ChannelMemberBanned || existing.BannedRights.ViewMessages {
			return domain.ErrInviteHashInvalid
		}
	} else if !errors.Is(err, domain.ErrChannelPrivate) {
		return err
	}
	if existing, err := s.getPendingInviteImporterTx(ctx, tx, channel.ID, userID, true); err == nil && existing.Requested {
		return domain.ErrInviteRequestSent
	} else if err != nil && !errors.Is(err, domain.ErrHideRequesterMissing) {
		return err
	}
	if _, err := tx.Exec(ctx, `
INSERT INTO channel_invite_importers (channel_id, invite_id, user_id, date, requested)
VALUES ($1, 0, $2, $3, true)
ON CONFLICT (channel_id, user_id) DO UPDATE
SET invite_id = 0,
    date = EXCLUDED.date,
    requested = true,
    approved_by = 0,
    updated_at = now()`, channel.ID, userID, date); err != nil {
		return fmt.Errorf("insert public channel join request: %w", err)
	}
	return nil
}

func (s *ChannelStore) HideChatJoinRequest(ctx context.Context, req domain.HideChannelJoinRequestRequest) (domain.CreateChannelResult, error) {
	if req.UserID == 0 || req.ChannelID == 0 || req.TargetUserID == 0 {
		return domain.CreateChannelResult{}, domain.ErrChannelInvalid
	}
	if req.Date == 0 {
		req.Date = nowUnix()
	}
	beginner, ok := s.db.(txBeginner)
	if !ok {
		return domain.CreateChannelResult{}, fmt.Errorf("hide channel join request: db does not support transactions")
	}
	tx, err := beginner.Begin(ctx)
	if err != nil {
		return domain.CreateChannelResult{}, fmt.Errorf("begin hide channel join request: %w", err)
	}
	committed := false
	defer func() {
		if !committed {
			_ = tx.Rollback(ctx)
		}
	}()
	channel, member, err := s.getChannelForMember(ctx, tx, req.UserID, req.ChannelID)
	if err != nil {
		return domain.CreateChannelResult{}, err
	}
	if !canExportChannelInvite(member) {
		return domain.CreateChannelResult{}, domain.ErrChannelAdminRequired
	}
	importer, err := s.getPendingInviteImporterTx(ctx, tx, req.ChannelID, req.TargetUserID, true)
	if err != nil {
		return domain.CreateChannelResult{}, err
	}
	invite := domain.ChannelInvite{ChannelID: req.ChannelID, AdminUserID: req.UserID}
	if importer.InviteID != 0 {
		invite, err = s.getInviteByID(ctx, tx, req.ChannelID, importer.InviteID, true)
		if err != nil {
			return domain.CreateChannelResult{}, err
		}
	}
	var result domain.CreateChannelResult
	if req.Approved {
		result, err = s.approveInviteImporterTx(ctx, tx, channel, invite, req.TargetUserID, req.UserID, req.Date)
		if err != nil {
			return domain.CreateChannelResult{}, err
		}
	} else if err := deletePendingInviteImporterTx(ctx, tx, invite, req.TargetUserID); err != nil {
		return domain.CreateChannelResult{}, err
	} else {
		result = domain.CreateChannelResult{Channel: channel}
	}
	if err := tx.Commit(ctx); err != nil {
		return domain.CreateChannelResult{}, fmt.Errorf("commit hide channel join request: %w", err)
	}
	committed = true
	recipients, _ := s.ListActiveChannelMemberIDs(ctx, req.UserID, req.ChannelID, 0)
	result.Recipients = recipients
	return result, nil
}