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

211 lines
6.6 KiB
Go

package postgres
import (
"context"
"fmt"
"strings"
"telesrv/internal/domain"
)
func (s *ChannelStore) ListInviteImporters(ctx context.Context, req domain.ChannelInviteImportersRequest) (domain.ChannelInviteImporterList, error) {
if req.UserID == 0 || req.ChannelID == 0 {
return domain.ChannelInviteImporterList{}, domain.ErrChannelInvalid
}
if _, member, err := s.getChannelForMember(ctx, s.db, req.UserID, req.ChannelID); err != nil {
return domain.ChannelInviteImporterList{}, err
} else if !canExportChannelInvite(member) {
return domain.ChannelInviteImporterList{}, domain.ErrChannelAdminRequired
}
var inviteID int64
if req.Hash != "" {
invite, err := s.getInviteByChannelHash(ctx, s.db, req.ChannelID, req.Hash, false)
if err != nil {
return domain.ChannelInviteImporterList{}, err
}
inviteID = invite.InviteID
}
limit := req.Limit
if limit <= 0 || limit > domain.MaxChannelInviteListLimit {
limit = domain.MaxChannelInviteListLimit
}
args := []any{req.ChannelID, req.Requested, inviteID, req.Query, req.OffsetDate, req.OffsetUserID, limit}
where := []string{
"i.channel_id = $1",
"i.requested = $2",
"($3::bigint = 0 OR i.invite_id = $3)",
"($4::text = '' OR lower(trim(u.username || ' ' || u.first_name || ' ' || u.last_name)) LIKE '%' || lower($4) || '%')",
"(($5::int = 0 AND $6::bigint = 0) OR (i.date, i.user_id) < ($5, $6))",
}
whereSQL := strings.Join(where, " AND ")
var total int
if err := s.db.QueryRow(ctx, `
SELECT COUNT(*)::int
FROM channel_invite_importers i
JOIN users u ON u.id = i.user_id
WHERE `+whereSQL, args[:6]...).Scan(&total); err != nil {
return domain.ChannelInviteImporterList{}, err
}
rows, err := s.db.Query(ctx, `
SELECT i.channel_id, i.invite_id, i.user_id, i.date, i.requested, i.approved_by, i.via_chatlist, i.about
FROM channel_invite_importers i
JOIN users u ON u.id = i.user_id
WHERE `+whereSQL+`
ORDER BY i.date DESC, i.user_id DESC
LIMIT $7`, args...)
if err != nil {
return domain.ChannelInviteImporterList{}, err
}
defer rows.Close()
importers := make([]domain.ChannelInviteImporter, 0, limit)
for rows.Next() {
var importer domain.ChannelInviteImporter
if err := rows.Scan(&importer.ChannelID, &importer.InviteID, &importer.UserID, &importer.Date, &importer.Requested, &importer.ApprovedBy, &importer.ViaChatlist, &importer.About); err != nil {
return domain.ChannelInviteImporterList{}, err
}
importers = append(importers, importer)
}
if err := rows.Err(); err != nil {
return domain.ChannelInviteImporterList{}, err
}
return domain.ChannelInviteImporterList{Count: total, Importers: importers}, nil
}
func (s *ChannelStore) PendingJoinRequests(ctx context.Context, channelID int64, limit int) (domain.ChannelPendingJoinRequests, error) {
if channelID == 0 {
return domain.ChannelPendingJoinRequests{}, domain.ErrChannelInvalid
}
if limit <= 0 || limit > domain.MaxChannelPendingJoinRecentRequesters {
limit = domain.MaxChannelPendingJoinRecentRequesters
}
rows, err := s.db.Query(ctx, `
SELECT user_id, COUNT(*) OVER()::int
FROM channel_invite_importers
WHERE channel_id = $1 AND requested
ORDER BY date DESC, user_id DESC
LIMIT $2`, channelID, limit)
if err != nil {
return domain.ChannelPendingJoinRequests{}, fmt.Errorf("list pending channel join requests: %w", err)
}
defer rows.Close()
out := domain.ChannelPendingJoinRequests{
ChannelID: channelID,
RecentRequesters: make([]int64, 0, limit),
}
for rows.Next() {
var userID int64
var count int
if err := rows.Scan(&userID, &count); err != nil {
return domain.ChannelPendingJoinRequests{}, err
}
out.Count = count
out.RecentRequesters = append(out.RecentRequesters, userID)
}
if err := rows.Err(); err != nil {
return domain.ChannelPendingJoinRequests{}, err
}
return out, nil
}
func (s *ChannelStore) HideAllChatJoinRequests(ctx context.Context, req domain.HideChannelJoinRequestsRequest) (domain.CreateChannelResult, error) {
if req.UserID == 0 || req.ChannelID == 0 {
return domain.CreateChannelResult{}, domain.ErrChannelInvalid
}
if req.Date == 0 {
req.Date = nowUnix()
}
var inviteID int64
if req.Hash != "" {
invite, err := s.GetExportedInvite(ctx, domain.GetChannelInviteRequest{UserID: req.UserID, ChannelID: req.ChannelID, Hash: req.Hash})
if err != nil {
return domain.CreateChannelResult{}, err
}
inviteID = invite.InviteID
}
limit := req.Limit
if limit <= 0 || limit > domain.MaxChannelHideJoinRequests {
limit = domain.MaxChannelHideJoinRequests
}
rows, err := s.db.Query(ctx, `
SELECT user_id
FROM channel_invite_importers
WHERE channel_id = $1 AND requested AND ($2::bigint = 0 OR invite_id = $2)
ORDER BY date ASC, user_id ASC
LIMIT $3`, req.ChannelID, inviteID, limit)
if err != nil {
return domain.CreateChannelResult{}, err
}
targets := make([]int64, 0, limit)
for rows.Next() {
var userID int64
if err := rows.Scan(&userID); err != nil {
rows.Close()
return domain.CreateChannelResult{}, err
}
targets = append(targets, userID)
}
if err := rows.Err(); err != nil {
rows.Close()
return domain.CreateChannelResult{}, err
}
rows.Close()
var result domain.CreateChannelResult
for _, target := range targets {
next, err := s.HideChatJoinRequest(ctx, domain.HideChannelJoinRequestRequest{
UserID: req.UserID,
ChannelID: req.ChannelID,
TargetUserID: target,
Approved: req.Approved,
Date: req.Date,
})
if err != nil {
return domain.CreateChannelResult{}, err
}
result = next
}
if result.Channel.ID == 0 {
ch, _, err := s.getChannelForMember(ctx, s.db, req.UserID, req.ChannelID)
if err != nil {
return domain.CreateChannelResult{}, err
}
result.Channel = ch
recipients, _ := s.ListActiveChannelMemberIDs(ctx, req.UserID, req.ChannelID, 0)
result.Recipients = recipients
}
return result, nil
}
func (s *ChannelStore) ListChannelInviteAdminMemberIDs(ctx context.Context, channelID int64, limit int) ([]int64, error) {
if channelID == 0 {
return nil, domain.ErrChannelInvalid
}
if limit <= 0 || limit > domain.MaxChannelRealtimeFanout {
limit = domain.MaxChannelRealtimeFanout
}
rows, err := s.db.Query(ctx, `
SELECT user_id
FROM channel_members
WHERE channel_id = $1
AND status = 'active'
AND (
role = 'creator' OR
(role = 'admin' AND (
(admin_rights->>'InviteUsers')::boolean IS TRUE OR
(admin_rights->>'ChangeInfo')::boolean IS TRUE
))
)
ORDER BY user_id
LIMIT $2`, channelID, limit)
if err != nil {
return nil, fmt.Errorf("list channel invite admin members: %w", err)
}
defer rows.Close()
out := make([]int64, 0, limit)
for rows.Next() {
var userID int64
if err := rows.Scan(&userID); err != nil {
return nil, err
}
out = append(out, userID)
}
return out, rows.Err()
}