From b90822942921b1797597733ba57b1f3fc830eb6e Mon Sep 17 00:00:00 2001 From: JustSong Date: Sun, 23 Apr 2023 11:31:00 +0800 Subject: [PATCH] Token API done without verification --- controller/token.go | 143 ++++++++++++ controller/user.go | 39 ---- model/channel.go | 19 +- model/token.go | 52 +++++ model/user.go | 8 +- router/api-router.go | 11 +- web/src/App.js | 7 + web/src/components/Header.js | 5 + web/src/components/PersonalSetting.js | 12 -- web/src/components/TokensTable.js | 300 ++++++++++++++++++++++++++ web/src/pages/Token/index.js | 14 ++ 11 files changed, 546 insertions(+), 64 deletions(-) create mode 100644 controller/token.go create mode 100644 model/token.go create mode 100644 web/src/components/TokensTable.js create mode 100644 web/src/pages/Token/index.js diff --git a/controller/token.go b/controller/token.go new file mode 100644 index 00000000..094235c2 --- /dev/null +++ b/controller/token.go @@ -0,0 +1,143 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "net/http" + "one-api/common" + "one-api/model" + "strconv" +) + +func GetAllTokens(c *gin.Context) { + userId := c.GetInt("id") + p, _ := strconv.Atoi(c.Query("p")) + if p < 0 { + p = 0 + } + tokens, err := model.GetAllUserTokens(userId, p*common.ItemsPerPage, common.ItemsPerPage) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "", + "data": tokens, + }) + return +} + +func SearchTokens(c *gin.Context) { + userId := c.GetInt("id") + keyword := c.Query("keyword") + tokens, err := model.SearchUserTokens(userId, keyword) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "", + "data": tokens, + }) + return +} + +func GetToken(c *gin.Context) { + id, err := strconv.Atoi(c.Param("id")) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + token, err := model.GetTokenById(id) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "", + "data": token, + }) + return +} + +func AddToken(c *gin.Context) { + token := model.Token{} + err := c.ShouldBindJSON(&token) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + err = token.Insert() + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "", + }) + return +} + +func DeleteToken(c *gin.Context) { + id, _ := strconv.Atoi(c.Param("id")) + token := model.Token{Id: id} + err := token.Delete() + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "", + }) + return +} + +func UpdateToken(c *gin.Context) { + token := model.Token{} + err := c.ShouldBindJSON(&token) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + err = token.Update() + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "", + }) + return +} diff --git a/controller/user.go b/controller/user.go index ce5f2862..014f974f 100644 --- a/controller/user.go +++ b/controller/user.go @@ -4,12 +4,10 @@ import ( "encoding/json" "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" - "github.com/google/uuid" "net/http" "one-api/common" "one-api/model" "strconv" - "strings" ) type LoginRequest struct { @@ -245,43 +243,6 @@ func GetUser(c *gin.Context) { return } -func GenerateToken(c *gin.Context) { - id := c.GetInt("id") - user, err := model.GetUserById(id, true) - if err != nil { - c.JSON(http.StatusOK, gin.H{ - "success": false, - "message": err.Error(), - }) - return - } - user.Token = uuid.New().String() - user.Token = strings.Replace(user.Token, "-", "", -1) - - if model.DB.Where("token = ?", user.Token).First(user).RowsAffected != 0 { - c.JSON(http.StatusOK, gin.H{ - "success": false, - "message": "请重试,系统生成的 UUID 竟然重复了!", - }) - return - } - - if err := user.Update(false); err != nil { - c.JSON(http.StatusOK, gin.H{ - "success": false, - "message": err.Error(), - }) - return - } - - c.JSON(http.StatusOK, gin.H{ - "success": true, - "message": "", - "data": user.Token, - }) - return -} - func GetSelf(c *gin.Context) { id := c.GetInt("id") user, err := model.GetUserById(id, false) diff --git a/model/channel.go b/model/channel.go index 4badd53c..3b885adb 100644 --- a/model/channel.go +++ b/model/channel.go @@ -5,28 +5,32 @@ import ( ) type Channel struct { - Id int `json:"id"` - Type int `json:"type" gorm:"default:0"` - Key string `json:"key"` - Status int `json:"status" gorm:"default:1"` + Id int `json:"id"` + Type int `json:"type" gorm:"default:0"` + Key string `json:"key"` + Status int `json:"status" gorm:"default:1"` + Name string `json:"name" gorm:"unique;index"` + Weight int `json:"weight"` + CreatedTime int64 `json:"created_time" gorm:"bigint"` + AccessedTime int64 `json:"accessed_time" gorm:"bigint"` } func GetAllChannels(startIdx int, num int) ([]*Channel, error) { var channels []*Channel var err error - err = DB.Order("id desc").Limit(num).Offset(startIdx).Find(&channels).Error + err = DB.Order("id desc").Limit(num).Offset(startIdx).Omit("key").Find(&channels).Error return channels, err } func SearchChannels(keyword string) (channels []*Channel, err error) { - err = DB.Select([]string{"id", "key"}, keyword, keyword).Find(&channels).Error + err = DB.Omit("key").Where("id = ? or name LIKE ?", keyword, keyword+"%").Find(&channels).Error return channels, err } func GetChannelById(id int) (*Channel, error) { channel := Channel{Id: id} var err error = nil - err = DB.Select([]string{"id", "type"}).First(&channel, "id = ?", id).Error + err = DB.Omit("key").First(&channel, "id = ?", id).Error return &channel, err } @@ -42,7 +46,6 @@ func (channel *Channel) Update() error { return err } -// Delete Make sure link is valid! Because we will use os.Remove to delete it! func (channel *Channel) Delete() error { var err error err = DB.Delete(channel).Error diff --git a/model/token.go b/model/token.go new file mode 100644 index 00000000..0cefd02c --- /dev/null +++ b/model/token.go @@ -0,0 +1,52 @@ +package model + +import ( + _ "gorm.io/driver/sqlite" +) + +type Token struct { + Id int `json:"id"` + UserId int `json:"user_id"` + Key string `json:"key"` + Status int `json:"status" gorm:"default:1"` + Name string `json:"name" gorm:"unique;index"` + CreatedTime int64 `json:"created_time" gorm:"bigint"` + AccessedTime int64 `json:"accessed_time" gorm:"bigint"` +} + +func GetAllUserTokens(userId int, startIdx int, num int) ([]*Token, error) { + var tokens []*Token + var err error + err = DB.Where("userId = ?", userId).Order("id desc").Limit(num).Offset(startIdx).Omit("key").Find(&tokens).Error + return tokens, err +} + +func SearchUserTokens(userId int, keyword string) (tokens []*Token, err error) { + err = DB.Where("userId = ?", userId).Omit("key").Where("id = ? or name LIKE ?", keyword, keyword+"%").Find(&tokens).Error + return tokens, err +} + +func GetTokenById(id int) (*Token, error) { + token := Token{Id: id} + var err error = nil + err = DB.Omit("key").Select([]string{"id", "type"}).First(&token, "id = ?", id).Error + return &token, err +} + +func (token *Token) Insert() error { + var err error + err = DB.Create(token).Error + return err +} + +func (token *Token) Update() error { + var err error + err = DB.Model(token).Updates(token).Error + return err +} + +func (token *Token) Delete() error { + var err error + err = DB.Delete(token).Error + return err +} diff --git a/model/user.go b/model/user.go index 496417b4..d84119bc 100644 --- a/model/user.go +++ b/model/user.go @@ -15,11 +15,11 @@ type User struct { DisplayName string `json:"display_name" gorm:"index" validate:"max=20"` Role int `json:"role" gorm:"type:int;default:1"` // admin, common Status int `json:"status" gorm:"type:int;default:1"` // enabled, disabled - Token string `json:"token" gorm:"index"` Email string `json:"email" gorm:"index" validate:"max=50"` GitHubId string `json:"github_id" gorm:"column:github_id;index"` WeChatId string `json:"wechat_id" gorm:"column:wechat_id;index"` VerificationCode string `json:"verification_code" gorm:"-:all"` // this field is only for Email verification, don't save it to database! + Balance int `json:"balance" gorm:"type:int;default:0"` } func GetMaxUserId() int { @@ -29,12 +29,12 @@ func GetMaxUserId() int { } func GetAllUsers(startIdx int, num int) (users []*User, err error) { - err = DB.Order("id desc").Limit(num).Offset(startIdx).Select([]string{"id", "username", "display_name", "role", "status", "email"}).Find(&users).Error + err = DB.Order("id desc").Limit(num).Offset(startIdx).Omit("password").Find(&users).Error return users, err } func SearchUsers(keyword string) (users []*User, err error) { - err = DB.Select([]string{"id", "username", "display_name", "role", "status", "email"}).Where("id = ? or username LIKE ? or email LIKE ? or display_name LIKE ?", keyword, keyword+"%", keyword+"%", keyword+"%").Find(&users).Error + err = DB.Omit("password").Where("id = ? or username LIKE ? or email LIKE ? or display_name LIKE ?", keyword, keyword+"%", keyword+"%", keyword+"%").Find(&users).Error return users, err } @@ -47,7 +47,7 @@ func GetUserById(id int, selectAll bool) (*User, error) { if selectAll { err = DB.First(&user, "id = ?", id).Error } else { - err = DB.Select([]string{"id", "username", "display_name", "role", "status", "email", "wechat_id", "github_id"}).First(&user, "id = ?", id).Error + err = DB.Omit("password").First(&user, "id = ?", id).Error } return &user, err } diff --git a/router/api-router.go b/router/api-router.go index 27efe79c..5e34cea6 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -33,7 +33,6 @@ func SetApiRouter(router *gin.Engine) { selfRoute.GET("/self", controller.GetSelf) selfRoute.PUT("/self", controller.UpdateSelf) selfRoute.DELETE("/self", controller.DeleteSelf) - selfRoute.GET("/token", controller.GenerateToken) } adminRoute := userRoute.Group("/") @@ -64,5 +63,15 @@ func SetApiRouter(router *gin.Engine) { channelRoute.PUT("/", controller.UpdateChannel) channelRoute.DELETE("/:id", controller.DeleteChannel) } + tokenRoute := apiRouter.Group("/token") + tokenRoute.Use(middleware.UserAuth()) + { + tokenRoute.GET("/", controller.GetAllTokens) + tokenRoute.GET("/search", controller.SearchTokens) + tokenRoute.GET("/:id", controller.GetToken) + tokenRoute.POST("/", controller.AddToken) + tokenRoute.PUT("/", controller.UpdateToken) + tokenRoute.DELETE("/:id", controller.DeleteToken) + } } } diff --git a/web/src/App.js b/web/src/App.js index a1a8a898..673ec496 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -15,6 +15,7 @@ import GitHubOAuth from './components/GitHubOAuth'; import PasswordResetConfirm from './components/PasswordResetConfirm'; import { UserContext } from './context/User'; import Channel from './pages/Channel'; +import Token from './pages/Token'; const Home = lazy(() => import('./pages/Home')); const About = lazy(() => import('./pages/About')); @@ -72,6 +73,12 @@ function App() { } /> + + } + /> { setInputs((inputs) => ({ ...inputs, [name]: value })); }; - const generateToken = async () => { - const res = await API.get('/api/user/token'); - const { success, message, data } = res.data; - if (success) { - await copy(data); - showSuccess(`令牌已重置并已复制到剪贴板:${data}`); - } else { - showError(message); - } - }; - const bindWeChat = async () => { if (inputs.wechat_verification_code === '') return; const res = await API.get( @@ -106,7 +95,6 @@ const PersonalSetting = () => { -
账号绑定