From 92229f525afc73e8491f6c7727abe57b34f3b897 Mon Sep 17 00:00:00 2001 From: Jonson Petard <41122242+greenhat616@users.noreply.github.com> Date: Sat, 5 Aug 2023 20:29:43 +0800 Subject: [PATCH] feat(middleware,controller): finish bizctx, user data in ctx, get user info --- api/admin/admin.go | 2 +- api/admin/v1/grant_authority.go | 2 +- api/poll/poll.go | 2 +- api/poll/v1/detail.go | 2 +- api/poll/v1/mark.go | 2 +- api/poll/v1/poll.go | 2 +- api/user/user.go | 2 +- api/user/v1/poll_result.go | 4 +- api/user/v1/user.go | 11 +-- internal/cmd/cmd.go | 2 +- internal/consts/user.go | 16 ++++- internal/controller/user/user_v1_get_user.go | 34 ++++++++- internal/logic/bizctx/bizctx.go | 44 ++++++++++++ internal/logic/logic.go | 1 + internal/logic/middleware/auth.go | 74 ++++++++++++++++++++ internal/logic/middleware/ctx.go | 14 ++++ internal/logic/middleware/middleware.go | 39 ----------- internal/logic/user/convert.go | 64 +++++++++++++++++ internal/logic/user/user.go | 46 ++++++++++-- internal/model/context.go | 7 ++ internal/model/user.go | 13 ++++ internal/service/bizctx.go | 40 +++++++++++ internal/service/brictx.go | 8 +++ internal/service/middleware.go | 9 ++- internal/service/user.go | 15 +++- 25 files changed, 386 insertions(+), 69 deletions(-) create mode 100644 internal/logic/bizctx/bizctx.go create mode 100644 internal/logic/middleware/auth.go create mode 100644 internal/logic/middleware/ctx.go create mode 100644 internal/logic/user/convert.go create mode 100644 internal/model/context.go create mode 100644 internal/model/user.go create mode 100644 internal/service/bizctx.go create mode 100644 internal/service/brictx.go diff --git a/api/admin/admin.go b/api/admin/admin.go index f01262f..80ce068 100644 --- a/api/admin/admin.go +++ b/api/admin/admin.go @@ -7,7 +7,7 @@ package admin import ( "context" - v1 "github.com/hitokoto-osc/reviewer/api/admin/v1" + "github.com/hitokoto-osc/reviewer/api/admin/v1" ) type IAdminV1 interface { diff --git a/api/admin/v1/grant_authority.go b/api/admin/v1/grant_authority.go index 100e2a8..a95cab2 100644 --- a/api/admin/v1/grant_authority.go +++ b/api/admin/v1/grant_authority.go @@ -12,7 +12,7 @@ type GrantUserAuthorityReq struct { } type GrantUserAuthorityRes struct { - ID int64 `json:"id" dc:"用户 ID"` + ID uint `json:"id" dc:"用户 ID"` Name string `json:"name" dc:"用户名"` Email string `json:"email" dc:"邮箱"` Token string `json:"token" dc:"Token"` diff --git a/api/poll/poll.go b/api/poll/poll.go index 4162bf6..f7e3f4b 100644 --- a/api/poll/poll.go +++ b/api/poll/poll.go @@ -7,7 +7,7 @@ package poll import ( "context" - v1 "github.com/hitokoto-osc/reviewer/api/poll/v1" + "github.com/hitokoto-osc/reviewer/api/poll/v1" ) type IPollV1 interface { diff --git a/api/poll/v1/detail.go b/api/poll/v1/detail.go index a30ca30..97a5d2b 100644 --- a/api/poll/v1/detail.go +++ b/api/poll/v1/detail.go @@ -11,7 +11,7 @@ type GetPollDetailReq struct { } type PollRecord struct { - UserID int64 `json:"user_id" dc:"用户 ID"` + UserID uint `json:"user_id" dc:"用户 ID"` Point int `json:"point" dc:"投票点数"` Type consts.PollMethod `json:"type" dc:"投票类型"` Comment string `json:"comment" dc:"理由"` diff --git a/api/poll/v1/mark.go b/api/poll/v1/mark.go index 0fa3c1d..e1a6759 100644 --- a/api/poll/v1/mark.go +++ b/api/poll/v1/mark.go @@ -10,7 +10,7 @@ type GetPollMarksReq struct { } type PollMark struct { - ID int64 `json:"id" dc:"标记 ID"` + ID uint `json:"id" dc:"标记 ID"` Text string `json:"text" dc:"标记文本"` Level consts.PollMarkLevel `json:"level" dc:"标记等级"` Property consts.PollMarkProperty `json:"property" dc:"标记属性"` diff --git a/api/poll/v1/poll.go b/api/poll/v1/poll.go index 08a5400..24efe7a 100644 --- a/api/poll/v1/poll.go +++ b/api/poll/v1/poll.go @@ -25,7 +25,7 @@ type PollReq struct { g.Meta `path:"/poll" tags:"Poll" method:"put" summary:"投票"` Method consts.PollMethod `json:"method" dc:"投票方式" v:"required|enums"` SentenceUUID string `json:"sentence_uuid" dc:"句子 UUID" v:"required|length:36"` - MarkID int64 `json:"mark_id" dc:"标记" v:"required-unless:method,1"` + MarkID uint `json:"mark_id" dc:"标记" v:"required-unless:method,1"` Comment string `json:"comment" dc:"理由" v:"required-if:method,2,3|length:1,255"` } diff --git a/api/user/user.go b/api/user/user.go index 9f419b5..e77aff5 100644 --- a/api/user/user.go +++ b/api/user/user.go @@ -7,7 +7,7 @@ package user import ( "context" - v1 "github.com/hitokoto-osc/reviewer/api/user/v1" + "github.com/hitokoto-osc/reviewer/api/user/v1" ) type IUserV1 interface { diff --git a/api/user/v1/poll_result.go b/api/user/v1/poll_result.go index e5453dc..e7c250b 100644 --- a/api/user/v1/poll_result.go +++ b/api/user/v1/poll_result.go @@ -14,11 +14,11 @@ type GetUserPollResultReq struct { type UserPollElement struct { UserPollLog PollInfo v1.PollSchema `json:"poll_info" dc:"投票信息"` - Marks []int64 `json:"marks" dc:"投票标记"` + Marks []uint `json:"marks" dc:"投票标记"` } type UserPollResult struct { - Total int64 `json:"total" dc:"总数"` + Total uint `json:"total" dc:"总数"` Collection []UserPollElement `json:"collection" dc:"数据"` } diff --git a/api/user/v1/user.go b/api/user/v1/user.go index f56fec4..c32e64d 100644 --- a/api/user/v1/user.go +++ b/api/user/v1/user.go @@ -2,6 +2,7 @@ package v1 import ( "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" "github.com/hitokoto-osc/reviewer/internal/consts" ) @@ -21,16 +22,16 @@ type UserPoll struct { Points UserPollPoints `json:"points" dc:"投票点数"` Count int `json:"count" dc:"投票次数"` Score int `json:"score" dc:"投票得分"` - CreatedAt string `json:"created_at" dc:"创建时间"` - UpdatedAt string `json:"updated_at" dc:"更新时间"` + CreatedAt *gtime.Time `json:"created_at" dc:"创建时间"` + UpdatedAt *gtime.Time `json:"updated_at" dc:"更新时间"` } type GetUserRes struct { - ID int64 `json:"id" dc:"用户 ID"` + ID uint `json:"id" dc:"用户 ID"` Name string `json:"name" dc:"用户名"` Email string `json:"email" dc:"邮箱"` Role consts.UserRole `json:"role" dc:"角色"` Poll UserPoll `json:"poll" dc:"投票信息"` - CreatedAt string `json:"created_at" dc:"创建时间"` - UpdatedAt string `json:"updated_at" dc:"更新时间"` + CreatedAt *gtime.Time `json:"created_at" dc:"创建时间"` + UpdatedAt *gtime.Time `json:"updated_at" dc:"更新时间"` } diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index d3e247b..affe5e5 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -34,7 +34,7 @@ var ( s.Group("/api/v1", func(group *ghttp.RouterGroup) { group.Bind(index.NewV1()) group.Group("/", func(group *ghttp.RouterGroup) { - group.Middleware(service.Middleware().AuthorizationV1) + group.Middleware(service.Middleware().Ctx, service.Middleware().AuthorizationV1) group.Bind(user.NewV1(), poll.NewV1()) group.Group("/admin", func(group *ghttp.RouterGroup) { group.Middleware(service.Middleware().AuthorizationAdminV1) diff --git a/internal/consts/user.go b/internal/consts/user.go index 380ac88..830410b 100644 --- a/internal/consts/user.go +++ b/internal/consts/user.go @@ -7,9 +7,10 @@ const ( type UserRole string const ( - RoleAdmin UserRole = "管理员" - RoleUser UserRole = "普通用户" - RoleReviewer UserRole = "审核员" + UserRoleGuest UserRole = "游客" + UserRoleAdmin UserRole = "管理员" + UserRoleUser UserRole = "普通用户" + UserRoleReviewer UserRole = "审核员" ) type UserStatus int @@ -28,3 +29,12 @@ const ( UserLoginTypeToken UserLoginType = "token" // Token 尝试 UserLoginTypeUsername UserLoginType = "username" // Username 尝试 ) + +// UserPollPoints 用户可以的投票点数 +type UserPollPoints int + +const ( + UserPollPointsReviewer UserPollPoints = 1 // 审核员 + UserPollPointsNormal UserPollPoints = 1 // 普通用户 + UserPollPointsAdmin UserPollPoints = 2 // 管理员 +) diff --git a/internal/controller/user/user_v1_get_user.go b/internal/controller/user/user_v1_get_user.go index 9d5bc0a..75bf45f 100644 --- a/internal/controller/user/user_v1_get_user.go +++ b/internal/controller/user/user_v1_get_user.go @@ -3,6 +3,12 @@ package user import ( "context" + "github.com/gogf/gf/v2/frame/g" + + "github.com/gogf/gf/v2/util/gconv" + + "github.com/hitokoto-osc/reviewer/internal/service" + "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" @@ -10,5 +16,31 @@ import ( ) func (c *ControllerV1) GetUser(ctx context.Context, req *v1.GetUserReq) (res *v1.GetUserRes, err error) { - return nil, gerror.NewCode(gcode.CodeNotImplemented) + bizctx := service.BizCtx().Get(ctx) + if bizctx == nil || bizctx.User == nil { // 正常情况下不会出现 + g.Log().Error(ctx, service.BizCtx().Get(ctx)) + err = gerror.NewCode(gcode.CodeUnknown, "bizctx or bizctx.User is nil") + } + user := bizctx.User + res = &v1.GetUserRes{ + ID: user.Id, + Name: user.Name, + Email: user.Email, + Role: user.Role, + Poll: v1.UserPoll{ + Points: v1.UserPollPoints{ + Total: user.Poll.Points, + Approve: user.Poll.Accept, + Reject: user.Poll.Reject, + NeedModify: user.Poll.NeedEdited, + }, + Count: user.Poll.Points / gconv.Int(service.User().GetUserPollPointsByUserRole(ctx, user.Role)), // TODO: 稍后换成数据库 Count + Score: user.Poll.Score, + CreatedAt: user.Poll.CreatedAt, + UpdatedAt: user.Poll.UpdatedAt, + }, + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + return } diff --git a/internal/logic/bizctx/bizctx.go b/internal/logic/bizctx/bizctx.go new file mode 100644 index 0000000..f954fbf --- /dev/null +++ b/internal/logic/bizctx/bizctx.go @@ -0,0 +1,44 @@ +package bizctx + +import ( + "context" + + "github.com/hitokoto-osc/reviewer/internal/service" + + "github.com/gogf/gf/v2/net/ghttp" + "github.com/hitokoto-osc/reviewer/internal/consts" + "github.com/hitokoto-osc/reviewer/internal/model" +) + +type sBizCtx struct{} + +func init() { + service.RegisterBizCtx(New()) +} + +func New() service.IBizCtx { + return &sBizCtx{} +} + +// Init initializes and injects custom business context object into request context. +func (s *sBizCtx) Init(r *ghttp.Request, customCtx *model.Context) { + r.SetCtxVar(consts.ContextKey, customCtx) +} + +// Get retrieves and returns the user object from context. +// It returns nil if nothing found in given context. +func (s *sBizCtx) Get(ctx context.Context) *model.Context { + value := ctx.Value(consts.ContextKey) + if value == nil { + return nil + } + if localCtx, ok := value.(*model.Context); ok { + return localCtx + } + return nil +} + +// SetUser injects business user object into context. +func (s *sBizCtx) SetUser(ctx context.Context, ctxUser *model.ContextUser) { + s.Get(ctx).User = ctxUser +} diff --git a/internal/logic/logic.go b/internal/logic/logic.go index 363c3e8..b214c93 100644 --- a/internal/logic/logic.go +++ b/internal/logic/logic.go @@ -5,6 +5,7 @@ package logic import ( + _ "github.com/hitokoto-osc/reviewer/internal/logic/bizctx" _ "github.com/hitokoto-osc/reviewer/internal/logic/middleware" _ "github.com/hitokoto-osc/reviewer/internal/logic/user" ) diff --git a/internal/logic/middleware/auth.go b/internal/logic/middleware/auth.go new file mode 100644 index 0000000..7a3db88 --- /dev/null +++ b/internal/logic/middleware/auth.go @@ -0,0 +1,74 @@ +package middleware + +import ( + "net/http" + "strings" + + "github.com/gogf/gf/v2/errors/gerror" + + "github.com/hitokoto-osc/reviewer/internal/model" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/hitokoto-osc/reviewer/internal/consts" + "github.com/hitokoto-osc/reviewer/internal/service" +) + +// AuthorizationV1 用于 v1 接口校验用户是否登录 +// 尝试顺序 Authorization: Bearer Token -> param -> form -> body -> query -> Router +func (s *sMiddleware) AuthorizationV1(r *ghttp.Request) { + g.Log("AuthorizationV1").Debugf(r.GetCtx(), "AuthorizationV1: %s", r.GetHeader("Authorization")) + authStr := r.GetHeader("Authorization") + if authStr == "" || !strings.HasPrefix(authStr, "Bearer ") { + if v := r.Get("token"); v != nil && !v.IsNil() && strings.HasPrefix(v.String(), "Bearer ") { + authStr = v.String() + } else { + r.Response.Status = http.StatusUnauthorized + return + } + } + token := strings.Trim(strings.TrimPrefix(authStr, "Bearer "), " ") + if len(token) != consts.UserAccessTokenV1Length { + r.Response.Status = http.StatusUnauthorized + return + } + flag, err := service.User().VerifyAPIV1Token(r.GetCtx(), token) + if err != nil { + g.Log().Error(r.GetCtx(), gerror.Wrap(err, "校验用户 Token 时发生错误")) + r.Response.Status = http.StatusInternalServerError + return + } + if !flag { + r.Response.Status = http.StatusUnauthorized + return + } + // 注入用户信息到上下文 + user, err := service.User().GetUserByToken(r.GetCtx(), token) + if err != nil { + g.Log().Error(r.GetCtx(), gerror.Wrap(err, "获取用户信息时发生错误")) + } else if user == nil { + r.Response.Status = http.StatusUnauthorized + return + } + userPoll, err := service.User().GetPollUserByUserID(r.GetCtx(), user.Id) + if err != nil { + g.Log().Error(r.GetCtx(), gerror.Wrap(err, "获取用户投票信息时发生错误")) + } else if userPoll == nil { + g.Log().Error(r.GetCtx(), gerror.New("获取用户投票信息时发生错误,用户投票信息为空")) + r.Response.Status = http.StatusInternalServerError + return + } + userPattern := &model.UserPattern{ + Users: *user, + Poll: *userPoll, + Role: service.User().MustGetRoleByUser(r.GetCtx(), user), + Status: service.User().MustGetUserStatusByUser(r.GetCtx(), user), + } + service.BizCtx().SetUser(r.GetCtx(), userPattern) + r.Middleware.Next() +} + +// AuthorizationAdminV1 用于 v1 接口校验用户是否登录且是否具有管理员权限 +func (s *sMiddleware) AuthorizationAdminV1(r *ghttp.Request) { + r.Middleware.Next() +} diff --git a/internal/logic/middleware/ctx.go b/internal/logic/middleware/ctx.go new file mode 100644 index 0000000..7a7fccc --- /dev/null +++ b/internal/logic/middleware/ctx.go @@ -0,0 +1,14 @@ +package middleware + +import ( + "github.com/gogf/gf/v2/net/ghttp" + "github.com/hitokoto-osc/reviewer/internal/model" + "github.com/hitokoto-osc/reviewer/internal/service" +) + +// Ctx 用于注入业务上下文,实现单次请求中的业务数据共享 +func (s *sMiddleware) Ctx(r *ghttp.Request) { + customCtx := &model.Context{} + service.BizCtx().Init(r, customCtx) + r.Middleware.Next() +} diff --git a/internal/logic/middleware/middleware.go b/internal/logic/middleware/middleware.go index d1c98fd..2a582b1 100644 --- a/internal/logic/middleware/middleware.go +++ b/internal/logic/middleware/middleware.go @@ -2,11 +2,6 @@ package middleware import ( "net/http" - "strings" - - "github.com/hitokoto-osc/reviewer/internal/consts" - - "github.com/gogf/gf/v2/frame/g" "github.com/hitokoto-osc/reviewer/internal/service" @@ -80,37 +75,3 @@ func (s *sMiddleware) HandlerResponse(r *ghttp.Request) { TS: gtime.TimestampMilli(), }) } - -// AuthorizationV1 用于 v1 接口校验用户是否登录 -// 尝试顺序 Authorization: Bearer Token -> param -> form -> body -> query -> Router -func (s *sMiddleware) AuthorizationV1(r *ghttp.Request) { - g.Log("AuthorizationV1").Debugf(r.GetCtx(), "AuthorizationV1: %s", r.GetHeader("Authorization")) - authStr := r.GetHeader("Authorization") - if authStr == "" || !strings.HasPrefix(authStr, "Bearer ") { - if v := r.Get("token"); v != nil && !v.IsNil() && strings.HasPrefix(v.String(), "Bearer ") { - authStr = v.String() - } else { - r.Response.Status = http.StatusUnauthorized - return - } - } - token := strings.Trim(strings.TrimPrefix(authStr, "Bearer "), " ") - if len(token) != consts.UserAccessTokenV1Length { - r.Response.Status = http.StatusUnauthorized - return - } - flag, err := service.User().VerifyAPIV1Token(r.GetCtx(), token) - if err != nil { - g.Log().Panicf(r.GetCtx(), "校验用户 Token 时发生错误: %s", err.Error()) - } - if !flag { - r.Response.Status = http.StatusUnauthorized - return - } - r.Middleware.Next() -} - -// AuthorizationAdminV1 用于 v1 接口校验用户是否登录且是否具有管理员权限 -func (s *sMiddleware) AuthorizationAdminV1(r *ghttp.Request) { - r.Middleware.Next() -} diff --git a/internal/logic/user/convert.go b/internal/logic/user/convert.go new file mode 100644 index 0000000..8577283 --- /dev/null +++ b/internal/logic/user/convert.go @@ -0,0 +1,64 @@ +package user + +import ( + "context" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/hitokoto-osc/reviewer/internal/consts" + "github.com/hitokoto-osc/reviewer/internal/model/entity" +) + +func (s *sUser) GetRoleByUser(ctx context.Context, user *entity.Users) (role consts.UserRole, err error) { + if user == nil { + return consts.UserRoleGuest, gerror.New("user is nil") + } + role = consts.UserRoleUser + if user.IsReviewer == 1 { + role = consts.UserRoleReviewer + } + if user.IsAdmin == 1 { + role = consts.UserRoleAdmin + } + return +} + +func (s *sUser) MustGetRoleByUser(ctx context.Context, user *entity.Users) (role consts.UserRole) { + var err error + role, err = s.GetRoleByUser(ctx, user) + if err != nil { + g.Log("service.user.MustGetRoleByUser").Panic(ctx, err) + } + return +} + +func (s *sUser) GetUserStatusByUser(ctx context.Context, user *entity.Users) (status consts.UserStatus, err error) { + if user == nil { + return consts.UserStatusSuspended, gerror.New("user is nil") + } + status = consts.UserStatusNormal + if user.IsSuspended == 1 { + status = consts.UserStatusSuspended + } + return +} + +func (s *sUser) MustGetUserStatusByUser(ctx context.Context, user *entity.Users) (status consts.UserStatus) { + var err error + status, err = s.GetUserStatusByUser(ctx, user) + if err != nil { + g.Log("service.user.MustGetUserStatusByUser").Panic(ctx, err) + } + return +} + +func (s *sUser) GetUserPollPointsByUserRole(ctx context.Context, role consts.UserRole) (points consts.UserPollPoints) { + points = consts.UserPollPointsNormal + if role == consts.UserRoleReviewer { + points = consts.UserPollPointsReviewer + } + if role == consts.UserRoleAdmin { + points = consts.UserPollPointsAdmin + } + return +} diff --git a/internal/logic/user/user.go b/internal/logic/user/user.go index 2a085fc..4ac808a 100644 --- a/internal/logic/user/user.go +++ b/internal/logic/user/user.go @@ -4,6 +4,10 @@ import ( "context" "time" + "github.com/gogf/gf/v2/util/gconv" + "github.com/hitokoto-osc/reviewer/internal/consts" + "github.com/hitokoto-osc/reviewer/internal/model/entity" + "github.com/hitokoto-osc/reviewer/internal/service" "github.com/gogf/gf/v2/database/gdb" @@ -23,14 +27,42 @@ func New() service.IUser { // VerifyAPIV1Token 用于 v1 接口校验用户是否登录 // TODO: v2 中会使用新的用户系统,并且将会使用带有 ACL、签名的授权机制。目前的 token 机制会被废弃。 -func (s *sUser) VerifyAPIV1Token(ctx context.Context, token string) (bool, error) { - user, err := dao.Users.Ctx(ctx).Cache(gdb.CacheOption{ +func (s *sUser) VerifyAPIV1Token(ctx context.Context, token string) (flag bool, err error) { + var user *entity.Users + user, err = s.GetUserByToken(ctx, token) + if err != nil || user == nil { + return + } + if userStatus, _ := s.GetUserStatusByUser(ctx, user); userStatus != consts.UserStatusNormal { // User 必定非空,因此不用判断错误 + return + } + flag = true + return +} + +func (s *sUser) GetUserByToken(ctx context.Context, token string) (user *entity.Users, err error) { + err = dao.Users.Ctx(ctx).Cache(gdb.CacheOption{ Duration: time.Hour, // 缓存一小时 Name: "user:token:" + token, Force: false, - }).Where("token = ?", token).One() - if err != nil || user == nil { - return false, err - } - return true, nil + }).Where("token = ?", token).Scan(&user) + return +} + +func (s *sUser) GetUserByID(ctx context.Context, id uint) (user *entity.Users, err error) { + err = dao.Users.Ctx(ctx).Cache(gdb.CacheOption{ + Duration: time.Hour, // 缓存一小时 + Name: "user:id:" + gconv.String(id), + Force: false, + }).Where("id = ?", id).Scan(&user) + return +} + +func (s *sUser) GetPollUserByUserID(ctx context.Context, id uint) (user *entity.PollUsers, err error) { + err = dao.PollUsers.Ctx(ctx).Cache(gdb.CacheOption{ + Duration: time.Hour, // 缓存一小时 + Name: "user:poll:id:" + gconv.String(id), + Force: false, + }).Where("user_id = ?", id).Scan(&user) + return } diff --git a/internal/model/context.go b/internal/model/context.go new file mode 100644 index 0000000..1d6bceb --- /dev/null +++ b/internal/model/context.go @@ -0,0 +1,7 @@ +package model + +type Context struct { + User *ContextUser // User in context. +} + +type ContextUser = UserPattern diff --git a/internal/model/user.go b/internal/model/user.go new file mode 100644 index 0000000..7740a82 --- /dev/null +++ b/internal/model/user.go @@ -0,0 +1,13 @@ +package model + +import ( + "github.com/hitokoto-osc/reviewer/internal/consts" + "github.com/hitokoto-osc/reviewer/internal/model/entity" +) + +type UserPattern struct { + entity.Users + Status consts.UserStatus `json:"status" dc:"用户状态"` + Role consts.UserRole `json:"role" dc:"用户角色"` + Poll entity.PollUsers `json:"poll" dc:"用户投票信息"` +} diff --git a/internal/service/bizctx.go b/internal/service/bizctx.go new file mode 100644 index 0000000..cbc5c51 --- /dev/null +++ b/internal/service/bizctx.go @@ -0,0 +1,40 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + + "github.com/gogf/gf/v2/net/ghttp" + "github.com/hitokoto-osc/reviewer/internal/model" +) + +type ( + IBizCtx interface { + // Init initializes and injects custom business context object into request context. + Init(r *ghttp.Request, customCtx *model.Context) + // Get retrieves and returns the user object from context. + // It returns nil if nothing found in given context. + Get(ctx context.Context) *model.Context + // SetUser injects business user object into context. + SetUser(ctx context.Context, ctxUser *model.ContextUser) + } +) + +var ( + localBizCtx IBizCtx +) + +func BizCtx() IBizCtx { + if localBizCtx == nil { + panic("implement not found for interface IBizCtx, forgot register?") + } + return localBizCtx +} + +func RegisterBizCtx(i IBizCtx) { + localBizCtx = i +} diff --git a/internal/service/brictx.go b/internal/service/brictx.go new file mode 100644 index 0000000..3d70438 --- /dev/null +++ b/internal/service/brictx.go @@ -0,0 +1,8 @@ +// ================================================================================ +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +type () diff --git a/internal/service/middleware.go b/internal/service/middleware.go index 9e472bf..d38aa67 100644 --- a/internal/service/middleware.go +++ b/internal/service/middleware.go @@ -11,12 +11,15 @@ import ( type ( IMiddleware interface { - // HandlerResponse 重写了默认的 JSON 响应格式,提供统一的响应格式 - HandlerResponse(r *ghttp.Request) - // AuthorizationV1 用于 v1 接口校验用户是否登录且是否具有审核员权限 + // AuthorizationV1 用于 v1 接口校验用户是否登录 + // 尝试顺序 Authorization: Bearer Token -> param -> form -> body -> query -> Router AuthorizationV1(r *ghttp.Request) // AuthorizationAdminV1 用于 v1 接口校验用户是否登录且是否具有管理员权限 AuthorizationAdminV1(r *ghttp.Request) + // Ctx 用于注入业务上下文,实现单次请求中的业务数据共享 + Ctx(r *ghttp.Request) + // HandlerResponse 重写了默认的 JSON 响应格式,提供统一的响应格式 + HandlerResponse(r *ghttp.Request) } ) diff --git a/internal/service/user.go b/internal/service/user.go index 5f1337c..4a16d81 100644 --- a/internal/service/user.go +++ b/internal/service/user.go @@ -7,11 +7,24 @@ package service import ( "context" + + "github.com/hitokoto-osc/reviewer/internal/consts" + "github.com/hitokoto-osc/reviewer/internal/model/entity" ) type ( IUser interface { - VerifyAPIV1Token(ctx context.Context, token string) (bool, error) + GetRoleByUser(ctx context.Context, user *entity.Users) (role consts.UserRole, err error) + MustGetRoleByUser(ctx context.Context, user *entity.Users) (role consts.UserRole) + GetUserStatusByUser(ctx context.Context, user *entity.Users) (status consts.UserStatus, err error) + MustGetUserStatusByUser(ctx context.Context, user *entity.Users) (status consts.UserStatus) + GetUserPollPointsByUserRole(ctx context.Context, role consts.UserRole) (points consts.UserPollPoints) + // VerifyAPIV1Token 用于 v1 接口校验用户是否登录 + // TODO: v2 中会使用新的用户系统,并且将会使用带有 ACL、签名的授权机制。目前的 token 机制会被废弃。 + VerifyAPIV1Token(ctx context.Context, token string) (flag bool, err error) + GetUserByToken(ctx context.Context, token string) (user *entity.Users, err error) + GetUserByID(ctx context.Context, id uint) (user *entity.Users, err error) + GetPollUserByUserID(ctx context.Context, id uint) (user *entity.PollUsers, err error) } )