veza/veza-backend-api/internal/websocket/chat/permissions.go
senke eb2862092d
Some checks failed
Backend API CI / test-unit (push) Failing after 0s
Backend API CI / test-integration (push) Failing after 0s
Frontend CI / test (push) Failing after 0s
Storybook Audit / Build & audit Storybook (push) Failing after 0s
feat(v0.10.6): Livestreaming basique F471-F476
- Backend: callbacks on_publish/on_publish_done, UpdateStreamURL, GetByStreamKey
- Nginx-RTMP: config infra, docker-compose service (profil live)
- Frontend: stream_url dans LiveStream, HLS.js dans LiveViewPlayer, état Stream terminé
- Chat: rate limit send_live_message 1 msg/3s pour rooms live_streams
- Env: RTMP_CALLBACK_SECRET, STREAM_HLS_BASE_URL, NGINX_RTMP_HOST
- Roadmap v0.10.6 marquée DONE
2026-03-10 10:21:57 +01:00

104 lines
2.7 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
}
// IsLiveRoom returns true if roomID is a live_streams.id (F474).
func (p *PermissionService) IsLiveRoom(ctx context.Context, roomID uuid.UUID) bool {
var count int64
if err := p.db.WithContext(ctx).
Table("live_streams").
Where("id = ?", roomID).
Count(&count).Error; err != nil {
return false
}
return count > 0
}
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"
}