upgrade
This commit is contained in:
@@ -17,6 +17,7 @@ const (
|
||||
ResubmitMsg = 10107
|
||||
HashIdsDecodeError = 10108
|
||||
SignatureError = 10109
|
||||
RBACError = 10110
|
||||
|
||||
// 业务模块级错误码
|
||||
// 用户模块
|
||||
@@ -47,6 +48,8 @@ const (
|
||||
AdminModifyPersonalInfoError = 20309
|
||||
AdminMenuListError = 20310
|
||||
AdminMenuCreateError = 20311
|
||||
AdminOfflineError = 20312
|
||||
AdminDetailError = 20313
|
||||
|
||||
// 配置
|
||||
ConfigEmailError = 20401
|
||||
@@ -83,6 +86,7 @@ var codeText = map[int]string{
|
||||
ResubmitMsg: "请勿重复提交",
|
||||
HashIdsDecodeError: "ID 参数有误",
|
||||
SignatureError: "Signature Error",
|
||||
RBACError: "暂无权限,请联系管理开通权限",
|
||||
|
||||
IllegalUserName: "非法用户名",
|
||||
UserCreateError: "创建用户失败",
|
||||
@@ -109,6 +113,8 @@ var codeText = map[int]string{
|
||||
AdminModifyPersonalInfoError: "修改个人信息失败",
|
||||
AdminMenuListError: "获取管理员菜单授权列表失败",
|
||||
AdminMenuCreateError: "管理员菜单授权失败",
|
||||
AdminOfflineError: "下线管理员失败",
|
||||
AdminDetailError: "获取个人信息失败",
|
||||
|
||||
ConfigEmailError: "修改邮箱配置失败",
|
||||
ConfigSaveError: "写入配置文件失败",
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type detailResponse struct {
|
||||
Username string `json:"username"` // 用户名
|
||||
Nickname string `json:"nickname"` // 昵称
|
||||
Mobile string `json:"mobile"` // 手机号
|
||||
Username string `json:"username"` // 用户名
|
||||
Nickname string `json:"nickname"` // 昵称
|
||||
Mobile string `json:"mobile"` // 手机号
|
||||
Menu []admin_service.ListMyMenuData `json:"menu"` // 菜单栏
|
||||
}
|
||||
|
||||
// Detail 管理员详情
|
||||
@@ -38,15 +43,29 @@ func (h *handler) Detail() core.HandlerFunc {
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
code.AdminDetailError,
|
||||
code.Text(code.AdminDetailError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
menuCacheData, err := h.cache.Get(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(searchOneData.Id)+":menu", cache.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminDetailError,
|
||||
code.Text(code.AdminDetailError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
var menuData []admin_service.ListMyMenuData
|
||||
_ = json.Unmarshal([]byte(menuCacheData), &menuData)
|
||||
|
||||
res.Username = info.Username
|
||||
res.Nickname = info.Nickname
|
||||
res.Mobile = info.Mobile
|
||||
res.Menu = menuData
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ package admin_handler
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
|
||||
|
||||
@@ -28,6 +30,7 @@ type listData struct {
|
||||
Nickname string `json:"nickname"` // 昵称
|
||||
Mobile string `json:"mobile"` // 手机号
|
||||
IsUsed int `json:"is_used"` // 是否启用 1:是 -1:否
|
||||
IsOnline int `json:"is_online"` // 是否在线 1:是 -1:否
|
||||
CreatedAt string `json:"created_at"` // 创建时间
|
||||
CreatedUser string `json:"created_user"` // 创建人
|
||||
UpdatedAt string `json:"updated_at"` // 更新时间
|
||||
@@ -117,6 +120,11 @@ func (h *handler) List() core.HandlerFunc {
|
||||
h.logger.Info("hashids err", zap.Error(err))
|
||||
}
|
||||
|
||||
isOnline := -1
|
||||
if h.cache.Exists(configs.RedisKeyPrefixLoginUser + password.GenerateLoginToken(v.Id)) {
|
||||
isOnline = 1
|
||||
}
|
||||
|
||||
data := listData{
|
||||
Id: cast.ToInt(v.Id),
|
||||
HashID: hashId,
|
||||
@@ -124,6 +132,7 @@ func (h *handler) List() core.HandlerFunc {
|
||||
Nickname: v.Nickname,
|
||||
Mobile: v.Mobile,
|
||||
IsUsed: cast.ToInt(v.IsUsed),
|
||||
IsOnline: isOnline,
|
||||
CreatedAt: v.CreatedAt.Format(time_parse.CSTLayout),
|
||||
CreatedUser: v.CreatedUser,
|
||||
UpdatedAt: v.UpdatedAt.Format(time_parse.CSTLayout),
|
||||
|
||||
@@ -5,14 +5,14 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
)
|
||||
|
||||
type loginRequest struct {
|
||||
@@ -77,8 +77,60 @@ func (h *handler) Login() core.HandlerFunc {
|
||||
// 用户信息
|
||||
adminJsonInfo, _ := json.Marshal(info)
|
||||
|
||||
// 记录 Redis 中
|
||||
err = h.cache.Set(h.adminService.CacheKeyPrefix()+token, string(adminJsonInfo), time.Hour*24, cache.WithTrace(c.Trace()))
|
||||
// 将用户信息记录到 Redis 中
|
||||
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token, string(adminJsonInfo), time.Hour*24, cache.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
searchMenuData := new(admin_service.SearchMyMenuData)
|
||||
searchMenuData.AdminId = info.Id
|
||||
menu, err := h.adminService.MyMenu(c, searchMenuData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 菜单栏信息
|
||||
menuJsonInfo, _ := json.Marshal(menu)
|
||||
|
||||
// 将菜单栏信息记录到 Redis 中
|
||||
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":menu", string(menuJsonInfo), time.Hour*24, cache.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
searchActionData := new(admin_service.SearchMyActionData)
|
||||
searchActionData.AdminId = info.Id
|
||||
action, err := h.adminService.MyAction(c, searchActionData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 可访问接口信息
|
||||
actionJsonInfo, _ := json.Marshal(action)
|
||||
|
||||
// 将可访问接口信息记录到 Redis 中
|
||||
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":action", string(actionJsonInfo), time.Hour*24, cache.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
|
||||
@@ -3,14 +3,12 @@ package admin_handler
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cast"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
)
|
||||
|
||||
type logoutResponse struct {
|
||||
@@ -31,7 +29,7 @@ func (h *handler) Logout() core.HandlerFunc {
|
||||
res := new(logoutResponse)
|
||||
res.Username = c.UserName()
|
||||
|
||||
if !h.cache.Del(h.adminService.CacheKeyPrefix()+password.GenerateLoginToken(cast.ToInt32(c.UserID())), cache.WithTrace(c.Trace())) {
|
||||
if !h.cache.Del(configs.RedisKeyPrefixLoginUser+c.GetHeader(configs.LoginToken), cache.WithTrace(c.Trace())) {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLogOutError,
|
||||
|
||||
70
internal/api/controller/admin_handler/func_offline.go
Executable file
70
internal/api/controller/admin_handler/func_offline.go
Executable file
@@ -0,0 +1,70 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type offlineRequest struct {
|
||||
Id string `form:"id"` // 主键ID
|
||||
}
|
||||
|
||||
type offlineResponse struct {
|
||||
Id int32 `json:"id"` // 主键ID
|
||||
}
|
||||
|
||||
// Offline 下线管理员
|
||||
// @Summary 下线管理员
|
||||
// @Description 下线管理员
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Success 200 {object} offlineResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/offline [patch]
|
||||
func (h *handler) Offline() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(offlineRequest)
|
||||
res := new(offlineResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
id := int32(ids[0])
|
||||
|
||||
b := h.cache.Del(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(id), cache.WithTrace(c.Trace()))
|
||||
if !b {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminOfflineError,
|
||||
code.Text(code.AdminOfflineError)),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = id
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,11 @@ type Handler interface {
|
||||
// @Router /api/admin/{id} [delete]
|
||||
Delete() core.HandlerFunc
|
||||
|
||||
// Offline 下线管理员
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/offline [patch]
|
||||
Offline() core.HandlerFunc
|
||||
|
||||
// UpdateUsed 更新管理员为启用/禁用
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/used [patch]
|
||||
|
||||
@@ -60,8 +60,8 @@ func (h *handler) Email() core.HandlerFunc {
|
||||
MailUser: req.User,
|
||||
MailPass: req.Pass,
|
||||
MailTo: req.To,
|
||||
Subject: fmt.Sprintf("%s[%s] 邮箱告警人调整通知。", configs.ProjectName(), env.Active().Value()),
|
||||
Body: fmt.Sprintf("%s[%s] 已添加您为系统告警通知人。", configs.ProjectName(), env.Active().Value()),
|
||||
Subject: fmt.Sprintf("%s[%s] 邮箱告警人调整通知。", configs.ProjectName, env.Active().Value()),
|
||||
Body: fmt.Sprintf("%s[%s] 已添加您为系统告警通知人。", configs.ProjectName, env.Active().Value()),
|
||||
}
|
||||
if err := mail.Send(options); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
|
||||
@@ -20,6 +20,7 @@ type listData struct {
|
||||
Link string `json:"link"` // 链接地址
|
||||
Icon string `json:"icon"` // 图标
|
||||
IsUsed int32 `json:"is_used"` // 是否启用 1=启用 -1=禁用
|
||||
Sort int32 `json:"sort"` // 排序
|
||||
}
|
||||
|
||||
type listResponse struct {
|
||||
@@ -64,6 +65,7 @@ func (h *handler) List() core.HandlerFunc {
|
||||
Link: v.Link,
|
||||
Icon: v.Icon,
|
||||
IsUsed: v.IsUsed,
|
||||
Sort: v.Sort,
|
||||
}
|
||||
|
||||
res.List[k] = data
|
||||
|
||||
69
internal/api/controller/menu_handler/func_updatesort.go
Executable file
69
internal/api/controller/menu_handler/func_updatesort.go
Executable file
@@ -0,0 +1,69 @@
|
||||
package menu_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type updateSortRequest struct {
|
||||
Id string `form:"id"` // HashId
|
||||
Sort int32 `form:"sort"` // 排序
|
||||
}
|
||||
|
||||
type updateSortResponse struct {
|
||||
Id int32 `json:"id"` // 主键ID
|
||||
}
|
||||
|
||||
// UpdateSort 更新菜单排序
|
||||
// @Summary 更新菜单排序
|
||||
// @Description 更新菜单排序
|
||||
// @Tags API.menu
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param sort formData int true "排序"
|
||||
// @Success 200 {object} updateSortResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/menu/sort [patch]
|
||||
func (h *handler) UpdateSort() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(updateSortRequest)
|
||||
res := new(updateSortResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ids, err := h.hashids.HashidsDecode(req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.HashIdsDecodeError,
|
||||
code.Text(code.HashIdsDecodeError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
id := int32(ids[0])
|
||||
|
||||
err = h.menuService.UpdateSort(c, id, req.Sort)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.MenuUpdateError,
|
||||
code.Text(code.MenuUpdateError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = id
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ type updateUsedResponse struct {
|
||||
// @Summary 更新菜单为启用/禁用
|
||||
// @Description 更新菜单为启用/禁用
|
||||
// @Tags API.menu
|
||||
// @Accept json
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param used formData int true "是否启用 1:是 -1:否"
|
||||
|
||||
@@ -36,6 +36,11 @@ type Handler interface {
|
||||
// @Router /api/menu/used [patch]
|
||||
UpdateUsed() core.HandlerFunc
|
||||
|
||||
// UpdateSort 更新菜单排序
|
||||
// @Tags API.menu
|
||||
// @Router /api/menu/sort [patch]
|
||||
UpdateSort() core.HandlerFunc
|
||||
|
||||
// List 菜单列表
|
||||
// @Tags API.menu
|
||||
// @Router /api/menu [get]
|
||||
|
||||
@@ -377,6 +377,49 @@ func (qb *menuRepoQueryBuilder) OrderByLevel(asc bool) *menuRepoQueryBuilder {
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *menuRepoQueryBuilder) WhereSort(p db_repo.Predicate, value int32) *menuRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "sort", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *menuRepoQueryBuilder) WhereSortIn(value []int32) *menuRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "sort", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *menuRepoQueryBuilder) WhereSortNotIn(value []int32) *menuRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "sort", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *menuRepoQueryBuilder) OrderBySort(asc bool) *menuRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "sort "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *menuRepoQueryBuilder) WhereIsUsed(p db_repo.Predicate, value int32) *menuRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
|
||||
@@ -11,6 +11,7 @@ type Menu struct {
|
||||
Link string // 链接地址
|
||||
Icon string // 图标
|
||||
Level int32 // 菜单类型 1:一级菜单 2:二级菜单
|
||||
Sort int32 // 排序
|
||||
IsUsed int32 // 是否启用 1:是 -1:否
|
||||
IsDeleted int32 // 是否删除 1:是 -1:否
|
||||
CreatedAt time.Time `gorm:"time"` // 创建时间
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
| 4 | link | 链接地址 | varchar(100) | | NO | | |
|
||||
| 5 | icon | 图标 | varchar(60) | | NO | | |
|
||||
| 6 | level | 菜单类型 1:一级菜单 2:二级菜单 | tinyint(1) unsigned | | NO | | 1 |
|
||||
| 7 | is_used | 是否启用 1:是 -1:否 | tinyint(1) | | NO | | 1 |
|
||||
| 8 | is_deleted | 是否删除 1:是 -1:否 | tinyint(1) | | NO | | -1 |
|
||||
| 9 | created_at | 创建时间 | timestamp | | NO | | CURRENT_TIMESTAMP |
|
||||
| 10 | created_user | 创建人 | varchar(60) | | NO | | |
|
||||
| 11 | updated_at | 更新时间 | timestamp | | NO | on update CURRENT_TIMESTAMP | CURRENT_TIMESTAMP |
|
||||
| 12 | updated_user | 更新人 | varchar(60) | | NO | | |
|
||||
| 7 | sort | 排序 | int(11) unsigned | | NO | | 0 |
|
||||
| 8 | is_used | 是否启用 1:是 -1:否 | tinyint(1) | | NO | | 1 |
|
||||
| 9 | is_deleted | 是否删除 1:是 -1:否 | tinyint(1) | | NO | | -1 |
|
||||
| 10 | created_at | 创建时间 | timestamp | | NO | | CURRENT_TIMESTAMP |
|
||||
| 11 | created_user | 创建人 | varchar(60) | | NO | | |
|
||||
| 12 | updated_at | 更新时间 | timestamp | | NO | on update CURRENT_TIMESTAMP | CURRENT_TIMESTAMP |
|
||||
| 13 | updated_user | 更新人 | varchar(60) | | NO | | |
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/menu_action_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
@@ -10,12 +10,8 @@ import (
|
||||
|
||||
var _ Service = (*service)(nil)
|
||||
|
||||
// 定义缓存前缀
|
||||
var cacheKeyPrefix = configs.ProjectName() + ":admin:"
|
||||
|
||||
type Service interface {
|
||||
i()
|
||||
CacheKeyPrefix() (pre string)
|
||||
|
||||
Create(ctx core.Context, adminData *CreateAdminData) (id int32, err error)
|
||||
PageList(ctx core.Context, searchData *SearchData) (listData []*admin_repo.Admin, err error)
|
||||
@@ -29,6 +25,8 @@ type Service interface {
|
||||
|
||||
CreateMenu(ctx core.Context, menuData *CreateMenuData) (err error)
|
||||
ListMenu(ctx core.Context, searchData *SearchListMenuData) (menuData []ListMenuData, err error)
|
||||
MyMenu(ctx core.Context, searchData *SearchMyMenuData) (menuData []ListMyMenuData, err error)
|
||||
MyAction(ctx core.Context, searchData *SearchMyActionData) (actionData []*menu_action_repo.MenuAction, err error)
|
||||
}
|
||||
|
||||
type service struct {
|
||||
@@ -44,8 +42,3 @@ func New(db db.Repo, cache cache.Repo) Service {
|
||||
}
|
||||
|
||||
func (s *service) i() {}
|
||||
|
||||
func (s *service) CacheKeyPrefix() (pre string) {
|
||||
pre = cacheKeyPrefix
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
@@ -21,6 +22,6 @@ func (s *service) Delete(ctx core.Context, id int32) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
s.cache.Del(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func (s *service) ListMenu(ctx core.Context, searchData *SearchListMenuData) (me
|
||||
menuQb := menu_repo.NewQueryBuilder()
|
||||
menuQb.WhereIsDeleted(db_repo.EqualPredicate, -1)
|
||||
menuListData, err := menuQb.
|
||||
OrderById(false).
|
||||
OrderBySort(true).
|
||||
QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
@@ -21,6 +22,6 @@ func (s *service) ModifyPassword(ctx core.Context, id int32, newPassword string)
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
s.cache.Del(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
|
||||
45
internal/api/service/admin_service/service_myaction.go
Normal file
45
internal/api/service/admin_service/service_myaction.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_menu_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/menu_action_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
type SearchMyActionData struct {
|
||||
AdminId int32 `json:"admin_id"` // 管理员ID
|
||||
}
|
||||
|
||||
func (s *service) MyAction(ctx core.Context, searchData *SearchMyActionData) (actionData []*menu_action_repo.MenuAction, err error) {
|
||||
adminMenuQb := admin_menu_repo.NewQueryBuilder()
|
||||
if searchData.AdminId != 0 {
|
||||
adminMenuQb.WhereAdminId(db_repo.EqualPredicate, searchData.AdminId)
|
||||
}
|
||||
|
||||
adminMenuListData, err := adminMenuQb.
|
||||
OrderById(false).
|
||||
QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(adminMenuListData) <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var menuIds []int32
|
||||
for _, v := range adminMenuListData {
|
||||
menuIds = append(menuIds, v.MenuId)
|
||||
}
|
||||
|
||||
actionQb := menu_action_repo.NewQueryBuilder()
|
||||
actionQb.WhereIsDeleted(db_repo.EqualPredicate, -1)
|
||||
actionQb.WhereMenuIdIn(menuIds)
|
||||
actionData, err = actionQb.QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
69
internal/api/service/admin_service/service_mymenu.go
Normal file
69
internal/api/service/admin_service/service_mymenu.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_menu_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/menu_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
type SearchMyMenuData struct {
|
||||
AdminId int32 `json:"admin_id"` // 管理员ID
|
||||
}
|
||||
|
||||
type ListMyMenuData struct {
|
||||
Id int32 `json:"id"` // ID
|
||||
Pid int32 `json:"pid"` // 父类ID
|
||||
Name string `json:"name"` // 菜单名称
|
||||
Link string `json:"link"` // 链接地址
|
||||
Icon string `json:"icon"` // 图标
|
||||
}
|
||||
|
||||
func (s *service) MyMenu(ctx core.Context, searchData *SearchMyMenuData) (menuData []ListMyMenuData, err error) {
|
||||
adminMenuQb := admin_menu_repo.NewQueryBuilder()
|
||||
if searchData.AdminId != 0 {
|
||||
adminMenuQb.WhereAdminId(db_repo.EqualPredicate, searchData.AdminId)
|
||||
}
|
||||
|
||||
adminMenuListData, err := adminMenuQb.
|
||||
OrderById(false).
|
||||
QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(adminMenuListData) <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
menuQb := menu_repo.NewQueryBuilder()
|
||||
menuQb.WhereIsDeleted(db_repo.EqualPredicate, -1)
|
||||
menuListData, err := menuQb.
|
||||
OrderBySort(true).
|
||||
QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(menuListData) <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, menuAllV := range menuListData {
|
||||
for _, v := range adminMenuListData {
|
||||
if menuAllV.Id == v.MenuId {
|
||||
data := ListMyMenuData{
|
||||
Id: menuAllV.Id,
|
||||
Pid: menuAllV.Pid,
|
||||
Name: menuAllV.Name,
|
||||
Link: menuAllV.Link,
|
||||
Icon: menuAllV.Icon,
|
||||
}
|
||||
|
||||
menuData = append(menuData, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
@@ -21,6 +22,6 @@ func (s *service) ResetPassword(ctx core.Context, id int32) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
s.cache.Del(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
@@ -21,6 +22,6 @@ func (s *service) UpdateUsed(ctx core.Context, id int32, used int32) (err error)
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
s.cache.Del(configs.RedisKeyPrefixLoginUser+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package authorized_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_api_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
@@ -11,9 +10,6 @@ import (
|
||||
|
||||
var _ Service = (*service)(nil)
|
||||
|
||||
// 定义缓存前缀
|
||||
var cacheKeyPrefix = configs.ProjectName() + ":authorized:"
|
||||
|
||||
type Service interface {
|
||||
i()
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package authorized_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_api_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
@@ -25,6 +26,6 @@ func (s *service) CreateAPI(ctx core.Context, authorizedAPIData *CreateAuthorize
|
||||
return 0, err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+authorizedAPIData.BusinessKey, cache.WithTrace(ctx.Trace()))
|
||||
s.cache.Del(configs.RedisKeyPrefixSignature+authorizedAPIData.BusinessKey, cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package authorized_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
@@ -32,6 +33,6 @@ func (s *service) Delete(ctx core.Context, id int32) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+authorizedInfo.BusinessKey, cache.WithTrace(ctx.Trace()))
|
||||
s.cache.Del(configs.RedisKeyPrefixSignature+authorizedInfo.BusinessKey, cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package authorized_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_api_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
@@ -32,6 +33,6 @@ func (s *service) DeleteAPI(ctx core.Context, id int32) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+authorizedApiInfo.BusinessKey, cache.WithTrace(ctx.Trace()))
|
||||
s.cache.Del(configs.RedisKeyPrefixSignature+authorizedApiInfo.BusinessKey, cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_api_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
|
||||
@@ -26,7 +27,7 @@ type cacheApiData struct {
|
||||
|
||||
func (s *service) DetailByKey(ctx core.Context, key string) (cacheData *CacheAuthorizedData, err error) {
|
||||
// 查询缓存
|
||||
cacheKey := cacheKeyPrefix + key
|
||||
cacheKey := configs.RedisKeyPrefixSignature + key
|
||||
value, err := s.cache.Get(cacheKey, cache.WithTrace(ctx.RequestContext().Trace))
|
||||
|
||||
cacheData = new(CacheAuthorizedData)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package authorized_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
@@ -31,6 +32,6 @@ func (s *service) UpdateUsed(ctx core.Context, id int32, used int32) (err error)
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+authorizedInfo.BusinessKey, cache.WithTrace(ctx.Trace()))
|
||||
s.cache.Del(configs.RedisKeyPrefixSignature+authorizedInfo.BusinessKey, cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package menu_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/menu_action_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/menu_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
@@ -11,17 +10,14 @@ import (
|
||||
|
||||
var _ Service = (*service)(nil)
|
||||
|
||||
// 定义缓存前缀
|
||||
var cacheKeyPrefix = configs.ProjectName() + ":admin:"
|
||||
|
||||
type Service interface {
|
||||
i()
|
||||
CacheKeyPrefix() (pre string)
|
||||
|
||||
Create(ctx core.Context, menuData *CreateMenuData) (id int32, err error)
|
||||
Modify(ctx core.Context, id int32, menuData *UpdateMenuData) (err error)
|
||||
List(ctx core.Context, searchData *SearchData) (listData []*menu_repo.Menu, err error)
|
||||
UpdateUsed(ctx core.Context, id int32, used int32) (err error)
|
||||
UpdateSort(ctx core.Context, id int32, sort int32) (err error)
|
||||
Delete(ctx core.Context, id int32) (err error)
|
||||
Detail(ctx core.Context, searchOneData *SearchOneData) (info *menu_repo.Menu, err error)
|
||||
|
||||
@@ -43,8 +39,3 @@ func New(db db.Repo, cache cache.Repo) Service {
|
||||
}
|
||||
|
||||
func (s *service) i() {}
|
||||
|
||||
func (s *service) CacheKeyPrefix() (pre string) {
|
||||
pre = cacheKeyPrefix
|
||||
return
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ func (s *service) List(ctx core.Context, searchData *SearchData) (listData []*me
|
||||
}
|
||||
|
||||
listData, err = qb.
|
||||
OrderById(false).
|
||||
OrderBySort(true).
|
||||
QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
23
internal/api/service/menu_service/service_updatesort.go
Normal file
23
internal/api/service/menu_service/service_updatesort.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package menu_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/menu_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
func (s *service) UpdateSort(ctx core.Context, id int32, sort int32) (err error) {
|
||||
data := map[string]interface{}{
|
||||
"sort": sort,
|
||||
"updated_user": ctx.UserName(),
|
||||
}
|
||||
|
||||
qb := menu_repo.NewQueryBuilder()
|
||||
qb.WhereId(db_repo.EqualPredicate, id)
|
||||
err = qb.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
2
internal/pkg/cache/redis.go
vendored
2
internal/pkg/cache/redis.go
vendored
@@ -4,11 +4,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/trace"
|
||||
|
||||
"github.com/go-redis/redis/v7"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Option func(*option)
|
||||
|
||||
@@ -111,11 +111,11 @@ type Context interface {
|
||||
// SetHeader 设置 Header
|
||||
SetHeader(key, value string)
|
||||
|
||||
// UserID 获取 JWT 中 UserID
|
||||
// UserID 获取 UserID
|
||||
UserID() int64
|
||||
setUserID(userID int64)
|
||||
|
||||
// UserName 获取 JWT 中 UserName
|
||||
// UserName 获取 UserName
|
||||
UserName() string
|
||||
setUserName(userName string)
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
}
|
||||
|
||||
fmt.Println(color.Blue(_UI))
|
||||
fmt.Println(color.Green(fmt.Sprintf("* [register port %s]", configs.ProjectPort())))
|
||||
fmt.Println(color.Green(fmt.Sprintf("* [register port %s]", configs.ProjectPort)))
|
||||
fmt.Println(color.Green(fmt.Sprintf("* [register env %s]", env.Active().Value())))
|
||||
|
||||
mux.engine.StaticFS("bootstrap", http.Dir("./assets/bootstrap"))
|
||||
|
||||
@@ -7,9 +7,8 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/token"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (m *middleware) Jwt(ctx core.Context) (userId int64, userName string, err errno.Error) {
|
||||
|
||||
77
internal/router/middleware/middle_rbac.go
Normal file
77
internal/router/middleware/middle_rbac.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/menu_action_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/urltable"
|
||||
)
|
||||
|
||||
func (m *middleware) RBAC() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
token := c.GetHeader("Token")
|
||||
if token == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中缺少 Token 参数")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if !m.cache.Exists(configs.RedisKeyPrefixLoginUser + token) {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("请先登录 1")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if !m.cache.Exists(configs.RedisKeyPrefixLoginUser + token + ":action") {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("请先登录 2")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
actionData, err := m.cache.Get(configs.RedisKeyPrefixLoginUser+token+":action", cache.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
var actions []menu_action_repo.MenuAction
|
||||
_ = json.Unmarshal([]byte(actionData), &actions)
|
||||
|
||||
if len(actions) > 0 {
|
||||
table := urltable.NewTable()
|
||||
for _, v := range actions {
|
||||
_ = table.Append(v.Method + v.Api)
|
||||
}
|
||||
|
||||
if pattern, _ := table.Mapping(c.Method() + c.Path()); pattern == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.RBACError,
|
||||
code.Text(code.RBACError)).WithErr(errors.New(c.Method() + c.Path() + " 未进行 RBAC 授权")),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,6 @@ import (
|
||||
)
|
||||
|
||||
func (m *middleware) Resubmit() core.HandlerFunc {
|
||||
|
||||
redisKeyPrefix := configs.ProjectName() + ":request-id:"
|
||||
|
||||
return func(c core.Context) {
|
||||
cfg := configs.Get().URLToken
|
||||
|
||||
@@ -31,7 +28,7 @@ func (m *middleware) Resubmit() core.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
redisKey := redisKeyPrefix + tokenString
|
||||
redisKey := configs.RedisKeyPrefixRequestID + tokenString
|
||||
if !m.cache.Exists(redisKey) {
|
||||
err = m.cache.Set(redisKey, "1", time.Minute*cfg.ExpireDuration)
|
||||
if err != nil {
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/signature"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/urltable"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const ttl = time.Minute * 2 // 签名超时时间 2 分钟
|
||||
@@ -23,7 +23,7 @@ var whiteListPath = map[string]bool{
|
||||
func (m *middleware) Signature() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
// 签名信息
|
||||
authorization := c.GetHeader("Authorization")
|
||||
authorization := c.GetHeader(configs.SignToken)
|
||||
if authorization == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
@@ -34,7 +34,7 @@ func (m *middleware) Signature() core.HandlerFunc {
|
||||
}
|
||||
|
||||
// 时间信息
|
||||
date := c.GetHeader("Authorization-Date")
|
||||
date := c.GetHeader(configs.SignTokenDate)
|
||||
if date == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
|
||||
@@ -4,16 +4,16 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
)
|
||||
|
||||
func (m *middleware) Token(ctx core.Context) (userId int64, userName string, err errno.Error) {
|
||||
token := ctx.GetHeader("Token")
|
||||
token := ctx.GetHeader(configs.LoginToken)
|
||||
if token == "" {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
@@ -23,7 +23,7 @@ func (m *middleware) Token(ctx core.Context) (userId int64, userName string, err
|
||||
return
|
||||
}
|
||||
|
||||
if !m.cache.Exists(m.adminService.CacheKeyPrefix() + token) {
|
||||
if !m.cache.Exists(configs.RedisKeyPrefixLoginUser + token) {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
@@ -32,7 +32,7 @@ func (m *middleware) Token(ctx core.Context) (userId int64, userName string, err
|
||||
return
|
||||
}
|
||||
|
||||
cacheData, cacheErr := m.cache.Get(m.adminService.CacheKeyPrefix()+token, cache.WithTrace(ctx.Trace()))
|
||||
cacheData, cacheErr := m.cache.Get(configs.RedisKeyPrefixLoginUser+token, cache.WithTrace(ctx.Trace()))
|
||||
if cacheErr != nil {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
|
||||
@@ -31,6 +31,9 @@ type Middleware interface {
|
||||
|
||||
// Token 签名验证,对登录用户的验证
|
||||
Token(ctx core.Context) (userId int64, userName string, err errno.Error)
|
||||
|
||||
// RBAC 权限验证
|
||||
RBAC() core.HandlerFunc
|
||||
}
|
||||
|
||||
type middleware struct {
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/metrics"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/notify"
|
||||
"github.com/xinliangnote/go-gin-api/internal/router/middleware"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errors"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/file"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -39,9 +39,9 @@ func NewHTTPServer(logger *zap.Logger) (*Server, error) {
|
||||
r := new(resource)
|
||||
r.logger = logger
|
||||
|
||||
openBrowserUri := "http://127.0.0.1" + configs.ProjectPort()
|
||||
openBrowserUri := "http://127.0.0.1" + configs.ProjectPort
|
||||
|
||||
_, ok := file.IsExists(configs.ProjectInstallFile())
|
||||
_, ok := file.IsExists(configs.ProjectInstallMark)
|
||||
if !ok { // 未安装
|
||||
openBrowserUri += "/install"
|
||||
} else { // 已安装
|
||||
|
||||
@@ -30,7 +30,7 @@ func setApiRouter(r *resource) {
|
||||
}
|
||||
|
||||
// 需要签名验证、登录验证、RBAC 权限验证
|
||||
api := r.mux.Group("/api", core.WrapAuthHandler(r.middles.Token), r.middles.Signature())
|
||||
api := r.mux.Group("/api", core.WrapAuthHandler(r.middles.Token), r.middles.Signature(), r.middles.RBAC())
|
||||
{
|
||||
// authorized
|
||||
authorizedHandler := authorized_handler.New(r.logger, r.db, r.cache)
|
||||
@@ -46,6 +46,7 @@ func setApiRouter(r *resource) {
|
||||
api.POST("/admin", adminHandler.Create())
|
||||
api.GET("/admin", adminHandler.List())
|
||||
api.PATCH("/admin/used", adminHandler.UpdateUsed())
|
||||
api.PATCH("/admin/offline", adminHandler.Offline())
|
||||
api.PATCH("/admin/reset_password/:id", core.AliasForRecordMetrics("/api/admin/reset_password"), adminHandler.ResetPassword())
|
||||
api.DELETE("/admin/:id", core.AliasForRecordMetrics("/api/admin"), adminHandler.Delete())
|
||||
|
||||
@@ -58,6 +59,7 @@ func setApiRouter(r *resource) {
|
||||
api.GET("/menu", menuHandler.List())
|
||||
api.GET("/menu/:id", core.AliasForRecordMetrics("/api/menu"), menuHandler.Detail())
|
||||
api.PATCH("/menu/used", menuHandler.UpdateUsed())
|
||||
api.PATCH("/menu/sort", menuHandler.UpdateSort())
|
||||
api.DELETE("/menu/:id", core.AliasForRecordMetrics("/api/menu"), menuHandler.Delete())
|
||||
api.POST("/menu_action", menuHandler.CreateAction())
|
||||
api.GET("/menu_action", menuHandler.ListAction())
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/env"
|
||||
|
||||
@@ -48,6 +49,8 @@ type viewResponse struct {
|
||||
Host string
|
||||
GoOS string
|
||||
GoArch string
|
||||
|
||||
ProjectVersion string
|
||||
}
|
||||
|
||||
func (h *handler) View() core.HandlerFunc {
|
||||
@@ -88,6 +91,7 @@ func (h *handler) View() core.HandlerFunc {
|
||||
obj.Env = env.Active().Value()
|
||||
obj.GoOS = runtime.GOOS
|
||||
obj.GoArch = runtime.GOARCH
|
||||
obj.ProjectVersion = configs.ProjectVersion
|
||||
|
||||
c.HTML("dashboard", obj)
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ func (h *handler) Execute() core.HandlerFunc {
|
||||
outPutString += "初始化 MySQL 数据表:admin_menu 默认数据成功。\n"
|
||||
|
||||
// 生成 install 完成标识
|
||||
f, err := os.Create(configs.ProjectInstallFile())
|
||||
f, err := os.Create(configs.ProjectInstallMark)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
|
||||
@@ -7,6 +7,7 @@ package mysql_table
|
||||
//`link` varchar(100) NOT NULL DEFAULT '' COMMENT '链接地址',
|
||||
//`icon` varchar(60) NOT NULL DEFAULT '' COMMENT '图标',
|
||||
//`level` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '菜单类型 1:一级菜单 2:二级菜单',
|
||||
//`sort` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '排序',
|
||||
//`is_used` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否启用 1:是 -1:否',
|
||||
//`is_deleted` tinyint(1) NOT NULL DEFAULT '-1' COMMENT '是否删除 1:是 -1:否',
|
||||
//`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
@@ -24,6 +25,7 @@ func CreateMenuTableSql() (sql string) {
|
||||
sql += "`link` varchar(100) NOT NULL DEFAULT '' COMMENT '链接地址',"
|
||||
sql += "`icon` varchar(60) NOT NULL DEFAULT '' COMMENT '图标',"
|
||||
sql += "`level` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '菜单类型 1:一级菜单 2:二级菜单',"
|
||||
sql += "`sort` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '排序',"
|
||||
sql += "`is_used` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否启用 1:是 -1:否',"
|
||||
sql += "`is_deleted` tinyint(1) NOT NULL DEFAULT '-1' COMMENT '是否删除 1:是 -1:否',"
|
||||
sql += "`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',"
|
||||
@@ -37,29 +39,29 @@ func CreateMenuTableSql() (sql string) {
|
||||
}
|
||||
|
||||
func CreateMenuTableDataSql() (sql string) {
|
||||
sql = "INSERT INTO `menu` (`id`, `pid`, `name`, `link`, `icon`, `level`, `created_user`) VALUES"
|
||||
sql += "(1, 0, '配置信息', '', 'mdi-settings-box', 1, 'init'),"
|
||||
sql += "(2, 1, '告警邮箱', '/config/email', '', 2, 'init'),"
|
||||
sql += "(3, 1, '错误码', '/config/code', '', 2, 'init'),"
|
||||
sql += "(4, 0, '代码生成器', '', 'mdi-code-not-equal-variant', 1, 'init'),"
|
||||
sql += "(5, 4, '生成数据表 CURD', '/generator/gorm', '', 2, 'init'),"
|
||||
sql += "(6, 4, '生成控制器方法', '/generator/handler', '', 2, 'init'),"
|
||||
sql += "(7, 0, '授权调用方', '', 'mdi-playlist-check', 1, 'init'),"
|
||||
sql += "(8, 7, '调用方', '/authorized/list', '', 2, 'init'),"
|
||||
sql += "(9, 7, '使用说明', '/authorized/demo', '', 2, 'init'),"
|
||||
sql += "(10, 0, '系统管理员', '', 'mdi-account', 1, 'init'),"
|
||||
sql += "(11, 10, '管理员', '/admin/list', '', 2, 'init'),"
|
||||
sql += "(12, 10, '菜单管理', '/admin/menu', '', 2, 'init'),"
|
||||
sql += "(13, 0, '查询小助手', '', 'mdi-database-search', 1, 'init'),"
|
||||
sql += "(14, 13, '查询缓存', '/tool/cache', '', 2, 'init'),"
|
||||
sql += "(15, 13, '查询数据', '/tool/data', '', 2, 'init'),"
|
||||
sql += "(16, 0, '实用工具箱', '', 'mdi-tools', 1, 'init'),"
|
||||
sql += "(17, 16, 'Hashids', '/tool/hashids', '', 2, 'init'),"
|
||||
sql += "(18, 16, '调用日志', '/tool/logs', '', 2, 'init'),"
|
||||
sql += "(19, 16, '接口文档', '/swagger/index.html', '', 2, 'init'),"
|
||||
sql += "(20, 16, 'GraphQL', '/graphql', '', 2, 'init'),"
|
||||
sql += "(21, 16, '接口指标', '/metrics', '', 2, 'init'),"
|
||||
sql += "(22, 16, '服务升级', '/upgrade', '', 2, 'init');"
|
||||
sql = "INSERT INTO `menu` (`id`, `pid`, `name`, `link`, `icon`, `level`, `sort`, `created_user`) VALUES"
|
||||
sql += "(1, 0, '配置信息', '', 'mdi-settings-box', 1, 1, 'init'),"
|
||||
sql += "(2, 1, '告警邮箱', '/config/email', '', 2, 11, 'init'),"
|
||||
sql += "(3, 1, '错误码', '/config/code', '', 2, 12, 'init'),"
|
||||
sql += "(4, 0, '代码生成器', '', 'mdi-code-not-equal-variant', 1, 2, 'init'),"
|
||||
sql += "(5, 4, '生成数据表 CURD', '/generator/gorm', '', 2, 21, 'init'),"
|
||||
sql += "(6, 4, '生成控制器方法', '/generator/handler', '', 2, 22, 'init'),"
|
||||
sql += "(7, 0, '授权调用方', '', 'mdi-playlist-check', 1, 3, 'init'),"
|
||||
sql += "(8, 7, '调用方', '/authorized/list', '', 2, 31, 'init'),"
|
||||
sql += "(9, 7, '使用说明', '/authorized/demo', '', 2, 32, 'init'),"
|
||||
sql += "(10, 0, '系统管理员', '', 'mdi-account', 1, 4, 'init'),"
|
||||
sql += "(11, 10, '管理员', '/admin/list', '', 2, 41, 'init'),"
|
||||
sql += "(12, 10, '菜单管理', '/admin/menu', '', 2, 42, 'init'),"
|
||||
sql += "(13, 0, '查询小助手', '', 'mdi-database-search', 1, 5, 'init'),"
|
||||
sql += "(14, 13, '查询缓存', '/tool/cache', '', 2, 51, 'init'),"
|
||||
sql += "(15, 13, '查询数据', '/tool/data', '', 2, 52, 'init'),"
|
||||
sql += "(16, 0, '实用工具箱', '', 'mdi-tools', 1, 6, 'init'),"
|
||||
sql += "(17, 16, 'Hashids', '/tool/hashids', '', 2, 62, 'init'),"
|
||||
sql += "(18, 16, '调用日志', '/tool/logs', '', 2, 63, 'init'),"
|
||||
sql += "(19, 16, '接口文档', '/swagger/index.html', '', 2, 64, 'init'),"
|
||||
sql += "(20, 16, 'GraphQL', '/graphql', '', 2, 65, 'init'),"
|
||||
sql += "(21, 16, '接口指标', '/metrics', '', 2, 66, 'init'),"
|
||||
sql += "(22, 16, '服务升级', '/upgrade', '', 2, 61, 'init');"
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -70,7 +70,9 @@ func CreateMenuActionTableDataSql() (sql string) {
|
||||
sql += "(34, 12, 'GET', '/api/menu_action', 'init'),"
|
||||
sql += "(35, 12, 'POST', '/api/menu_action', 'init'),"
|
||||
sql += "(36, 12, 'DELETE', '/api/menu_action/*', 'init'),"
|
||||
sql += "(37, 22, 'POST', '/upgrade/execute', 'init');"
|
||||
sql += "(37, 22, 'POST', '/upgrade/execute', 'init'),"
|
||||
sql += "(38, 11, 'PATCH', '/api/admin/offline', 'init'),"
|
||||
sql += "(39, 12, 'PATCH', '/api/menu/sort', 'init');"
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ func (h *handler) LogsView() core.HandlerFunc {
|
||||
}
|
||||
|
||||
return func(c core.Context) {
|
||||
readLineFromEnd, err := file.NewReadLineFromEnd(configs.ProjectLogFile())
|
||||
readLineFromEnd, err := file.NewReadLineFromEnd(configs.ProjectLogFile)
|
||||
if err != nil {
|
||||
h.logger.Error("NewReadLineFromEnd err", zap.Error(err))
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ import (
|
||||
)
|
||||
|
||||
type upgradeViewResponse struct {
|
||||
List []upgradeViewData `json:"list"`
|
||||
LockFile string `json:"lock_file"`
|
||||
List []upgradeViewData `json:"list"`
|
||||
}
|
||||
|
||||
type upgradeViewData struct {
|
||||
@@ -68,6 +69,7 @@ func (h *handler) UpgradeView() core.HandlerFunc {
|
||||
|
||||
obj := new(upgradeViewResponse)
|
||||
obj.List = tableData
|
||||
obj.LockFile = configs.ProjectInstallMark
|
||||
c.HTML("upgrade_view", obj)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user