mirror of https://github.com/synctv-org/synctv
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
5.1 KiB
Go
187 lines
5.1 KiB
Go
package db
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/synctv-org/synctv/internal/model"
|
|
"github.com/zijiren233/stream"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
const (
|
|
ErrRoomNotFound = "room"
|
|
)
|
|
|
|
type CreateRoomConfig func(r *model.Room)
|
|
|
|
func WithSetting(setting *model.RoomSettings) CreateRoomConfig {
|
|
return func(r *model.Room) {
|
|
r.Settings = setting
|
|
}
|
|
}
|
|
|
|
func WithCreator(creator *model.User) CreateRoomConfig {
|
|
return func(r *model.Room) {
|
|
r.CreatorID = creator.ID
|
|
r.RoomMembers = []*model.RoomMember{
|
|
{
|
|
UserID: creator.ID,
|
|
Status: model.RoomMemberStatusActive,
|
|
Role: model.RoomMemberRoleCreator,
|
|
Permissions: model.AllPermissions,
|
|
AdminPermissions: model.AllAdminPermissions,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
func WithRelations(relations []*model.RoomMember) CreateRoomConfig {
|
|
return func(r *model.Room) {
|
|
r.RoomMembers = append(r.RoomMembers, relations...)
|
|
}
|
|
}
|
|
|
|
func WithStatus(status model.RoomStatus) CreateRoomConfig {
|
|
return func(r *model.Room) {
|
|
r.Status = status
|
|
}
|
|
}
|
|
|
|
func WithSettingHidden(hidden bool) CreateRoomConfig {
|
|
return func(r *model.Room) {
|
|
if r.Settings == nil {
|
|
r.Settings = model.DefaultRoomSettings()
|
|
}
|
|
r.Settings.Hidden = hidden
|
|
}
|
|
}
|
|
|
|
// if maxCount is 0, it will be ignored
|
|
func CreateRoom(name, password string, maxCount int64, conf ...CreateRoomConfig) (*model.Room, error) {
|
|
r := &model.Room{
|
|
Name: name,
|
|
Settings: model.DefaultRoomSettings(),
|
|
}
|
|
for _, c := range conf {
|
|
c(r)
|
|
}
|
|
if password != "" {
|
|
hashedPassword, err := bcrypt.GenerateFromPassword(stream.StringToBytes(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to hash password: %w", err)
|
|
}
|
|
r.HashedPassword = hashedPassword
|
|
}
|
|
|
|
err := Transactional(func(tx *gorm.DB) error {
|
|
if maxCount > 0 {
|
|
var count int64
|
|
if err := tx.Model(&model.Room{}).Where("creator_id = ?", r.CreatorID).Count(&count).Error; err != nil {
|
|
return fmt.Errorf("failed to count rooms: %w", err)
|
|
}
|
|
if count >= maxCount {
|
|
return errors.New("room count exceeds limit")
|
|
}
|
|
}
|
|
if err := tx.Create(r).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrDuplicatedKey) {
|
|
return errors.New("room already exists")
|
|
}
|
|
return fmt.Errorf("failed to create room: %w", err)
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
func GetRoomByID(id string) (*model.Room, error) {
|
|
if len(id) != 32 {
|
|
return nil, errors.New("room id is not 32 bit")
|
|
}
|
|
var r model.Room
|
|
err := db.Where("id = ?", id).First(&r).Error
|
|
return &r, HandleNotFound(err, ErrRoomNotFound)
|
|
}
|
|
|
|
func CreateOrLoadRoomSettings(roomID string) (*model.RoomSettings, error) {
|
|
var rs model.RoomSettings
|
|
err := db.Where(model.RoomSettings{ID: roomID}).Attrs(model.DefaultRoomSettings()).FirstOrCreate(&rs).Error
|
|
return &rs, err
|
|
}
|
|
|
|
func SaveRoomSettings(roomID string, settings *model.RoomSettings) error {
|
|
settings.ID = roomID
|
|
return HandleNotFound(db.Save(settings).Error, "room settings")
|
|
}
|
|
|
|
func UpdateRoomSettings(roomID string, settings map[string]interface{}) (*model.RoomSettings, error) {
|
|
var rs model.RoomSettings
|
|
err := db.Model(&model.RoomSettings{ID: roomID}).
|
|
Clauses(clause.Returning{}).
|
|
Updates(settings).
|
|
First(&rs).Error
|
|
return &rs, HandleNotFound(err, "room settings")
|
|
}
|
|
|
|
func DeleteRoomByID(roomID string) error {
|
|
result := db.Unscoped().Select(clause.Associations).Delete(&model.Room{ID: roomID})
|
|
return HandleUpdateResult(result, ErrRoomNotFound)
|
|
}
|
|
|
|
func SetRoomPassword(roomID, password string) error {
|
|
var hashedPassword []byte
|
|
var err error
|
|
if password != "" {
|
|
hashedPassword, err = bcrypt.GenerateFromPassword(stream.StringToBytes(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to hash password: %w", err)
|
|
}
|
|
}
|
|
return SetRoomHashedPassword(roomID, hashedPassword)
|
|
}
|
|
|
|
func SetRoomHashedPassword(roomID string, hashedPassword []byte) error {
|
|
result := db.Model(&model.Room{}).Where("id = ?", roomID).Update("hashed_password", hashedPassword)
|
|
return HandleUpdateResult(result, ErrRoomNotFound)
|
|
}
|
|
|
|
func GetAllRooms(scopes ...func(*gorm.DB) *gorm.DB) ([]*model.Room, error) {
|
|
var rooms []*model.Room
|
|
err := db.Scopes(scopes...).Find(&rooms).Error
|
|
return rooms, err
|
|
}
|
|
|
|
func GetAllRoomsCount(scopes ...func(*gorm.DB) *gorm.DB) (int64, error) {
|
|
var count int64
|
|
err := db.Model(&model.Room{}).Scopes(scopes...).Count(&count).Error
|
|
return count, err
|
|
}
|
|
|
|
func GetAllRoomsAndCreator(scopes ...func(*gorm.DB) *gorm.DB) ([]*model.Room, error) {
|
|
var rooms []*model.Room
|
|
err := db.Preload("Creator").Scopes(scopes...).Find(&rooms).Error
|
|
return rooms, err
|
|
}
|
|
|
|
func GetAllRoomsByUserID(userID string) ([]*model.Room, error) {
|
|
var rooms []*model.Room
|
|
err := db.Where("creator_id = ?", userID).Find(&rooms).Error
|
|
return rooms, err
|
|
}
|
|
|
|
func SetRoomStatus(roomID string, status model.RoomStatus) error {
|
|
result := db.Model(&model.Room{}).Where("id = ?", roomID).Update("status", status)
|
|
return HandleUpdateResult(result, ErrRoomNotFound)
|
|
}
|
|
|
|
func SetRoomStatusByCreator(userID string, status model.RoomStatus) error {
|
|
result := db.Model(&model.Room{}).Where("creator_id = ?", userID).Update("status", status)
|
|
return HandleUpdateResult(result, ErrRoomNotFound)
|
|
}
|