owpengram-server/internal/store/postgres/channel_member_join_requests.go

180 lines
6.2 KiB
Go

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
}