diff --git a/cmd/app/main.go b/cmd/app/main.go index 4e1e2d4..afae6fa 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -18,6 +18,14 @@ func main() { Name: "Paul", Email: "i@0x7f.app", }, + { + Name: "cxy004", + Email: "cxy004@qq.com", + }, + { + Name: "wzt", + Email: "w.zhongtao@qq.com", + }, }, Flags: []cli.Flag{ &cli.StringFlag{ diff --git a/go.mod b/go.mod index 645f379..8db94ce 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/gin-contrib/pprof v1.4.0 github.com/gin-contrib/zap v0.0.2 github.com/gin-gonic/gin v1.8.1 + github.com/go-redis/redis/v8 v8.11.5 github.com/golang-jwt/jwt/v4 v4.4.2 - github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.13.0 github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a github.com/swaggo/gin-swagger v1.5.3 @@ -29,6 +29,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.19.6 // indirect diff --git a/go.sum b/go.sum index dc97834..d2106f7 100644 --- a/go.sum +++ b/go.sum @@ -74,10 +74,13 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= @@ -124,6 +127,8 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= @@ -299,6 +304,9 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= @@ -733,6 +741,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/api/user/create.go b/internal/api/user/create.go index 78c07a7..68425f0 100644 --- a/internal/api/user/create.go +++ b/internal/api/user/create.go @@ -2,6 +2,7 @@ package user import ( "github.com/WHUPRJ/woj-server/internal/e" + "github.com/WHUPRJ/woj-server/internal/global" "github.com/WHUPRJ/woj-server/internal/service/user" "github.com/gin-gonic/gin" ) @@ -20,8 +21,7 @@ type createRequest struct { // @Param username formData string true "username" // @Param nickname formData string true "nickname" // @Param password formData string true "password" -// @Response 200 {object} e.Response "random string" -// @Security Authentication +// @Response 200 {object} e.Response "jwt token" // @Router /v1/user/create [post] func (h *handler) Create(c *gin.Context) { req := new(createRequest) @@ -37,6 +37,21 @@ func (h *handler) Create(c *gin.Context) { Password: req.Password, } - id, err := h.userService.Create(createData) - e.Pong(c, err, id) + u, err := h.userService.Create(createData) + if err != e.Success { + e.Pong(c, err, nil) + return + } + + version, err := h.userService.IncrVersion(u.ID) + if err != e.Success { + e.Pong(c, err, nil) + return + } + claim := &global.Claim{ + UID: u.ID, + Version: version, + } + token, err := h.jwtService.SignClaim(claim) + e.Pong(c, err, token) } diff --git a/internal/api/user/handler.go b/internal/api/user/handler.go index 549c498..6f0e94b 100644 --- a/internal/api/user/handler.go +++ b/internal/api/user/handler.go @@ -2,7 +2,6 @@ package user import ( "github.com/WHUPRJ/woj-server/internal/global" - "github.com/WHUPRJ/woj-server/internal/repo/model" "github.com/WHUPRJ/woj-server/internal/service/user" "github.com/gin-gonic/gin" "go.uber.org/zap" @@ -14,8 +13,6 @@ type Handler interface { Create(c *gin.Context) Login(c *gin.Context) // List(c *gin.Context) - - tokenNext(c *gin.Context, user *model.User) } type handler struct { @@ -32,6 +29,7 @@ func RouteRegister(g *global.Global, group *gin.RouterGroup) { } group.POST("/login", app.Login) - group.POST("/create", app.jwtService.Handler(), app.Create) + group.POST("/create", app.Create) + group.POST("/logout", app.jwtService.Handler(), app.Logout) // group.GET("/", app.List) } diff --git a/internal/api/user/login.go b/internal/api/user/login.go index 7b7c0dc..c199ec3 100644 --- a/internal/api/user/login.go +++ b/internal/api/user/login.go @@ -2,6 +2,7 @@ package user import ( "github.com/WHUPRJ/woj-server/internal/e" + "github.com/WHUPRJ/woj-server/internal/global" "github.com/WHUPRJ/woj-server/internal/repo/model" "github.com/gin-gonic/gin" ) @@ -18,7 +19,7 @@ type loginRequest struct { // @Produce json // @Param username formData string true "username" // @Param password formData string true "password" -// @Response 200 {object} e.Response "random string" +// @Response 200 {object} e.Response "jwt token" // @Router /v1/user/login [post] func (h *handler) Login(c *gin.Context) { req := new(loginRequest) @@ -40,5 +41,15 @@ func (h *handler) Login(c *gin.Context) { } // sign and return token - h.tokenNext(c, user) + version, err := h.userService.IncrVersion(user.ID) + if err != e.Success { + e.Pong(c, err, nil) + return + } + claim := &global.Claim{ + UID: user.ID, + Version: version, + } + token, err := h.jwtService.SignClaim(claim) + e.Pong(c, err, token) } diff --git a/internal/api/user/logout.go b/internal/api/user/logout.go new file mode 100644 index 0000000..0a66bb7 --- /dev/null +++ b/internal/api/user/logout.go @@ -0,0 +1,26 @@ +package user + +import ( + "github.com/WHUPRJ/woj-server/internal/e" + "github.com/WHUPRJ/woj-server/internal/global" + "github.com/gin-gonic/gin" +) + +// Logout +// @Summary logout +// @Description logout +// @Accept application/x-www-form-urlencoded +// @Produce json +// @Response 200 {object} e.Response "nil" +// @Security Authentication +// @Router /v1/user/logout [post] +func (h *handler) Logout(c *gin.Context) { + claim, exist := c.Get("claim") + if !exist { + e.Pong(c, e.UserUnauthenticated, nil) + return + } + + _, err := h.userService.IncrVersion(claim.(*global.Claim).UID) + e.Pong(c, err, nil) +} diff --git a/internal/api/user/token.go b/internal/api/user/token.go deleted file mode 100644 index 10a38fa..0000000 --- a/internal/api/user/token.go +++ /dev/null @@ -1,18 +0,0 @@ -package user - -import ( - "github.com/WHUPRJ/woj-server/internal/e" - "github.com/WHUPRJ/woj-server/internal/global" - "github.com/WHUPRJ/woj-server/internal/repo/model" - "github.com/gin-gonic/gin" -) - -func (h *handler) tokenNext(c *gin.Context, user *model.User) { - claim := &global.Claim{ - UID: user.ID, - UserName: user.UserName, - NickName: user.NickName, - } - token, err := h.jwtService.SignClaim(claim) - e.Pong(c, err, token) -} diff --git a/internal/app/app.go b/internal/app/app.go index 7a5c46c..58139f5 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/WHUPRJ/woj-server/internal/global" "github.com/WHUPRJ/woj-server/internal/repo/postgresql" + "github.com/WHUPRJ/woj-server/internal/repo/redis" "github.com/WHUPRJ/woj-server/internal/router" "github.com/WHUPRJ/woj-server/internal/service/jwt" "go.uber.org/zap" @@ -17,9 +18,13 @@ import ( func Run(g *global.Global) error { // Setup Database - g.Db = new(postgresql.PgRepo) + g.Db = new(postgresql.Repo) g.Db.Setup(g) + // Setup Redis + g.Redis = new(redis.Repo) + g.Redis.Setup(g) + // Setup JWT g.Jwt = jwt.NewJwtService(g) diff --git a/internal/e/code.go b/internal/e/code.go index 4320e61..83abc4f 100644 --- a/internal/e/code.go +++ b/internal/e/code.go @@ -17,9 +17,12 @@ const ( TokenSignError Err = 205 TokenRevoked Err = 206 - UserNotFound Err = 300 - UserWrongPassword Err = 301 - UserDuplicated Err = 302 + UserNotFound Err = 300 + UserWrongPassword Err = 301 + UserDuplicated Err = 302 + UserUnauthenticated Err = 303 + + RedisError Err = 400 ) var msgText = map[Err]string{ @@ -39,7 +42,10 @@ var msgText = map[Err]string{ TokenSignError: "Token Sign Error", TokenRevoked: "Token Revoked", - UserNotFound: "User Not Found", - UserWrongPassword: "User Wrong Password", - UserDuplicated: "User Duplicated", + UserNotFound: "User Not Found", + UserWrongPassword: "User Wrong Password", + UserDuplicated: "User Duplicated", + UserUnauthenticated: "User Unauthenticated", + + RedisError: "Redis Error", } diff --git a/internal/global/global.go b/internal/global/global.go index 9d445ba..609895a 100644 --- a/internal/global/global.go +++ b/internal/global/global.go @@ -6,9 +6,10 @@ import ( ) type Global struct { - Log *zap.Logger - Conf *Config - Stat *metrics.Metrics - Db Repo - Jwt JwtService + Log *zap.Logger + Conf *Config + Stat *metrics.Metrics + Db Repo + Redis Repo + Jwt JwtService } diff --git a/internal/global/jwt.go b/internal/global/jwt.go index 6311ce5..dbd5e77 100644 --- a/internal/global/jwt.go +++ b/internal/global/jwt.go @@ -7,17 +7,15 @@ import ( ) type Claim struct { - UID uint `json:"id"` - UserName string `json:"user_name"` - NickName string `json:"nick_name"` - Version int `json:"version"` + UID uint `json:"id"` + Version int64 `json:"version"` jwt.RegisteredClaims } type JwtService interface { ParseToken(tokenText string) (*Claim, e.Err) SignClaim(claim *Claim) (string, e.Err) - // TODO: Validate(claim *Claim) bool + Validate(claim *Claim) bool Handler() gin.HandlerFunc } diff --git a/internal/global/repo.go b/internal/global/repo.go index 4bd5218..89b8b28 100644 --- a/internal/global/repo.go +++ b/internal/global/repo.go @@ -1,12 +1,7 @@ package global -import ( - "gorm.io/gorm" -) - type Repo interface { Setup(*Global) - - Get() *gorm.DB + Get() interface{} Close() error } diff --git a/internal/repo/postgresql/postgresql.go b/internal/repo/postgresql/postgresql.go index 311e971..1181a77 100644 --- a/internal/repo/postgresql/postgresql.go +++ b/internal/repo/postgresql/postgresql.go @@ -14,18 +14,18 @@ import ( "time" ) -var _ global.Repo = (*PgRepo)(nil) +var _ global.Repo = (*Repo)(nil) -type PgRepo struct { +type Repo struct { db *gorm.DB log *zap.Logger } -func (r *PgRepo) Get() *gorm.DB { +func (r *Repo) Get() interface{} { return r.db } -func (r *PgRepo) Close() error { +func (r *Repo) Close() error { db, err := r.db.DB() if err != nil { return err @@ -33,7 +33,7 @@ func (r *PgRepo) Close() error { return db.Close() } -func (r *PgRepo) Setup(g *global.Global) { +func (r *Repo) Setup(g *global.Global) { r.log = g.Log r.log.Info("Connecting to database...") @@ -78,14 +78,14 @@ func (r *PgRepo) Setup(g *global.Global) { r.migrateDatabase() } -func (r *PgRepo) migrateDatabase() { +func (r *Repo) migrateDatabase() { r.log.Info("Auto Migrating database...") _ = r.db.AutoMigrate(&model.User{}) } // checkAlive deprecated -func (r *PgRepo) checkAlive(retry int) (*sql.DB, error) { +func (r *Repo) checkAlive(retry int) (*sql.DB, error) { if retry <= 0 { return nil, errors.New("all retries are used up. failed to connect to database") } diff --git a/internal/repo/redis/redis.go b/internal/repo/redis/redis.go new file mode 100644 index 0000000..d23da71 --- /dev/null +++ b/internal/repo/redis/redis.go @@ -0,0 +1,39 @@ +package redis + +import ( + "context" + "github.com/WHUPRJ/woj-server/internal/global" + "github.com/go-redis/redis/v8" + "go.uber.org/zap" +) + +var _ global.Repo = (*Repo)(nil) + +type Repo struct { + client *redis.Client + log *zap.Logger +} + +func (r *Repo) Setup(g *global.Global) { + r.log = g.Log + + r.client = redis.NewClient(&redis.Options{ + Addr: g.Conf.Redis.Address, + Password: g.Conf.Redis.Password, + DB: g.Conf.Redis.Db, + }) + + _, err := r.client.Ping(context.Background()).Result() + if err != nil { + r.log.Fatal("Redis ping failed", zap.Error(err)) + return + } +} + +func (r *Repo) Get() interface{} { + return r.client +} + +func (r *Repo) Close() error { + return r.client.Close() +} diff --git a/internal/service/jwt/middleware.go b/internal/service/jwt/middleware.go index c708684..22145e9 100644 --- a/internal/service/jwt/middleware.go +++ b/internal/service/jwt/middleware.go @@ -8,13 +8,14 @@ import ( func (s *service) Handler() gin.HandlerFunc { return func(c *gin.Context) { + const tokenPrefix = "bearer " tokenHeader := c.GetHeader("Authorization") - if tokenHeader == "" || !strings.HasPrefix(strings.ToLower(tokenHeader), "bearer ") { + if tokenHeader == "" || !strings.HasPrefix(strings.ToLower(tokenHeader), tokenPrefix) { e.Pong(c, e.TokenEmpty, nil) c.Abort() return } - token := tokenHeader[7:] + token := tokenHeader[len(tokenPrefix):] claim, err := s.ParseToken(token) if err != e.Success { @@ -23,11 +24,11 @@ func (s *service) Handler() gin.HandlerFunc { return } - // TODO: validate claim version - // if !s.Validate(claim) { - // e.Pong(c, e.TokenRevoked, nil) - // c.Abort() - // } + if !s.Validate(claim) { + e.Pong(c, e.TokenRevoked, nil) + c.Abort() + return + } c.Set("claim", claim) c.Next() diff --git a/internal/service/jwt/service.go b/internal/service/jwt/service.go index 25f7fb0..3cb372d 100644 --- a/internal/service/jwt/service.go +++ b/internal/service/jwt/service.go @@ -2,6 +2,7 @@ package jwt import ( "github.com/WHUPRJ/woj-server/internal/global" + "github.com/go-redis/redis/v8" "go.uber.org/zap" ) @@ -9,6 +10,7 @@ var _ global.JwtService = (*service)(nil) type service struct { log *zap.Logger + redis *redis.Client SigningKey []byte ExpireHour int } @@ -16,6 +18,7 @@ type service struct { func NewJwtService(g *global.Global) global.JwtService { return &service{ log: g.Log, + redis: g.Redis.Get().(*redis.Client), SigningKey: []byte(g.Conf.WebServer.JwtSigningKey), ExpireHour: g.Conf.WebServer.JwtExpireHour, } diff --git a/internal/service/jwt/token.go b/internal/service/jwt/token.go index ddc2bbf..19a2412 100644 --- a/internal/service/jwt/token.go +++ b/internal/service/jwt/token.go @@ -1,6 +1,7 @@ package jwt import ( + "context" "fmt" "github.com/WHUPRJ/woj-server/internal/e" "github.com/WHUPRJ/woj-server/internal/global" @@ -17,7 +18,7 @@ func (s *service) ParseToken(tokenText string) (*global.Claim, e.Err) { token, err := jwt.ParseWithClaims( tokenText, - &global.Claim{}, + new(global.Claim), func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) @@ -64,3 +65,12 @@ func (s *service) SignClaim(claim *global.Claim) (string, e.Err) { } return ss, e.Success } + +func (s *service) Validate(claim *global.Claim) bool { + curVersion, err := s.redis.Get(context.Background(), fmt.Sprintf("Version:%d", claim.UID)).Int64() + if err != nil { + s.log.Debug("redis.Get error", zap.Error(err)) + return false + } + return curVersion == claim.Version +} diff --git a/internal/service/user/create.go b/internal/service/user/create.go index 3c85674..a0b2b8d 100644 --- a/internal/service/user/create.go +++ b/internal/service/user/create.go @@ -14,11 +14,11 @@ type CreateData struct { Password string } -func (s *service) Create(data *CreateData) (uint, e.Err) { +func (s *service) Create(data *CreateData) (*model.User, e.Err) { hashed, err := bcrypt.GenerateFromPassword([]byte(data.Password), bcrypt.DefaultCost) if err != nil { s.log.Debug("bcrypt error", zap.Error(err), zap.String("password", data.Password)) - return 0, e.InternalError + return nil, e.InternalError } user := &model.User{ @@ -28,12 +28,12 @@ func (s *service) Create(data *CreateData) (uint, e.Err) { IsEnabled: true, } - if err := s.db.Get().Create(user).Error; err != nil { + if err := s.db.Create(user).Error; err != nil { if strings.Contains(err.Error(), "duplicate key") { - return 0, e.UserDuplicated + return nil, e.UserDuplicated } s.log.Debug("create user error", zap.Error(err), zap.Any("data", data)) - return 0, e.DatabaseError + return nil, e.DatabaseError } - return user.ID, e.Success + return user, e.Success } diff --git a/internal/service/user/login.go b/internal/service/user/login.go index bc604a4..48e8ee4 100644 --- a/internal/service/user/login.go +++ b/internal/service/user/login.go @@ -11,7 +11,7 @@ import ( func (s *service) Login(data *model.User) (*model.User, e.Err) { user := &model.User{UserName: data.UserName} - err := s.db.Get().Where(user).First(&user).Error + err := s.db.Where(user).First(&user).Error if errors.Is(err, gorm.ErrRecordNotFound) { return user, e.UserNotFound } diff --git a/internal/service/user/service.go b/internal/service/user/service.go index 5e2f1fa..00ae8f1 100644 --- a/internal/service/user/service.go +++ b/internal/service/user/service.go @@ -4,24 +4,29 @@ import ( "github.com/WHUPRJ/woj-server/internal/e" "github.com/WHUPRJ/woj-server/internal/global" "github.com/WHUPRJ/woj-server/internal/repo/model" + "github.com/go-redis/redis/v8" "go.uber.org/zap" + "gorm.io/gorm" ) var _ Service = (*service)(nil) type Service interface { - Create(data *CreateData) (uint, e.Err) + Create(data *CreateData) (*model.User, e.Err) Login(data *model.User) (*model.User, e.Err) + IncrVersion(id uint) (int64, e.Err) } type service struct { - log *zap.Logger - db global.Repo + log *zap.Logger + db *gorm.DB + redis *redis.Client } func NewUserService(g *global.Global) Service { return &service{ - log: g.Log, - db: g.Db, + log: g.Log, + db: g.Db.Get().(*gorm.DB), + redis: g.Redis.Get().(*redis.Client), } } diff --git a/internal/service/user/version.go b/internal/service/user/version.go new file mode 100644 index 0000000..1485dad --- /dev/null +++ b/internal/service/user/version.go @@ -0,0 +1,17 @@ +package user + +import ( + "context" + "fmt" + "github.com/WHUPRJ/woj-server/internal/e" + "go.uber.org/zap" +) + +func (s *service) IncrVersion(id uint) (int64, e.Err) { + version, err := s.redis.Incr(context.Background(), fmt.Sprintf("Version:%d", id)).Result() + if err != nil { + s.log.Debug("redis.Incr error", zap.Error(err)) + return -1, e.RedisError + } + return version, e.Success +}