veza/veza-backend-api/internal/websocket/chat/permissions.go
senke 93666a3390 feat(v0.703): Go Live & Streaming Complet
- Backend: room creation for live streams, permissions CanJoin/CanSend/CanRead for stream rooms
- LiveViewChat: useLiveStreamChat hook, WebSocket connection, stream_id as room
- LiveViewPlayer: real-time viewer count via polling (5s)
- Media Session: seekbackward/seekforward handlers (10s step)
- GoLiveView.stories.tsx: Default, Loading, Error, StreamKeyVisible
- Docs: API_REFERENCE, CHANGELOG, PROJECT_STATE, FEATURE_STATUS, RETROSPECTIVE_V0703
- SCOPE_CONTROL, .cursorrules: update to v0.801
- Archive V0_703_RELEASE_SCOPE.md
2026-02-25 09:35:22 +01:00

92 lines
2.4 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 {
// GL3-01: Live stream chat — allow read when roomID is a live_streams.id (public)
var count int64
if err := p.db.WithContext(ctx).
Table("live_streams").
Where("id = ?", roomID).
Count(&count).Error; err == nil && count > 0 {
return true
}
_, isMember := p.getMembership(ctx, userID, roomID)
return isMember
}
func (p *PermissionService) CanSend(ctx context.Context, userID, roomID uuid.UUID) bool {
// GL3-01: Live stream chat — allow send when roomID is a live_streams.id (public)
var count int64
if err := p.db.WithContext(ctx).
Table("live_streams").
Where("id = ?", roomID).
Count(&count).Error; err == nil && count > 0 {
return true
}
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 {
// GL3-01: Live stream chat — allow join when roomID is a live_streams.id (public)
var count int64
if err := p.db.WithContext(ctx).
Table("live_streams").
Where("id = ?", roomID).
Count(&count).Error; err == nil && count > 0 {
return true
}
_, 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"
}