veza/veza-backend-api/internal/websocket/chat/permissions.go
senke 603eb06dae feat(chat): Sprint 3 -- message handlers, real-time features, permissions
- Implement full MessageHandler dispatch with all 18 incoming message types
- Add handler_messages.go: SendMessage, EditMessage, DeleteMessage with ownership checks
- Add handler_rooms.go: JoinConversation, LeaveConversation
- Add handler_history.go: FetchHistory (cursor-based), SearchMessages (ILIKE), SyncMessages
- Add handler_realtime.go: Typing, MarkAsRead, Delivered, AddReaction, RemoveReaction
- Add handler_calls.go: WebRTC signaling relay (CallOffer/Answer/ICE/Hangup/Reject)
- Add PermissionService: CanRead/CanSend/CanJoin/CanModerate based on room_members
- Add RateLimiter: per-user per-action sliding window (in-memory)
- Wire all dependencies in router.go setupChatWebSocket
2026-02-22 20:43:44 +01:00

68 lines
1.6 KiB
Go

package chat
import (
"context"
"github.com/google/uuid"
"go.uber.org/zap"
"gorm.io/gorm"
)
type PermissionService struct {
db *gorm.DB
logger *zap.Logger
}
func NewPermissionService(db *gorm.DB, logger *zap.Logger) *PermissionService {
if logger == nil {
logger = zap.NewNop()
}
return &PermissionService{
db: db,
logger: logger,
}
}
type roomMemberCheck struct {
Role string `gorm:"column:role"`
IsMuted bool `gorm:"column:is_muted"`
}
func (p *PermissionService) getMembership(ctx context.Context, userID, roomID uuid.UUID) (*roomMemberCheck, bool) {
var member roomMemberCheck
err := p.db.WithContext(ctx).
Table("room_members").
Select("role, is_muted").
Where("user_id = ? AND room_id = ?", userID, roomID).
First(&member).Error
if err != nil {
return nil, false
}
return &member, true
}
func (p *PermissionService) CanRead(ctx context.Context, userID, roomID uuid.UUID) bool {
_, isMember := p.getMembership(ctx, userID, roomID)
return isMember
}
func (p *PermissionService) CanSend(ctx context.Context, userID, roomID uuid.UUID) bool {
member, isMember := p.getMembership(ctx, userID, roomID)
if !isMember {
return false
}
return !member.IsMuted
}
func (p *PermissionService) CanJoin(ctx context.Context, userID, roomID uuid.UUID) bool {
_, isMember := p.getMembership(ctx, userID, roomID)
return isMember
}
func (p *PermissionService) CanModerate(ctx context.Context, userID, roomID uuid.UUID) bool {
member, isMember := p.getMembership(ctx, userID, roomID)
if !isMember {
return false
}
return member.Role == "admin" || member.Role == "moderator" || member.Role == "owner"
}