merged from gramsrv upstream
This commit is contained in:
parent
79c64ee916
commit
21a0856587
651 changed files with 54774 additions and 4590 deletions
121
internal/app/welcomemessages/service.go
Normal file
121
internal/app/welcomemessages/service.go
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
package welcomemessages
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store"
|
||||
)
|
||||
|
||||
type ChannelAccess interface {
|
||||
ResolveChannel(ctx context.Context, userID, channelID int64) (domain.ChannelView, error)
|
||||
}
|
||||
|
||||
type Option func(*Service)
|
||||
|
||||
func WithClock(now func() time.Time) Option {
|
||||
return func(s *Service) {
|
||||
if now != nil {
|
||||
s.now = now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
messages store.WelcomeMessageStore
|
||||
channels ChannelAccess
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
func NewService(messages store.WelcomeMessageStore, channels ChannelAccess, options ...Option) *Service {
|
||||
s := &Service{messages: messages, channels: channels, now: time.Now}
|
||||
for _, option := range options {
|
||||
if option != nil {
|
||||
option(s)
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Authorize is the cheap gate RPC uses before resolving upload/media/rich
|
||||
// content. Mutations call authorize again immediately before the store write so
|
||||
// a concurrent demotion cannot turn this preflight into a stale capability.
|
||||
func (s *Service) Authorize(ctx context.Context, userID int64, peer domain.Peer) error {
|
||||
return s.authorize(ctx, userID, peer)
|
||||
}
|
||||
|
||||
func (s *Service) Create(ctx context.Context, userID int64, peer domain.Peer, randomID int64, content domain.WelcomeMessageContent) (domain.WelcomeMessage, bool, error) {
|
||||
if err := s.authorize(ctx, userID, peer); err != nil {
|
||||
return domain.WelcomeMessage{}, false, err
|
||||
}
|
||||
if err := content.Validate(); err != nil {
|
||||
return domain.WelcomeMessage{}, false, err
|
||||
}
|
||||
fingerprint, err := domain.WelcomeCreateFingerprint(peer, userID, randomID, content)
|
||||
if err != nil {
|
||||
return domain.WelcomeMessage{}, false, domain.ErrWelcomeMessageInvalid
|
||||
}
|
||||
return s.messages.CreateWelcomeMessage(ctx, domain.CreateWelcomeMessageRequest{
|
||||
Peer: peer, CreatorUserID: userID, Date: int(s.now().Unix()), RandomID: randomID,
|
||||
Content: content, CreateFingerprint: fingerprint,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) Edit(ctx context.Context, userID int64, peer domain.Peer, id int, fields domain.WelcomeMessageEditFields) (domain.WelcomeMessage, error) {
|
||||
if err := s.authorize(ctx, userID, peer); err != nil {
|
||||
return domain.WelcomeMessage{}, err
|
||||
}
|
||||
return s.messages.EditWelcomeMessage(ctx, domain.EditWelcomeMessageRequest{
|
||||
Peer: peer, ID: id, EditDate: int(s.now().Unix()), Fields: fields,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) List(ctx context.Context, userID int64, peer domain.Peer, hash int64) (domain.WelcomeMessageList, error) {
|
||||
if err := s.authorize(ctx, userID, peer); err != nil {
|
||||
return domain.WelcomeMessageList{}, err
|
||||
}
|
||||
return s.messages.ListWelcomeMessages(ctx, peer, hash)
|
||||
}
|
||||
|
||||
func (s *Service) Delete(ctx context.Context, userID int64, peer domain.Peer, id int) (bool, error) {
|
||||
if err := s.authorize(ctx, userID, peer); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return s.messages.DeleteWelcomeMessage(ctx, peer, id)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteAll(ctx context.Context, userID int64, peer domain.Peer) (bool, error) {
|
||||
if err := s.authorize(ctx, userID, peer); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return s.messages.DeleteAllWelcomeMessages(ctx, peer)
|
||||
}
|
||||
|
||||
// HasAny is used only after the ordinary full-chat access check has succeeded.
|
||||
// It deliberately does not require manage_welcome_messages so non-admin members
|
||||
// receive the same has_welcome_messages projection as official clients.
|
||||
func (s *Service) HasAny(ctx context.Context, peer domain.Peer) (bool, error) {
|
||||
if s == nil || s.messages == nil || peer.Type != domain.PeerTypeChannel || peer.ID <= 0 {
|
||||
return false, domain.ErrWelcomeMessageInvalid
|
||||
}
|
||||
return s.messages.HasWelcomeMessages(ctx, peer)
|
||||
}
|
||||
|
||||
func (s *Service) authorize(ctx context.Context, userID int64, peer domain.Peer) error {
|
||||
if s == nil || s.messages == nil || s.channels == nil || userID <= 0 ||
|
||||
peer.Type != domain.PeerTypeChannel || peer.ID <= 0 {
|
||||
return domain.ErrWelcomeMessageInvalid
|
||||
}
|
||||
view, err := s.channels.ResolveChannel(ctx, userID, peer.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if view.Channel.Monoforum {
|
||||
return domain.ErrWelcomeMessagePeerInvalid
|
||||
}
|
||||
if !view.Self.CanManageWelcomeMessages() {
|
||||
return domain.ErrWelcomeMessageForbidden
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue