- F481: Co-listening sessions (WebSocket sync, ListenTogether page) - F482: Stem sharing (upload/list/download wav,aiff,flac) - F483: Collaborative rooms (type collaborative, max 10, invite-only) - Roadmap: v0.10.7 → DONE
151 lines
5 KiB
Go
151 lines
5 KiB
Go
package repositories
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"veza-backend-api/internal/models"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// RoomRepository gère les opérations de base de données pour les rooms
|
|
type RoomRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewRoomRepository crée une nouvelle instance de RoomRepository
|
|
func NewRoomRepository(db *gorm.DB) *RoomRepository {
|
|
return &RoomRepository{db: db}
|
|
}
|
|
|
|
// Create crée une nouvelle room
|
|
func (r *RoomRepository) Create(ctx context.Context, room *models.Room) error {
|
|
return r.db.WithContext(ctx).Create(room).Error
|
|
}
|
|
|
|
// GetByID récupère une room par son ID
|
|
func (r *RoomRepository) GetByID(ctx context.Context, id uuid.UUID) (*models.Room, error) {
|
|
var room models.Room
|
|
err := r.db.WithContext(ctx).
|
|
Preload("Members").
|
|
Preload("Messages").
|
|
First(&room, "id = ?", id).Error // Use explicit WHERE clause for UUID
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &room, nil
|
|
}
|
|
|
|
// GetByUserID récupère toutes les rooms d'un utilisateur
|
|
// MIGRATION UUID: userID migré vers uuid.UUID
|
|
func (r *RoomRepository) GetByUserID(ctx context.Context, userID uuid.UUID) ([]*models.Room, error) {
|
|
var rooms []*models.Room
|
|
// Note: RoomMember model doesn't have DeletedAt field, so we don't check for deleted_at
|
|
// Also, Preload("Members") would try to add deleted_at IS NULL which doesn't exist for RoomMember
|
|
// So we load members separately or use Unscoped() to avoid the deleted_at check
|
|
err := r.db.WithContext(ctx).
|
|
Joins("JOIN room_members ON rooms.id = room_members.room_id").
|
|
Where("room_members.user_id = ?", userID).
|
|
Preload("Members", func(db *gorm.DB) *gorm.DB {
|
|
// Don't add deleted_at condition since RoomMember doesn't have DeletedAt
|
|
return db
|
|
}).
|
|
Find(&rooms).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return rooms, nil
|
|
}
|
|
|
|
// Update met à jour une room
|
|
func (r *RoomRepository) Update(ctx context.Context, room *models.Room) error {
|
|
return r.db.WithContext(ctx).Save(room).Error
|
|
}
|
|
|
|
// Delete supprime une room (soft delete)
|
|
func (r *RoomRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
|
return r.db.WithContext(ctx).Delete(&models.Room{}, "id = ?", id).Error // Use explicit WHERE clause for UUID
|
|
}
|
|
|
|
// AddMember ajoute un membre à une room
|
|
func (r *RoomRepository) AddMember(ctx context.Context, member *models.RoomMember) error {
|
|
return r.db.WithContext(ctx).Create(member).Error
|
|
}
|
|
|
|
// RemoveMember retire un membre d'une room
|
|
// MIGRATION UUID: userID migré vers uuid.UUID
|
|
func (r *RoomRepository) RemoveMember(ctx context.Context, roomID uuid.UUID, userID uuid.UUID) error {
|
|
return r.db.WithContext(ctx).
|
|
Where("room_id = ? AND user_id = ?", roomID, userID).
|
|
Delete(&models.RoomMember{}).Error
|
|
}
|
|
|
|
// GetMembersByRoomID récupère tous les membres d'une room
|
|
func (r *RoomRepository) GetMembersByRoomID(ctx context.Context, roomID uuid.UUID) ([]*models.RoomMember, error) {
|
|
var members []*models.RoomMember
|
|
err := r.db.WithContext(ctx).
|
|
Where("room_id = ?", roomID).
|
|
Preload("User").
|
|
Find(&members).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return members, nil
|
|
}
|
|
|
|
// CountMembers returns the number of members in a room
|
|
func (r *RoomRepository) CountMembers(ctx context.Context, roomID uuid.UUID) (int64, error) {
|
|
var count int64
|
|
err := r.db.WithContext(ctx).Model(&models.RoomMember{}).
|
|
Where("room_id = ?", roomID).
|
|
Count(&count).Error
|
|
return count, err
|
|
}
|
|
|
|
// GetMemberRole returns the role of a user in a room, or empty if not a member
|
|
func (r *RoomRepository) GetMemberRole(ctx context.Context, roomID uuid.UUID, userID uuid.UUID) (string, error) {
|
|
var m models.RoomMember
|
|
err := r.db.WithContext(ctx).
|
|
Where("room_id = ? AND user_id = ?", roomID, userID).
|
|
First(&m).Error
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return "", nil
|
|
}
|
|
return "", err
|
|
}
|
|
return m.Role, nil
|
|
}
|
|
|
|
// CreateRoomInvitation creates a room invitation
|
|
func (r *RoomRepository) CreateRoomInvitation(ctx context.Context, inv *models.RoomInvitation) error {
|
|
return r.db.WithContext(ctx).Create(inv).Error
|
|
}
|
|
|
|
// GetRoomInvitationByToken returns a pending invitation by token
|
|
func (r *RoomRepository) GetRoomInvitationByToken(ctx context.Context, token uuid.UUID) (*models.RoomInvitation, error) {
|
|
var inv models.RoomInvitation
|
|
err := r.db.WithContext(ctx).
|
|
Where("token = ? AND status = ? AND expires_at > ?", token, "pending", time.Now()).
|
|
First(&inv).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &inv, nil
|
|
}
|
|
|
|
// UpdateRoomInvitationStatus updates invitation status
|
|
func (r *RoomRepository) UpdateRoomInvitationStatus(ctx context.Context, id uuid.UUID, status string) error {
|
|
return r.db.WithContext(ctx).Model(&models.RoomInvitation{}).
|
|
Where("id = ?", id).Update("status", status).Error
|
|
}
|
|
|
|
// UpdateMemberRole updates the role of a room member (v0.9.7)
|
|
func (r *RoomRepository) UpdateMemberRole(ctx context.Context, roomID, userID uuid.UUID, role string) error {
|
|
return r.db.WithContext(ctx).Model(&models.RoomMember{}).
|
|
Where("room_id = ? AND user_id = ?", roomID, userID).
|
|
Update("role", role).Error
|
|
}
|