diff --git a/internal/db/movie.go b/internal/db/movie.go index adb7c19..1cb6c79 100644 --- a/internal/db/movie.go +++ b/internal/db/movie.go @@ -13,6 +13,10 @@ func CreateMovie(movie *model.Movie) error { return db.Create(movie).Error } +func CreateMovies(movies []*model.Movie) error { + return db.Create(movies).Error +} + func GetAllMoviesByRoomID(roomID string) []*model.Movie { movies := []*model.Movie{} db.Where("room_id = ?", roomID).Order("position ASC").Find(&movies) diff --git a/internal/db/relation.go b/internal/db/relation.go index 6fdc43f..6567129 100644 --- a/internal/db/relation.go +++ b/internal/db/relation.go @@ -7,37 +7,52 @@ import ( "gorm.io/gorm" ) -func GetRoomUserRelation(roomID, userID string) (*model.RoomUserRelation, error) { +type CreateRoomUserRelationConfig func(r *model.RoomUserRelation) + +func WithRoomUserRelationStatus(status model.RoomUserStatus) CreateRoomUserRelationConfig { + return func(r *model.RoomUserRelation) { + r.Status = status + } +} + +func WithRoomUserRelationPermissions(permissions model.RoomUserPermission) CreateRoomUserRelationConfig { + return func(r *model.RoomUserRelation) { + r.Permissions = permissions + } +} + +func FirstOrCreateRoomUserRelation(roomID, userID string, conf ...CreateRoomUserRelationConfig) (*model.RoomUserRelation, error) { roomUserRelation := &model.RoomUserRelation{} - err := db.Where("room_id = ? AND user_id = ?", roomID, userID).Attrs(&model.RoomUserRelation{ + d := &model.RoomUserRelation{ RoomID: roomID, UserID: userID, - Role: model.RoomRoleUser, Permissions: model.DefaultPermissions, - }).FirstOrInit(roomUserRelation).Error + } + for _, c := range conf { + c(d) + } + err := db.Where("room_id = ? AND user_id = ?", roomID, userID).Attrs(d).FirstOrCreate(roomUserRelation).Error return roomUserRelation, err } -func CreateRoomUserRelation(roomID, userID string, role model.RoomRole, permissions model.Permission) (*model.RoomUserRelation, error) { - roomUserRelation := &model.RoomUserRelation{ - RoomID: roomID, - UserID: userID, - Role: role, - Permissions: permissions, +func GetRoomUserRelation(roomID, userID string) (*model.RoomUserRelation, error) { + roomUserRelation := &model.RoomUserRelation{} + err := db.Where("room_id = ? AND user_id = ?", roomID, userID).First(roomUserRelation).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + return roomUserRelation, errors.New("room or user not found") } - err := db.Create(roomUserRelation).Error return roomUserRelation, err } -func SetUserRole(roomID string, userID string, role model.RoomRole) error { - err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("role", role).Error +func SetRoomUserStatus(roomID string, userID string, status model.RoomUserStatus) error { + err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("status", status).Error if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("room or user not found") } return err } -func SetUserPermission(roomID string, userID string, permission model.Permission) error { +func SetUserPermission(roomID string, userID string, permission model.RoomUserPermission) error { err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", permission).Error if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("room or user not found") @@ -45,7 +60,7 @@ func SetUserPermission(roomID string, userID string, permission model.Permission return err } -func AddUserPermission(roomID string, userID string, permission model.Permission) error { +func AddUserPermission(roomID string, userID string, permission model.RoomUserPermission) error { err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", db.Raw("permissions | ?", permission)).Error if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("room or user not found") @@ -53,18 +68,10 @@ func AddUserPermission(roomID string, userID string, permission model.Permission return err } -func RemoveUserPermission(roomID string, userID string, permission model.Permission) error { +func RemoveUserPermission(roomID string, userID string, permission model.RoomUserPermission) error { err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", db.Raw("permissions & ?", ^permission)).Error if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("room or user not found") } return err } - -func DeleteUserPermission(roomID string, userID string) error { - err := db.Unscoped().Where("room_id = ? AND user_id = ?", roomID, userID).Delete(&model.RoomUserRelation{}).Error - if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { - return errors.New("room or user not found") - } - return err -} diff --git a/internal/db/room.go b/internal/db/room.go index 2a20d58..4e2dd19 100644 --- a/internal/db/room.go +++ b/internal/db/room.go @@ -11,7 +11,7 @@ import ( type CreateRoomConfig func(r *model.Room) -func WithSetting(setting model.Settings) CreateRoomConfig { +func WithSetting(setting model.RoomSettings) CreateRoomConfig { return func(r *model.Room) { r.Settings = setting } @@ -23,8 +23,8 @@ func WithCreator(creator *model.User) CreateRoomConfig { r.GroupUserRelations = []model.RoomUserRelation{ { UserID: creator.ID, - Role: model.RoomRoleCreator, - Permissions: model.AllPermissions, + Status: model.RoomRoleActive, + Permissions: model.PermissionAll, }, } } @@ -77,7 +77,7 @@ func GetRoomByID(id string) (*model.Room, error) { return r, err } -func ChangeRoomSetting(roomID string, setting model.Settings) error { +func SaveRoomSettings(roomID string, setting model.RoomSettings) error { err := db.Model(&model.Room{}).Where("id = ?", roomID).Update("setting", setting).Error if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("room not found") @@ -85,26 +85,6 @@ func ChangeRoomSetting(roomID string, setting model.Settings) error { return err } -func ChangeUserPermission(roomID, userID string, permission model.Permission) error { - err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", permission).Error - if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { - return errors.New("room or user not found") - } - return err -} - -func HasPermission(roomID, userID string, permission model.Permission) (bool, error) { - ur := &model.RoomUserRelation{} - err := db.Where("room_id = ? AND user_id = ?", roomID, userID).First(ur).Error - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - err = errors.New("room or user not found") - } - return false, err - } - return ur.Permissions.Has(permission), nil -} - func DeleteRoomByID(roomID string) error { err := db.Unscoped().Where("id = ?", roomID).Delete(&model.Room{}).Error if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { diff --git a/internal/db/user.go b/internal/db/user.go index 4f983c4..58a1e81 100644 --- a/internal/db/user.go +++ b/internal/db/user.go @@ -72,20 +72,6 @@ func GetProviderUserID(p provider.OAuth2Provider, puid uint) (string, error) { return userProvider.UserID, nil } -func AddUserToRoom(userID, roomID string, role model.RoomRole, permission model.Permission) error { - ur := &model.RoomUserRelation{ - UserID: userID, - RoomID: roomID, - Role: role, - Permissions: permission, - } - err := db.Create(ur).Error - if err != nil && errors.Is(err, gorm.ErrDuplicatedKey) { - return errors.New("user already exists in room") - } - return err -} - func GetUserByUsername(username string) (*model.User, error) { u := &model.User{} err := db.Where("username = ?", username).First(u).Error diff --git a/internal/model/movie.go b/internal/model/movie.go index b5d914c..a60247c 100644 --- a/internal/model/movie.go +++ b/internal/model/movie.go @@ -14,7 +14,7 @@ import ( ) type Movie struct { - ID string `gorm:"primaryKey;type:varchar(36)" json:"id"` + ID string `gorm:"primaryKey;type:varchar(32)" json:"id"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` Position uint `gorm:"not null" json:"-"` diff --git a/internal/model/relation.go b/internal/model/relation.go index 93709ec..33c89cc 100644 --- a/internal/model/relation.go +++ b/internal/model/relation.go @@ -1,56 +1,64 @@ package model -import "time" +import ( + "errors" + "time" +) -type RoomRole uint32 +type RoomUserStatus uint const ( - RoomRoleBanned RoomRole = iota + 1 - RoomRoleUser - RoomRoleCreator + RoomRoleBanned RoomUserStatus = iota + 1 + RoomRolePending + RoomRoleActive ) -type Permission uint32 +func (r RoomUserStatus) String() string { + switch r { + case RoomRoleBanned: + return "banned" + case RoomRolePending: + return "pending" + case RoomRoleActive: + return "active" + default: + return "unknown" + } +} + +type RoomUserPermission uint32 const ( - CanRenameRoom Permission = 1 << iota - CanSetAdmin - CanSetRoomPassword - CanSetRoomSetting - CanSetUserPermission - CanSetUserPassword - CanCreateUserPublishKey - CanEditUserMovies - CanDeleteUserMovies - CanCreateMovie - CanChangeCurrentMovie - CanChangeMovieStatus - CanDeleteRoom - AllPermissions Permission = 0xffffffff + PermissionAll RoomUserPermission = 0xffffffff + PermissionEditRoom RoomUserPermission = 1 << iota + PermissionEditUser + PermissionCreateMovie + PermissionEditCurrent + PermissionSendChat ) const ( - DefaultPermissions = CanCreateMovie | CanChangeCurrentMovie | CanChangeMovieStatus + DefaultPermissions = PermissionCreateMovie | PermissionEditCurrent | PermissionSendChat ) -func (p Permission) Has(permission Permission) bool { +func (p RoomUserPermission) Has(permission RoomUserPermission) bool { return p&permission == permission } type RoomUserRelation struct { CreatedAt time.Time UpdatedAt time.Time - UserID string `gorm:"not null;primarykey"` - RoomID string `gorm:"not null;primarykey"` - Role RoomRole `gorm:"not null"` - Permissions Permission + UserID string `gorm:"not null;primarykey"` + RoomID string `gorm:"not null;primarykey"` + Status RoomUserStatus `gorm:"not null;default:2"` + Permissions RoomUserPermission } -func (r *RoomUserRelation) HasPermission(permission Permission) bool { - switch r.Role { - case RoomRoleCreator: - return true - case RoomRoleUser: +var ErrNoPermission = errors.New("no permission") + +func (r *RoomUserRelation) HasPermission(permission RoomUserPermission) bool { + switch r.Status { + case RoomRoleActive: return r.Permissions.Has(permission) default: return false diff --git a/internal/model/room.go b/internal/model/room.go index 82a0f01..e259672 100644 --- a/internal/model/room.go +++ b/internal/model/room.go @@ -9,22 +9,35 @@ import ( "gorm.io/gorm" ) -type RoomStatus string +type RoomStatus uint const ( - RoomStatusBanned RoomStatus = "banned" - RoomStatusPending RoomStatus = "pending" - RoomStatusActive RoomStatus = "active" + RoomStatusBanned RoomStatus = 1 + RoomStatusPending RoomStatus = 2 + RoomStatusActive RoomStatus = 3 ) +func (r RoomStatus) String() string { + switch r { + case RoomStatusBanned: + return "banned" + case RoomStatusPending: + return "pending" + case RoomStatusActive: + return "active" + default: + return "unknown" + } +} + type Room struct { - ID string `gorm:"not null;primaryKey;type:varchar(36)" json:"id"` + ID string `gorm:"not null;primaryKey;type:varchar(32)" json:"id"` CreatedAt time.Time UpdatedAt time.Time - Status RoomStatus `gorm:"not null;default:pending"` - Name string `gorm:"not null;uniqueIndex"` - Settings Settings `gorm:"embedded;embeddedPrefix:settings_"` - CreatorID string `gorm:"index"` + Status RoomStatus `gorm:"not null;default:2"` + Name string `gorm:"not null;uniqueIndex"` + Settings RoomSettings `gorm:"embedded;embeddedPrefix:settings_"` + CreatorID string `gorm:"index"` HashedPassword []byte GroupUserRelations []RoomUserRelation `gorm:"foreignKey:RoomID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` Movies []Movie `gorm:"foreignKey:RoomID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` @@ -37,9 +50,14 @@ func (r *Room) BeforeCreate(tx *gorm.DB) error { return nil } -type Settings struct { - Hidden bool `json:"hidden"` - CanPushMovie bool `gorm:"default:true" json:"canPushMovie"` +type RoomSettings struct { + Hidden bool `json:"hidden"` + CanCreateMovie bool `gorm:"default:true" json:"canCreateMovie"` + CanEditCurrent bool `gorm:"default:true" json:"canEditCurrent"` + CanSendChat bool `gorm:"default:true" json:"canSendChat"` + DisableJoinNewUser bool `gorm:"default:false" json:"disableJoinNewUser"` + JoinNeedReview bool `gorm:"default:false" json:"joinNeedReview"` + UserDefaultPermissions RoomUserPermission `json:"userDefaultPermissions"` } func (r *Room) NeedPassword() bool { diff --git a/internal/model/user.go b/internal/model/user.go index 555d358..b0f50e7 100644 --- a/internal/model/user.go +++ b/internal/model/user.go @@ -9,23 +9,40 @@ import ( "gorm.io/gorm" ) -type Role string +type Role uint const ( - RoleBanned Role = "banned" - RolePending Role = "pending" - RoleUser Role = "user" - RoleAdmin Role = "admin" - RoleRoot Role = "root" + RoleBanned Role = 1 + RolePending Role = 2 + RoleUser Role = 3 + RoleAdmin Role = 4 + RoleRoot Role = 5 ) +func (r Role) String() string { + switch r { + case RoleBanned: + return "banned" + case RolePending: + return "pending" + case RoleUser: + return "user" + case RoleAdmin: + return "admin" + case RoleRoot: + return "root" + default: + return "unknown" + } +} + type User struct { - ID string `gorm:"primaryKey;type:varchar(36)" json:"id"` + ID string `gorm:"primaryKey;type:varchar(32)" json:"id"` CreatedAt time.Time UpdatedAt time.Time Providers []UserProvider `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` Username string `gorm:"not null;uniqueIndex"` - Role Role `gorm:"not null;default:pending"` + Role Role `gorm:"not null;default:2"` GroupUserRelations []RoomUserRelation `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` Rooms []Room `gorm:"foreignKey:CreatorID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` Movies []Movie `gorm:"foreignKey:CreatorID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL"` diff --git a/internal/op/movies.go b/internal/op/movies.go index 7348d5f..1a824f3 100644 --- a/internal/op/movies.go +++ b/internal/op/movies.go @@ -36,7 +36,7 @@ func (m *movies) Len() int { return m.list.Len() } -func (m *movies) Add(mo *model.Movie) error { +func (m *movies) AddMovie(mo *model.Movie) error { m.lock.Lock() defer m.lock.Unlock() m.init() @@ -60,6 +60,43 @@ func (m *movies) Add(mo *model.Movie) error { return nil } +func (m *movies) AddMovies(mos []*model.Movie) error { + m.lock.Lock() + defer m.lock.Unlock() + m.init() + inited := make([]*Movie, 0, len(mos)) + for _, mo := range mos { + mo.Position = uint(time.Now().UnixMilli()) + movie := &Movie{ + Movie: mo, + } + + err := movie.init() + if err != nil { + for _, movie := range inited { + movie.terminate() + } + return err + } + + inited = append(inited, movie) + } + + err := db.CreateMovies(mos) + if err != nil { + for _, movie := range inited { + movie.terminate() + } + return err + } + + for _, mo := range inited { + m.list.PushBack(mo) + } + + return nil +} + func (m *movies) GetChannel(id string) (*rtmps.Channel, error) { if id == "" { return nil, errors.New("channel name is nil") diff --git a/internal/op/room.go b/internal/op/room.go index 0c760a8..e40ac0e 100644 --- a/internal/op/room.go +++ b/internal/op/room.go @@ -75,15 +75,51 @@ func (r *Room) UpdateMovie(movieId string, movie model.BaseMovie) error { func (r *Room) AddMovie(m *model.Movie) error { m.RoomID = r.ID - return r.movies.Add(m) + return r.movies.AddMovie(m) } -func (r *Room) HasPermission(userID string, permission model.Permission) bool { - ur, err := db.GetRoomUserRelation(r.ID, userID) +func (r *Room) AddMovies(movies []*model.Movie) error { + for _, m := range movies { + m.RoomID = r.ID + } + return r.movies.AddMovies(movies) +} + +func (r *Room) HasPermission(userID string, permission model.RoomUserPermission) bool { + if r.CreatorID == userID { + return true + } + + rur, err := r.LoadOrCreateRoomUserRelation(userID) if err != nil { return false } - return ur.HasPermission(permission) + + return rur.HasPermission(permission) +} + +func (r *Room) LoadOrCreateRoomUserRelation(userID string) (*model.RoomUserRelation, error) { + var conf []db.CreateRoomUserRelationConfig + if r.Settings.JoinNeedReview { + conf = []db.CreateRoomUserRelationConfig{db.WithRoomUserRelationStatus(model.RoomRolePending)} + } else { + conf = []db.CreateRoomUserRelationConfig{db.WithRoomUserRelationStatus(model.RoomRoleActive)} + } + if r.Settings.UserDefaultPermissions != 0 { + conf = append(conf, db.WithRoomUserRelationPermissions(r.Settings.UserDefaultPermissions)) + } + return db.FirstOrCreateRoomUserRelation(r.ID, userID, conf...) +} + +func (r *Room) GetRoomUserRelation(userID string) (model.RoomUserPermission, error) { + if r.CreatorID == userID { + return model.PermissionAll, nil + } + ur, err := db.GetRoomUserRelation(r.ID, userID) + if err != nil { + return 0, err + } + return ur.Permissions, nil } func (r *Room) NeedPassword() bool { @@ -107,26 +143,22 @@ func (r *Room) SetPassword(password string) error { return db.SetRoomHashedPassword(r.ID, hashedPassword) } -func (r *Room) SetUserRole(userID string, role model.RoomRole) error { - return db.SetUserRole(r.ID, userID, role) +func (r *Room) SetUserStatus(userID string, status model.RoomUserStatus) error { + return db.SetRoomUserStatus(r.ID, userID, status) } -func (r *Room) SetUserPermission(userID string, permission model.Permission) error { +func (r *Room) SetUserPermission(userID string, permission model.RoomUserPermission) error { return db.SetUserPermission(r.ID, userID, permission) } -func (r *Room) AddUserPermission(userID string, permission model.Permission) error { +func (r *Room) AddUserPermission(userID string, permission model.RoomUserPermission) error { return db.AddUserPermission(r.ID, userID, permission) } -func (r *Room) RemoveUserPermission(userID string, permission model.Permission) error { +func (r *Room) RemoveUserPermission(userID string, permission model.RoomUserPermission) error { return db.RemoveUserPermission(r.ID, userID, permission) } -func (r *Room) DeleteUserPermission(userID string) error { - return db.DeleteUserPermission(r.ID, userID) -} - func (r *Room) GetMoviesCount() int { return r.movies.Len() } @@ -199,3 +231,12 @@ func (r *Room) SetRoomStatus(status model.RoomStatus) error { } return nil } + +func (r *Room) SetSettings(settings model.RoomSettings) error { + err := db.SaveRoomSettings(r.ID, settings) + if err != nil { + return err + } + r.Settings = settings + return nil +} diff --git a/internal/op/rooms.go b/internal/op/rooms.go index b1cc681..05e8a4d 100644 --- a/internal/op/rooms.go +++ b/internal/op/rooms.go @@ -66,15 +66,23 @@ func LoadOrInitRoom(room *model.Room) (*Room, error) { return i.Value(), nil } -func DeleteRoom(roomID string) error { +func DeleteRoomByID(roomID string) error { err := db.DeleteRoomByID(roomID) if err != nil { return err } - return CloseRoom(roomID) + return CloseRoomByID(roomID) } -func CloseRoom(roomID string) error { +func CompareAndDeleteRoom(room *Room) error { + err := CompareAndCloseRoom(room) + if err != nil { + return err + } + return db.DeleteRoomByID(room.ID) +} + +func CloseRoomByID(roomID string) error { r, loaded := roomCache.LoadAndDelete(roomID) if loaded { r.Value().close() diff --git a/internal/op/user.go b/internal/op/user.go index 582a270..aebae22 100644 --- a/internal/op/user.go +++ b/internal/op/user.go @@ -31,14 +31,28 @@ func (u *User) NewMovie(movie *model.BaseMovie) *model.Movie { } } +func (u *User) AddMovieToRoom(room *Room, movie *model.BaseMovie) error { + if !u.HasRoomPermission(room, model.PermissionCreateMovie) { + return model.ErrNoPermission + } + return room.AddMovie(u.NewMovie(movie)) +} + func (u *User) NewMovies(movies []*model.BaseMovie) []*model.Movie { - var ms = make([]*model.Movie, 0, len(movies)) + var ms = make([]*model.Movie, len(movies)) for i, m := range movies { ms[i] = u.NewMovie(m) } return ms } +func (u *User) AddMoviesToRoom(room *Room, movies []*model.BaseMovie) error { + if !u.HasRoomPermission(room, model.PermissionCreateMovie) { + return model.ErrNoPermission + } + return room.AddMovies(u.NewMovies(movies)) +} + func (u *User) IsRoot() bool { return u.Role == model.RoleRoot } @@ -55,29 +69,25 @@ func (u *User) IsPending() bool { return u.Role == model.RolePending } -func (u *User) HasPermission(roomID string, permission model.Permission) bool { +func (u *User) HasRoomPermission(room *Room, permission model.RoomUserPermission) bool { if u.IsAdmin() { return true } - ur, err := db.GetRoomUserRelation(roomID, u.ID) - if err != nil { - return false - } - return ur.HasPermission(permission) + return room.HasPermission(u.ID, permission) } -func (u *User) DeleteRoom(roomID string) error { - if !u.HasPermission(roomID, model.CanDeleteRoom) { - return errors.New("no permission") +func (u *User) DeleteRoom(room *Room) error { + if !u.HasRoomPermission(room, model.PermissionEditRoom) { + return model.ErrNoPermission } - return DeleteRoom(roomID) + return CompareAndDeleteRoom(room) } -func (u *User) SetRoomPassword(roomID, password string) error { - if !u.HasPermission(roomID, model.CanSetRoomPassword) { - return errors.New("no permission") +func (u *User) SetRoomPassword(room *Room, password string) error { + if !u.HasRoomPermission(room, model.PermissionEditRoom) { + return model.ErrNoPermission } - return SetRoomPassword(roomID, password) + return room.SetPassword(password) } func (u *User) SetRole(role model.Role) error { @@ -95,3 +105,21 @@ func (u *User) SetUsername(username string) error { u.Username = username return nil } + +func (u *User) UpdateMovie(room *Room, movieID string, movie model.BaseMovie) error { + m, err := room.GetMovieByID(movieID) + if err != nil { + return err + } + if m.CreatorID != u.ID && !u.HasRoomPermission(room, model.PermissionEditUser) { + return model.ErrNoPermission + } + return room.UpdateMovie(movieID, movie) +} + +func (u *User) SetRoomSetting(room *Room, setting model.RoomSettings) error { + if !u.HasRoomPermission(room, model.PermissionEditRoom) { + return model.ErrNoPermission + } + return room.SetSettings(setting) +} diff --git a/server/handlers/init.go b/server/handlers/init.go index 37436ac..7d65582 100644 --- a/server/handlers/init.go +++ b/server/handlers/init.go @@ -75,7 +75,9 @@ func Init(e *gin.Engine) { needAuthRoom.POST("/pwd", SetRoomPassword) - needAuthRoom.GET("/setting", RoomSetting) + needAuthRoom.GET("/settings", RoomSetting) + + needAuthRoom.POST("/settings", SetRoomSetting) } { diff --git a/server/handlers/movie.go b/server/handlers/movie.go index be009a9..b112bfa 100644 --- a/server/handlers/movie.go +++ b/server/handlers/movie.go @@ -175,10 +175,12 @@ func PushMovie(ctx *gin.Context) { return } - mi := user.NewMovie((*dbModel.BaseMovie)(&req)) - - err := room.AddMovie(mi) + err := user.AddMovieToRoom(room, (*dbModel.BaseMovie)(&req)) if err != nil { + if errors.Is(err, dbModel.ErrNoPermission) { + ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(err)) + return + } ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) return } @@ -206,24 +208,21 @@ func PushMovies(ctx *gin.Context) { return } - var ms []*dbModel.Movie = make([]*dbModel.Movie, len(req)) + var ms []*dbModel.BaseMovie = make([]*dbModel.BaseMovie, len(req)) for i, v := range req { m := (*dbModel.BaseMovie)(v) - err := m.Validate() - if err != nil { - ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) - return - } - ms[i] = user.NewMovie(m) + ms[i] = m } - for _, m := range ms { - err := room.AddMovie(m) - if err != nil { - ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) + err := user.AddMoviesToRoom(room, ms) + if err != nil { + if errors.Is(err, dbModel.ErrNoPermission) { + ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(err)) return } + ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) + return } if err := room.Broadcast(&op.ElementMessage{ @@ -254,7 +253,7 @@ func NewPublishKey(ctx *gin.Context) { return } - if !user.HasPermission(room.ID, dbModel.CanCreateUserPublishKey) && movie.CreatorID != user.ID { + if movie.CreatorID != user.ID && !user.HasRoomPermission(room, dbModel.PermissionEditUser) { ctx.AbortWithStatus(http.StatusForbidden) return } @@ -292,7 +291,7 @@ func EditMovie(ctx *gin.Context) { return } - if err := room.UpdateMovie(req.Id, dbModel.BaseMovie(req.PushMovieReq)); err != nil { + if err := user.UpdateMovie(room, req.Id, dbModel.BaseMovie(req.PushMovieReq)); err != nil { ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) return } diff --git a/server/handlers/room.go b/server/handlers/room.go index f36c3b4..56e8e56 100644 --- a/server/handlers/room.go +++ b/server/handlers/room.go @@ -202,7 +202,7 @@ func DeleteRoom(ctx *gin.Context) { room := ctx.MustGet("room").(*op.Room) user := ctx.MustGet("user").(*op.User) - if err := user.DeleteRoom(room.ID); err != nil { + if err := user.DeleteRoom(room); err != nil { ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(err)) return } @@ -220,7 +220,7 @@ func SetRoomPassword(ctx *gin.Context) { return } - if err := user.SetRoomPassword(room.ID, req.Password); err != nil { + if err := user.SetRoomPassword(room, req.Password); err != nil { ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(err)) return } @@ -241,8 +241,23 @@ func RoomSetting(ctx *gin.Context) { room := ctx.MustGet("room").(*op.Room) // user := ctx.MustGet("user").(*op.User) - ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{ - "hidden": room.Settings.Hidden, - "needPassword": room.NeedPassword(), - })) + ctx.JSON(http.StatusOK, model.NewApiDataResp(room.Settings)) +} + +func SetRoomSetting(ctx *gin.Context) { + room := ctx.MustGet("room").(*op.Room) + user := ctx.MustGet("user").(*op.User) + + req := model.SetRoomSettingReq{} + if err := model.Decode(ctx, &req); err != nil { + ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) + return + } + + if err := user.SetRoomSetting(room, dbModel.RoomSettings(req)); err != nil { + ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(err)) + return + } + + ctx.Status(http.StatusNoContent) } diff --git a/server/middlewares/auth.go b/server/middlewares/auth.go index a9fda12..8d15a0c 100644 --- a/server/middlewares/auth.go +++ b/server/middlewares/auth.go @@ -156,6 +156,14 @@ func NewAuthRoomToken(user *op.User, room *op.Room) (string, error) { if user.IsPending() { return "", errors.New("user is pending, need admin to approve") } + if room.Settings.DisableJoinNewUser { + if _, err := room.GetRoomUserRelation(user.ID); err != nil { + return "", errors.New("room is not allow new user to join") + } + } else if _, err := room.LoadOrCreateRoomUserRelation(user.ID); err != nil { + return "", err + } + t, err := time.ParseDuration(conf.Conf.Jwt.Expire) if err != nil { return "", err diff --git a/server/model/movie.go b/server/model/movie.go index e0ffee5..8af6c60 100644 --- a/server/model/movie.go +++ b/server/model/movie.go @@ -41,7 +41,7 @@ func (p *PushMovieReq) Validate() error { return ErrTypeTooLong } - return (*model.BaseMovie)(p).Validate() + return nil } type PushMoviesReq []*PushMovieReq diff --git a/server/model/room.go b/server/model/room.go index 9e28400..f9c422e 100644 --- a/server/model/room.go +++ b/server/model/room.go @@ -11,6 +11,7 @@ import ( "github.com/synctv-org/synctv/internal/settings" "github.com/gin-gonic/gin" + dbModel "github.com/synctv-org/synctv/internal/model" ) var ( @@ -40,9 +41,9 @@ func (f FormatEmptyPasswordError) Error() string { } type CreateRoomReq struct { - RoomName string `json:"roomName"` - Password string `json:"password"` - Setting model.Settings `json:"setting"` + RoomName string `json:"roomName"` + Password string `json:"password"` + Setting model.RoomSettings `json:"setting"` } func (c *CreateRoomReq) Decode(ctx *gin.Context) error { @@ -126,3 +127,13 @@ func (r *RoomIDReq) Validate() error { return nil } + +type SetRoomSettingReq dbModel.RoomSettings + +func (s *SetRoomSettingReq) Decode(ctx *gin.Context) error { + return json.NewDecoder(ctx.Request.Body).Decode(s) +} + +func (s *SetRoomSettingReq) Validate() error { + return nil +}