diff --git a/internal/db/room.go b/internal/db/room.go index 8af46a3..c505f8e 100644 --- a/internal/db/room.go +++ b/internal/db/room.go @@ -19,7 +19,7 @@ func WithSetting(setting model.Setting) CreateRoomConfig { func WithCreator(creator *model.User) CreateRoomConfig { return func(r *model.Room) { - r.Creator = *creator + r.CreatorID = creator.ID r.GroupUserRelations = []model.RoomUserRelation{ { UserID: creator.ID, @@ -174,3 +174,12 @@ func GetAllRoomsAndCreator() ([]*model.Room, error) { } return rooms, err } + +func GetAllRoomsByUserID(userID uint) ([]*model.Room, error) { + rooms := []*model.Room{} + err := db.Where("creator_id = ?", userID).Find(&rooms).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + return rooms, nil + } + return rooms, err +} diff --git a/internal/db/user.go b/internal/db/user.go index 6fc1934..5640b42 100644 --- a/internal/db/user.go +++ b/internal/db/user.go @@ -85,7 +85,10 @@ func DeleteUserByID(userID uint) error { func LoadAndDeleteUserByID(userID uint, columns ...clause.Column) (*model.User, error) { u := &model.User{} - err := db.Unscoped().Clauses(clause.Returning{Columns: columns}).Delete(u, userID).Error + err := db.Unscoped(). + Clauses(clause.Returning{Columns: columns}). + Delete(u, userID). + Error if errors.Is(err, gorm.ErrRecordNotFound) { return u, errors.New("user not found") } diff --git a/internal/model/movie.go b/internal/model/movie.go index 985787d..89242ab 100644 --- a/internal/model/movie.go +++ b/internal/model/movie.go @@ -6,16 +6,15 @@ import ( type Movie struct { gorm.Model - Position uint `gorm:"not null"` - RoomID uint `gorm:"not null;index"` - Room Room `gorm:"foreignKey:RoomID"` + Position uint `gorm:"not null"` + RoomID uint `gorm:"not null;index"` + CreatorID uint `gorm:"not null;index" json:"creatorId"` MovieInfo } type MovieInfo struct { BaseMovieInfo - PullKey string `json:"pullKey"` - CreatorID uint `gorm:"not null;index" json:"creatorId"` + PullKey string `json:"pullKey"` } type BaseMovieInfo struct { diff --git a/internal/model/room.go b/internal/model/room.go index 0128397..775b4b8 100644 --- a/internal/model/room.go +++ b/internal/model/room.go @@ -11,7 +11,6 @@ type Room struct { Name string `gorm:"not null;uniqueIndex"` Setting CreatorID uint `gorm:"index"` - Creator User `gorm:"foreignKey:CreatorID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL"` HashedPassword []byte GroupUserRelations []RoomUserRelation `gorm:"foreignKey:RoomID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` Movies []Movie `gorm:"foreignKey:RoomID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` diff --git a/internal/model/user.go b/internal/model/user.go index 79b4f0e..090bb21 100644 --- a/internal/model/user.go +++ b/internal/model/user.go @@ -12,6 +12,7 @@ const ( RoleBanned Role = iota RoleUser RoleAdmin + RoleRoot ) type User struct { @@ -20,6 +21,7 @@ type User struct { Role Role `gorm:"not null"` HashedPassword []byte 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/current.go b/internal/op/current.go index 5a70f8e..7c15e24 100644 --- a/internal/op/current.go +++ b/internal/op/current.go @@ -100,7 +100,7 @@ func (c *Current) Proto() *pb.Current { }, PullKey: c.Movie.PullKey, CreatedAt: c.Movie.CreatedAt.UnixMilli(), - Creator: GetUserName(c.Movie.MovieInfo.CreatorID), + Creator: GetUserName(c.Movie.CreatorID), }, Status: &pb.Status{ Seek: c.Status.Seek, diff --git a/internal/op/room.go b/internal/op/room.go index 68bbe58..0fd9054 100644 --- a/internal/op/room.go +++ b/internal/op/room.go @@ -256,24 +256,26 @@ func (r *Room) initMovie(movie *model.Movie) error { return nil } -func (r *Room) AddMovie(m model.MovieInfo) error { +func (r *Room) AddMovie(m model.Movie) error { err := r.LazyInit() if err != nil { return err } - movie := &model.Movie{ - RoomID: r.ID, - Position: uint(time.Now().UnixMilli()), - MovieInfo: m, - } + m.Position = uint(time.Now().UnixMilli()) + + m.RoomID = r.ID - err = r.initMovie(movie) + err = r.initMovie(&m) if err != nil { return err } - return CreateMovie(movie) + err = CreateMovie(&m) + if err != nil { + r.terminateMovie(&m) + } + return err } func (r *Room) HasPermission(user *model.User, permission model.Permission) bool { diff --git a/internal/op/rooms.go b/internal/op/rooms.go index 5945b28..3dd77ef 100644 --- a/internal/op/rooms.go +++ b/internal/op/rooms.go @@ -54,6 +54,15 @@ func DeleteRoom(room *Room) error { return db.DeleteRoomByID(room.ID) } +func DeleteRoomByID(id uint) error { + r, ok := roomCache.LoadAndDelete(id) + if ok { + r.close() + } + + return db.DeleteRoomByID(r.ID) +} + func GetRoomByID(id uint) (*Room, error) { r2, ok := roomCache.Load(id) if ok { diff --git a/internal/op/user.go b/internal/op/user.go index e6398b2..7068b10 100644 --- a/internal/op/user.go +++ b/internal/op/user.go @@ -28,10 +28,10 @@ func (u *User) CreateRoom(name, password string, conf ...db.CreateRoomConfig) (* return db.CreateRoom(name, password, append(conf, db.WithCreator(&u.User))...) } -func (u *User) NewMovie(movie model.BaseMovieInfo) model.MovieInfo { - return model.MovieInfo{ - BaseMovieInfo: movie, - CreatorID: u.ID, +func (u *User) NewMovie(movie model.MovieInfo) model.Movie { + return model.Movie{ + MovieInfo: movie, + CreatorID: u.ID, } } diff --git a/internal/op/users.go b/internal/op/users.go index 20f6cf3..7aa8fed 100644 --- a/internal/op/users.go +++ b/internal/op/users.go @@ -9,7 +9,6 @@ import ( "github.com/synctv-org/synctv/internal/model" "github.com/zijiren233/stream" "golang.org/x/crypto/bcrypt" - "gorm.io/gorm/clause" ) var userCache gcache.Cache @@ -42,7 +41,7 @@ func GetUserByUsername(username string) (*User, error) { u2 := &User{ User: *u, - version: 1, + version: crc32.ChecksumIEEE(u.HashedPassword), } return u2, userCache.SetWithExpire(u.ID, u2, time.Hour) @@ -80,24 +79,22 @@ func SetUserPassword(userID uint, password string) error { } func DeleteUserByID(userID uint) error { - u, err := db.LoadAndDeleteUserByID(userID, clause.Column{ - Name: "id", - }) + rs, err := db.GetAllRoomsByUserID(userID) if err != nil { return err } - userCache.Remove(u.ID) - return nil -} - -func DeleteUserByUsername(username string) error { - u, err := db.LoadAndDeleteUserByUsername(username, clause.Column{ - Name: "id", - }) + err = db.DeleteUserByID(userID) if err != nil { return err } - userCache.Remove(u.ID) + userCache.Remove(userID) + + for _, r := range rs { + r2, loaded := roomCache.LoadAndDelete(r.ID) + if loaded { + r2.close() + } + } return nil } diff --git a/server/handlers/init.go b/server/handlers/init.go index cdac9cf..adc7401 100644 --- a/server/handlers/init.go +++ b/server/handlers/init.go @@ -110,6 +110,8 @@ func Init(e *gin.Engine) { user.POST("/signup", SignupUser) + needAuthUser.POST("/logout", LogoutUser) + needAuthUser.GET("/me", Me) needAuthUser.POST("/pwd", SetUserPassword) diff --git a/server/handlers/movie.go b/server/handlers/movie.go index c76830b..edf0ffe 100644 --- a/server/handlers/movie.go +++ b/server/handlers/movie.go @@ -141,7 +141,9 @@ func PushMovie(ctx *gin.Context) { return } - mi := user.NewMovie(dbModel.BaseMovieInfo(req)) + mi := user.NewMovie(dbModel.MovieInfo{ + BaseMovieInfo: dbModel.BaseMovieInfo(req), + }) err := room.AddMovie(mi) if err != nil { diff --git a/server/handlers/user.go b/server/handlers/user.go index e07137d..098fb82 100644 --- a/server/handlers/user.go +++ b/server/handlers/user.go @@ -94,3 +94,15 @@ func SignupUser(ctx *gin.Context) { "token": token, })) } + +func LogoutUser(ctx *gin.Context) { + user := ctx.MustGet("user").(*op.User) + + err := op.DeleteUserByID(user.ID) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) + return + } + + ctx.Status(http.StatusNoContent) +}