211 lines
6.6 KiB
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()
|
|
}
|