Sync telesrv 36eda30 (feat(communities): implement Layer 228 community aggregates). Skipped telesrv docs changes per public sync rules; normalized the public appearance seed label.
185 lines
8.3 KiB
Go
185 lines
8.3 KiB
Go
package communities
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"unicode/utf8"
|
|
|
|
"telesrv/internal/domain"
|
|
"telesrv/internal/store"
|
|
)
|
|
|
|
// Service owns Community business validation. The store is the aggregate
|
|
// transaction boundary because link changes span community/link and peer rows.
|
|
type Service struct {
|
|
communities store.CommunityStore
|
|
}
|
|
|
|
func NewService(communities store.CommunityStore) *Service {
|
|
return &Service{communities: communities}
|
|
}
|
|
|
|
func validPeer(peer domain.Peer) bool {
|
|
return peer.ID > 0 && (peer.Type == domain.PeerTypeChannel || peer.Type == domain.PeerTypeUser)
|
|
}
|
|
|
|
func validVisibility(v domain.CommunityPeerVisibility) bool {
|
|
return v == domain.CommunityPeerVisible || v == domain.CommunityPeerHidden
|
|
}
|
|
|
|
func (s *Service) Create(ctx context.Context, userID int64, req domain.CreateCommunityRequest) (domain.CommunityView, error) {
|
|
if s == nil || s.communities == nil || userID == 0 || !validPeer(req.InitialPeer) || !validVisibility(req.Visibility) {
|
|
return domain.CommunityView{}, domain.ErrCommunityInvalid
|
|
}
|
|
req.CreatorUserID = userID
|
|
req.Title = strings.TrimSpace(req.Title)
|
|
req.About = strings.TrimSpace(req.About)
|
|
if req.Title == "" || utf8.RuneCountInString(req.Title) > domain.MaxCommunityTitleRunes {
|
|
return domain.CommunityView{}, domain.ErrChannelTitleInvalid
|
|
}
|
|
if utf8.RuneCountInString(req.About) > domain.MaxCommunityAboutRunes {
|
|
return domain.CommunityView{}, domain.ErrAboutTooLong
|
|
}
|
|
return s.communities.CreateCommunity(ctx, req)
|
|
}
|
|
|
|
func (s *Service) Get(ctx context.Context, userID, communityID int64) (domain.CommunityView, error) {
|
|
if s == nil || s.communities == nil || userID == 0 || communityID == 0 {
|
|
return domain.CommunityView{}, domain.ErrCommunityInvalid
|
|
}
|
|
return s.communities.GetCommunity(ctx, userID, communityID)
|
|
}
|
|
|
|
func (s *Service) GetMany(ctx context.Context, userID int64, ids []int64) ([]domain.CommunityView, error) {
|
|
if s == nil || s.communities == nil || userID == 0 {
|
|
return nil, domain.ErrCommunityInvalid
|
|
}
|
|
return s.communities.GetCommunities(ctx, userID, ids)
|
|
}
|
|
|
|
func (s *Service) ListJoined(ctx context.Context, userID int64) ([]domain.CommunityView, error) {
|
|
if s == nil || s.communities == nil || userID == 0 {
|
|
return nil, domain.ErrCommunityInvalid
|
|
}
|
|
return s.communities.ListJoinedCommunities(ctx, userID)
|
|
}
|
|
|
|
func (s *Service) TogglePeerLink(ctx context.Context, userID int64, req domain.CommunityTogglePeerLinkRequest) (domain.CommunityTogglePeerLinkResult, error) {
|
|
if s == nil || s.communities == nil || userID == 0 || req.CommunityID == 0 || !validPeer(req.Peer) {
|
|
return domain.CommunityTogglePeerLinkResult{}, domain.ErrCommunityInvalid
|
|
}
|
|
if !req.Deleted && !validVisibility(req.Visibility) {
|
|
return domain.CommunityTogglePeerLinkResult{}, domain.ErrCommunityPeerInvalid
|
|
}
|
|
req.ActorUserID = userID
|
|
return s.communities.ToggleCommunityPeerLink(ctx, req)
|
|
}
|
|
|
|
func (s *Service) SetCollapsed(ctx context.Context, userID, communityID int64, collapsed bool) (domain.CommunityView, bool, error) {
|
|
if s == nil || s.communities == nil || userID == 0 || communityID == 0 {
|
|
return domain.CommunityView{}, false, domain.ErrCommunityInvalid
|
|
}
|
|
return s.communities.SetCommunityCollapsed(ctx, userID, communityID, collapsed)
|
|
}
|
|
|
|
func (s *Service) ListPeerLinkRequests(ctx context.Context, userID, communityID int64, offset string, limit int) (domain.CommunityPeerLinkRequestPage, error) {
|
|
if s == nil || s.communities == nil || userID == 0 || communityID == 0 {
|
|
return domain.CommunityPeerLinkRequestPage{}, domain.ErrCommunityInvalid
|
|
}
|
|
if limit <= 0 || limit > domain.MaxCommunityLinkRequests {
|
|
limit = domain.MaxCommunityLinkRequests
|
|
}
|
|
return s.communities.ListCommunityPeerLinkRequests(ctx, userID, communityID, offset, limit)
|
|
}
|
|
|
|
func (s *Service) DecidePeerLinkRequest(ctx context.Context, userID, communityID int64, peer domain.Peer, reject bool, date int) (domain.CommunityTogglePeerLinkResult, error) {
|
|
if s == nil || s.communities == nil || userID == 0 || communityID == 0 || !validPeer(peer) {
|
|
return domain.CommunityTogglePeerLinkResult{}, domain.ErrCommunityInvalid
|
|
}
|
|
return s.communities.DecideCommunityPeerLinkRequest(ctx, userID, communityID, peer, reject, date)
|
|
}
|
|
|
|
func (s *Service) DecideAllPeerLinkRequests(ctx context.Context, userID, communityID int64, reject bool, date int) ([]domain.CommunityTogglePeerLinkResult, error) {
|
|
if s == nil || s.communities == nil || userID == 0 || communityID == 0 {
|
|
return nil, domain.ErrCommunityInvalid
|
|
}
|
|
return s.communities.DecideAllCommunityPeerLinkRequests(ctx, userID, communityID, reject, date)
|
|
}
|
|
|
|
func (s *Service) ToggleParticipantBanned(ctx context.Context, userID, communityID, participantUserID int64, unban bool, date int) (domain.CommunityParticipantBanResult, error) {
|
|
if s == nil || s.communities == nil || userID == 0 || communityID == 0 || participantUserID == 0 {
|
|
return domain.CommunityParticipantBanResult{}, domain.ErrCommunityInvalid
|
|
}
|
|
return s.communities.ToggleCommunityParticipantBanned(ctx, userID, communityID, participantUserID, unban, date)
|
|
}
|
|
|
|
func (s *Service) ParticipantJoinedChats(ctx context.Context, userID, communityID, participantUserID int64) (domain.CommunityParticipantJoinedChats, error) {
|
|
if s == nil || s.communities == nil || userID == 0 || communityID == 0 || participantUserID == 0 {
|
|
return domain.CommunityParticipantJoinedChats{}, domain.ErrCommunityInvalid
|
|
}
|
|
return s.communities.GetCommunityParticipantJoinedChats(ctx, userID, communityID, participantUserID)
|
|
}
|
|
|
|
func (s *Service) Participants(ctx context.Context, userID, communityID int64, filter domain.ChannelParticipantsFilter, offset, limit int) (domain.CommunityParticipantList, error) {
|
|
if s == nil || s.communities == nil || userID == 0 || communityID == 0 {
|
|
return domain.CommunityParticipantList{}, domain.ErrCommunityInvalid
|
|
}
|
|
if offset < 0 {
|
|
offset = 0
|
|
}
|
|
if offset > domain.MaxChannelParticipantsOffset {
|
|
offset = domain.MaxChannelParticipantsOffset
|
|
}
|
|
if limit <= 0 || limit > domain.MaxCommunityParticipants {
|
|
limit = domain.MaxCommunityParticipants
|
|
}
|
|
return s.communities.ListCommunityParticipants(ctx, userID, communityID, filter, offset, limit)
|
|
}
|
|
|
|
func (s *Service) EditTitle(ctx context.Context, userID, communityID int64, title string) (domain.CommunityView, bool, error) {
|
|
title = strings.TrimSpace(title)
|
|
if title == "" || utf8.RuneCountInString(title) > domain.MaxCommunityTitleRunes {
|
|
return domain.CommunityView{}, false, domain.ErrChannelTitleInvalid
|
|
}
|
|
return s.communities.EditCommunityTitle(ctx, userID, communityID, title)
|
|
}
|
|
|
|
func (s *Service) EditAbout(ctx context.Context, userID, communityID int64, about string) (domain.CommunityView, bool, error) {
|
|
about = strings.TrimSpace(about)
|
|
if utf8.RuneCountInString(about) > domain.MaxCommunityAboutRunes {
|
|
return domain.CommunityView{}, false, domain.ErrAboutTooLong
|
|
}
|
|
return s.communities.EditCommunityAbout(ctx, userID, communityID, about)
|
|
}
|
|
|
|
func (s *Service) EditAdmin(ctx context.Context, userID int64, req domain.CommunityEditAdminRequest) (domain.CommunityView, bool, error) {
|
|
if req.CommunityID == 0 || req.UserID == 0 || userID == 0 {
|
|
return domain.CommunityView{}, false, domain.ErrCommunityInvalid
|
|
}
|
|
req.ActorUserID = userID
|
|
return s.communities.EditCommunityAdmin(ctx, req)
|
|
}
|
|
|
|
func (s *Service) EditDefaultBannedRights(ctx context.Context, userID, communityID int64, rights domain.ChannelBannedRights) (domain.CommunityView, bool, error) {
|
|
return s.communities.EditCommunityDefaultBannedRights(ctx, userID, communityID, rights)
|
|
}
|
|
|
|
func (s *Service) SetPhoto(ctx context.Context, userID, communityID int64, photo *domain.Photo, date int) (domain.CommunityView, bool, error) {
|
|
return s.communities.SetCommunityPhoto(ctx, userID, communityID, photo, date)
|
|
}
|
|
|
|
func (s *Service) Delete(ctx context.Context, userID, communityID int64, date int) (domain.CommunityView, []domain.Peer, error) {
|
|
return s.communities.DeleteCommunity(ctx, userID, communityID, date)
|
|
}
|
|
|
|
func (s *Service) SetPinned(ctx context.Context, userID, communityID int64, pinned bool) (bool, error) {
|
|
return s.communities.SetCommunityPinned(ctx, userID, communityID, pinned)
|
|
}
|
|
|
|
func (s *Service) ReorderPinned(ctx context.Context, userID int64, order []domain.Peer, force bool) (bool, error) {
|
|
return s.communities.ReorderCommunityPinned(ctx, userID, order, force)
|
|
}
|
|
|
|
func (s *Service) SearchScope(ctx context.Context, userID, communityID int64) (domain.CommunitySearchScope, error) {
|
|
return s.communities.CommunitySearchScope(ctx, userID, communityID)
|
|
}
|