diff --git a/internal/db/setting.go b/internal/db/setting.go index ad0329e..7447940 100644 --- a/internal/db/setting.go +++ b/internal/db/setting.go @@ -37,6 +37,13 @@ func GetSettingItemValue(name string) (string, error) { return value, err } -func SetSettingItemValue(name, value string) error { - return db.Model(&model.Setting{}).Where("name = ?", name).Assign("value", value).FirstOrCreate(&model.Setting{}).Error +func FirstOrCreateSettingItemValue(s *model.Setting) error { + return db.Where("name = ?", s.Name).Attrs(model.Setting{ + Value: s.Value, + Type: s.Type, + }).FirstOrCreate(s).Error +} + +func UpdateSettingItemValue(name, value string) error { + return db.Model(&model.Setting{}).Where("name = ?", name).Update("value", value).Error } diff --git a/internal/op/op.go b/internal/op/op.go index 8b1eb8c..95aa65d 100644 --- a/internal/op/op.go +++ b/internal/op/op.go @@ -11,20 +11,26 @@ func Init(size int) error { LRU(). Build() - si, err := db.GetSettingItems() + err := initSettings(ToSettings(BoolSettings)...) if err != nil { - panic(err) + return err } - for _, si2 := range si { - switch si2.Type { - case model.SettingTypeBool: - b, ok := boolSettings[si2.Name] - if ok { - b.value = si2.Value - } + + return nil +} + +func initSettings(i ...Setting) error { + for _, b := range i { + s := &model.Setting{ + Name: b.Name(), + Value: b.Raw(), + Type: model.SettingTypeBool, + } + err := db.FirstOrCreateSettingItemValue(s) + if err != nil { + return err } + b.SetRaw(s.Value) } - cleanReg() - return nil } diff --git a/internal/op/settings.go b/internal/op/settings.go index 8cbe72d..d979775 100644 --- a/internal/op/settings.go +++ b/internal/op/settings.go @@ -5,17 +5,26 @@ import ( "github.com/synctv-org/synctv/internal/model" ) -var boolSettings map[string]*Bool +var BoolSettings map[string]BoolSetting type Setting interface { Name() string + SetRaw(string) Raw() string Type() model.SettingType } +func ToSettings[s Setting](settings map[string]s) []Setting { + var ss []Setting + for _, v := range settings { + ss = append(ss, v) + } + return ss +} + type BoolSetting interface { Setting - Set(value bool) error + Set(bool) error Get() (bool, error) } @@ -35,13 +44,26 @@ func (b *Bool) Name() string { return b.name } +func (b *Bool) SetRaw(s string) { + if b.value == s { + return + } + b.value = s +} + func (b *Bool) Set(value bool) error { if value { + if b.value == "1" { + return nil + } b.value = "1" } else { + if b.value == "0" { + return nil + } b.value = "0" } - return db.SetSettingItemValue(b.name, b.value) + return db.UpdateSettingItemValue(b.name, b.value) } func (b *Bool) Get() (bool, error) { @@ -57,36 +79,40 @@ func (b *Bool) Type() model.SettingType { } type Int64Setting interface { - Set(value int64) error + Set(int64) error Get() (int64, error) Raw() string } type Float64Setting interface { - Set(value float64) error + Set(float64) error Get() (float64, error) Raw() string } type StringSetting interface { - Set(value string) error + Set(string) error Get() (string, error) Raw() string } -func cleanReg() { - boolSettings = nil -} - func newRegBoolSetting(k, v string) BoolSetting { b := NewBool(k, v) - if boolSettings == nil { - boolSettings = make(map[string]*Bool) + if BoolSettings == nil { + BoolSettings = make(map[string]BoolSetting) } - boolSettings[k] = b + BoolSettings[k] = b return b } +func GetSettingType(name string) (model.SettingType, bool) { + s, ok := BoolSettings[name] + if !ok { + return "", false + } + return s.Type(), true +} + var ( DisableCreateRoom = newRegBoolSetting("disable_create_room", "0") ) diff --git a/server/handlers/admin.go b/server/handlers/admin.go index 42704ff..86627c4 100644 --- a/server/handlers/admin.go +++ b/server/handlers/admin.go @@ -1,7 +1,33 @@ package handlers -import "github.com/gin-gonic/gin" +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + dbModel "github.com/synctv-org/synctv/internal/model" + "github.com/synctv-org/synctv/internal/op" + "github.com/synctv-org/synctv/server/model" +) func AdminSettings(ctx *gin.Context) { + // user := ctx.MustGet("user").(*op.User) + + req := model.AdminSettingsReq{} + if err := req.Decode(ctx); err != nil { + ctx.AbortWithError(http.StatusBadRequest, err) + return + } + for k, v := range req { + t, ok := op.GetSettingType(k) + if !ok { + ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorStringResp(fmt.Sprintf("setting %s not found", k))) + return + } + switch t { + case dbModel.SettingTypeBool: + op.BoolSettings[k].Set(v == "1") + } + } } diff --git a/server/handlers/init.go b/server/handlers/init.go index 551f4e8..27b1b46 100644 --- a/server/handlers/init.go +++ b/server/handlers/init.go @@ -38,8 +38,10 @@ func Init(e *gin.Engine) { } { - // TODO: admin api implement - // admin := api.Group("/admin") + admin := api.Group("/admin") + admin.Use(middlewares.AuthAdminMiddleware) + + admin.POST("/settings", AdminSettings) } { diff --git a/server/middlewares/auth.go b/server/middlewares/auth.go index aea25fb..61b952e 100644 --- a/server/middlewares/auth.go +++ b/server/middlewares/auth.go @@ -2,6 +2,7 @@ package middlewares import ( "errors" + "net/http" "strings" "time" @@ -111,6 +112,17 @@ func AuthUser(Authorization string) (*op.User, error) { return u, nil } +func AuthAdmin(Authorization string) (*op.User, error) { + u, err := AuthUser(Authorization) + if err != nil { + return nil, err + } + if !u.IsAdmin() { + return nil, errors.New("user is not admin") + } + return u, nil +} + func NewAuthUserToken(user *op.User) (string, error) { if user.IsBanned() { return "", errors.New("user banned") @@ -154,7 +166,7 @@ func NewAuthRoomToken(user *op.User, room *op.Room) (string, error) { func AuthRoomMiddleware(ctx *gin.Context) { user, room, err := AuthRoom(ctx.GetHeader("Authorization")) if err != nil { - ctx.AbortWithStatusJSON(401, model.NewApiErrorResp(err)) + ctx.AbortWithStatusJSON(http.StatusUnauthorized, model.NewApiErrorResp(err)) return } @@ -166,7 +178,18 @@ func AuthRoomMiddleware(ctx *gin.Context) { func AuthUserMiddleware(ctx *gin.Context) { user, err := AuthUser(ctx.GetHeader("Authorization")) if err != nil { - ctx.AbortWithStatusJSON(401, model.NewApiErrorResp(err)) + ctx.AbortWithStatusJSON(http.StatusUnauthorized, model.NewApiErrorResp(err)) + return + } + + ctx.Set("user", user) + ctx.Next() +} + +func AuthAdminMiddleware(ctx *gin.Context) { + user, err := AuthAdmin(ctx.GetHeader("Authorization")) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusForbidden, model.NewApiErrorResp(err)) return } diff --git a/server/model/admin.go b/server/model/admin.go new file mode 100644 index 0000000..6805ba0 --- /dev/null +++ b/server/model/admin.go @@ -0,0 +1,16 @@ +package model + +import ( + "github.com/gin-gonic/gin" + json "github.com/json-iterator/go" +) + +type AdminSettingsReq map[string]string + +func (asr *AdminSettingsReq) Validate() error { + return nil +} + +func (asr *AdminSettingsReq) Decode(ctx *gin.Context) error { + return json.NewDecoder(ctx.Request.Body).Decode(asr) +}