mirror of
https://github.com/xinliangnote/go-gin-api.git
synced 2024-04-21 12:31:46 +00:00
# 22 add web - admin/login
This commit is contained in:
@@ -16,22 +16,35 @@ const (
|
||||
ResubmitError = 10106
|
||||
ResubmitMsg = 10107
|
||||
HashIdsDecodeError = 10108
|
||||
SignatureError = 10109
|
||||
|
||||
// 模块级错误码 - 用户模块
|
||||
// 业务模块级错误码
|
||||
// 用户模块
|
||||
IllegalUserName = 20101
|
||||
UserCreateError = 20102
|
||||
UserUpdateError = 20103
|
||||
UserSearchError = 20104
|
||||
|
||||
// 授权调用方
|
||||
AuthorizedCreateError = 30101
|
||||
AuthorizedListError = 30102
|
||||
AuthorizedDeleteError = 30103
|
||||
AuthorizedUpdateError = 30104
|
||||
AuthorizedDetailError = 30105
|
||||
AuthorizedCreateAPIError = 30106
|
||||
AuthorizedListAPIError = 30107
|
||||
AuthorizedDeleteAPIError = 30108
|
||||
AuthorizedCreateError = 20201
|
||||
AuthorizedListError = 20202
|
||||
AuthorizedDeleteError = 20203
|
||||
AuthorizedUpdateError = 20204
|
||||
AuthorizedDetailError = 20205
|
||||
AuthorizedCreateAPIError = 20206
|
||||
AuthorizedListAPIError = 20207
|
||||
AuthorizedDeleteAPIError = 20208
|
||||
|
||||
// 管理员
|
||||
AdminCreateError = 20301
|
||||
AdminListError = 20302
|
||||
AdminDeleteError = 20303
|
||||
AdminUpdateError = 20304
|
||||
AdminResetPasswordError = 20305
|
||||
AdminLoginError = 20307
|
||||
AdminLogOutError = 20308
|
||||
AdminModifyPasswordError = 20309
|
||||
AdminModifyPersonalInfoError = 20310
|
||||
)
|
||||
|
||||
var codeText = map[int]string{
|
||||
@@ -43,6 +56,7 @@ var codeText = map[int]string{
|
||||
ResubmitError: "Resubmit Error",
|
||||
ResubmitMsg: "请勿重复提交",
|
||||
HashIdsDecodeError: "ID 参数有误",
|
||||
SignatureError: "Signature Error",
|
||||
|
||||
IllegalUserName: "非法用户名",
|
||||
UserCreateError: "创建用户失败",
|
||||
@@ -57,6 +71,16 @@ var codeText = map[int]string{
|
||||
AuthorizedCreateAPIError: "创建调用方API地址失败",
|
||||
AuthorizedListAPIError: "获取调用方API地址列表失败",
|
||||
AuthorizedDeleteAPIError: "删除调用方API地址失败",
|
||||
|
||||
AdminCreateError: "创建管理员失败",
|
||||
AdminListError: "获取管理员列表页失败",
|
||||
AdminDeleteError: "删除管理员失败",
|
||||
AdminUpdateError: "更新管理员失败",
|
||||
AdminResetPasswordError: "重置密码失败",
|
||||
AdminLoginError: "登录失败",
|
||||
AdminLogOutError: "退出失败",
|
||||
AdminModifyPasswordError: "修改密码失败",
|
||||
AdminModifyPersonalInfoError: "修改个人信息失败",
|
||||
}
|
||||
|
||||
func Text(code int) string {
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"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/pkg/errno"
|
||||
)
|
||||
|
||||
type createRequest struct {
|
||||
Username string `form:"username"` // 用户名
|
||||
Nickname string `form:"nickname"` // 昵称
|
||||
Mobile string `form:"mobile"` // 手机号
|
||||
Password string `form:"password"` // 密码
|
||||
}
|
||||
|
||||
type createResponse struct {
|
||||
Id int32 `json:"id"` // 主键ID
|
||||
}
|
||||
|
||||
// Create 新增管理员
|
||||
// @Summary 新增管理员
|
||||
// @Description 新增管理员
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param username formData string true "用户名"
|
||||
// @Param nickname formData string true "昵称"
|
||||
// @Param mobile formData string true "手机号"
|
||||
// @Param password formData string true "密码"
|
||||
// @Success 200 {object} createResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin [post]
|
||||
func (h *handler) Create() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(createRequest)
|
||||
res := new(createResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
createData := new(admin_service.CreateAdminData)
|
||||
createData.Nickname = req.Nickname
|
||||
createData.Username = req.Username
|
||||
createData.Mobile = req.Mobile
|
||||
createData.Password = req.Password
|
||||
|
||||
id, err := h.adminService.Create(c, createData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminCreateError,
|
||||
code.Text(code.AdminCreateError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = id
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package admin_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 deleteRequest struct {
|
||||
Id string `uri:"id"` // HashID
|
||||
}
|
||||
|
||||
type deleteResponse struct {
|
||||
Id int32 `json:"id"` // 主键ID
|
||||
}
|
||||
|
||||
// Delete 删除管理员
|
||||
// @Summary 删除管理员
|
||||
// @Description 删除管理员
|
||||
// @Tags API.admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "hashId"
|
||||
// @Success 200 {object} deleteResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/{id} [delete]
|
||||
func (h *handler) Delete() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(deleteRequest)
|
||||
res := new(deleteResponse)
|
||||
if err := c.ShouldBindURI(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.adminService.Delete(c, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminDeleteError,
|
||||
code.Text(code.AdminDeleteError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = id
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"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/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type detailResponse struct {
|
||||
Username string `json:"username"` // 用户名
|
||||
Nickname string `json:"nickname"` // 昵称
|
||||
Mobile string `json:"mobile"` // 手机号
|
||||
}
|
||||
|
||||
// Detail 管理员详情
|
||||
// @Summary 管理员详情
|
||||
// @Description 管理员详情
|
||||
// @Tags API.admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} detailResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/info [get]
|
||||
func (h *handler) Detail() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
res := new(detailResponse)
|
||||
|
||||
searchOneData := new(admin_service.SearchOneData)
|
||||
searchOneData.Id = cast.ToInt32(c.UserID())
|
||||
searchOneData.IsUsed = 1
|
||||
|
||||
info, err := h.adminService.Detail(c, searchOneData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Username = info.Username
|
||||
res.Nickname = info.Nickname
|
||||
res.Mobile = info.Mobile
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"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/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type listRequest struct {
|
||||
Page int `form:"page"` // 第几页
|
||||
PageSize int `form:"page_size"` // 每页显示条数
|
||||
Username string `form:"username"` // 用户名
|
||||
Nickname string `form:"nickname"` // 昵称
|
||||
Mobile string `form:"mobile"` // 手机号
|
||||
}
|
||||
|
||||
type listData struct {
|
||||
Id int `json:"id"` // ID
|
||||
HashID string `json:"hashid"` // hashid
|
||||
Username string `json:"username"` // 用户名
|
||||
Nickname string `json:"nickname"` // 昵称
|
||||
Mobile string `json:"mobile"` // 手机号
|
||||
IsUsed int `json:"is_used"` // 是否启用 1:是 -1:否
|
||||
CreatedAt string `json:"created_at"` // 创建时间
|
||||
CreatedUser string `json:"created_user"` // 创建人
|
||||
UpdatedAt string `json:"updated_at"` // 更新时间
|
||||
UpdatedUser string `json:"updated_user"` // 更新人
|
||||
}
|
||||
|
||||
type listResponse struct {
|
||||
List []listData `json:"list"`
|
||||
Pagination struct {
|
||||
Total int `json:"total"`
|
||||
CurrentPage int `json:"current_page"`
|
||||
PrePageCount int `json:"pre_page_count"`
|
||||
} `json:"pagination"`
|
||||
}
|
||||
|
||||
// List 管理员列表
|
||||
// @Summary 管理员列表
|
||||
// @Description 管理员列表
|
||||
// @Tags API.admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "第几页"
|
||||
// @Param page_size query string false "每页显示条数"
|
||||
// @Param username query string false "用户名"
|
||||
// @Param nickname query string false "昵称"
|
||||
// @Param mobile query string false "手机号"
|
||||
// @Success 200 {object} listResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin [get]
|
||||
func (h *handler) List() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(listRequest)
|
||||
res := new(listResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
page := req.Page
|
||||
if page == 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
pageSize := req.PageSize
|
||||
if pageSize == 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
|
||||
searchData := new(admin_service.SearchData)
|
||||
searchData.Page = page
|
||||
searchData.PageSize = pageSize
|
||||
searchData.Username = req.Username
|
||||
searchData.Nickname = req.Nickname
|
||||
searchData.Mobile = req.Mobile
|
||||
|
||||
resListData, err := h.adminService.PageList(c, searchData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminListError,
|
||||
code.Text(code.AdminListError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
resCountData, err := h.adminService.PageListCount(c, searchData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminListError,
|
||||
code.Text(code.AdminListError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
res.Pagination.Total = cast.ToInt(resCountData)
|
||||
res.Pagination.PrePageCount = pageSize
|
||||
res.Pagination.CurrentPage = page
|
||||
res.List = make([]listData, len(resListData))
|
||||
|
||||
for k, v := range resListData {
|
||||
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
|
||||
if err != nil {
|
||||
h.logger.Info("hashids err", zap.Error(err))
|
||||
}
|
||||
|
||||
data := listData{
|
||||
Id: cast.ToInt(v.Id),
|
||||
HashID: hashId,
|
||||
Username: v.Username,
|
||||
Nickname: v.Nickname,
|
||||
Mobile: v.Mobile,
|
||||
IsUsed: cast.ToInt(v.IsUsed),
|
||||
CreatedAt: v.CreatedAt.Format(time_parse.CSTLayout),
|
||||
CreatedUser: v.CreatedUser,
|
||||
UpdatedAt: v.UpdatedAt.Format(time_parse.CSTLayout),
|
||||
UpdatedUser: v.UpdatedUser,
|
||||
}
|
||||
|
||||
res.List[k] = data
|
||||
}
|
||||
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
type loginRequest struct {
|
||||
Username string `form:"username"` // 用户名
|
||||
Password string `form:"password"` // 密码
|
||||
}
|
||||
|
||||
type loginResponse struct {
|
||||
Token string `json:"token"` // 用户身份标识
|
||||
}
|
||||
|
||||
// Login 管理员登录
|
||||
// @Summary 管理员登录
|
||||
// @Description 管理员登录
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param username formData string true "用户名"
|
||||
// @Param password formData string true "密码"
|
||||
// @Success 200 {object} loginResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/login [post]
|
||||
func (h *handler) Login() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(loginRequest)
|
||||
res := new(loginResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
searchOneData := new(admin_service.SearchOneData)
|
||||
searchOneData.Username = req.Username
|
||||
searchOneData.Password = password.GeneratePassword(req.Password)
|
||||
searchOneData.IsUsed = 1
|
||||
|
||||
info, err := h.adminService.Detail(c, searchOneData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if info == nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLoginError,
|
||||
code.Text(code.AdminLoginError)).WithErr(errors.New("未查询出符合条件的用户")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
token := password.GenerateLoginToken(info.Id)
|
||||
|
||||
// 用户信息
|
||||
adminJsonInfo, _ := json.Marshal(info)
|
||||
|
||||
// 记录 Redis 中
|
||||
err = h.cache.Set(h.adminService.CacheKeyPrefix()+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
|
||||
}
|
||||
|
||||
res.Token = token
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
type logoutResponse struct {
|
||||
Username string `json:"username"` // 用户账号
|
||||
}
|
||||
|
||||
// Logout 管理员登出
|
||||
// @Summary 管理员登出
|
||||
// @Description 管理员登出
|
||||
// @Tags API.admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} logoutResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/login [post]
|
||||
func (h *handler) Logout() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
res := new(logoutResponse)
|
||||
res.Username = c.UserName()
|
||||
|
||||
if !h.cache.Del(h.adminService.CacheKeyPrefix()+password.GenerateLoginToken(cast.ToInt32(c.UserID())), cache.WithTrace(c.Trace())) {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminLogOutError,
|
||||
code.Text(code.AdminLogOutError)).WithErr(errors.New("cache del err")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"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/spf13/cast"
|
||||
)
|
||||
|
||||
type modifyPasswordRequest struct {
|
||||
OldPassword string `form:"old_password"` // 旧密码
|
||||
NewPassword string `form:"new_password"` // 新密码
|
||||
}
|
||||
|
||||
type modifyPasswordResponse struct {
|
||||
Username string `json:"username"` // 用户账号
|
||||
}
|
||||
|
||||
// ModifyPassword 修改密码
|
||||
// @Summary 修改密码
|
||||
// @Description 修改密码
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param old_password formData string true "旧密码"
|
||||
// @Param new_password formData string true "新密码"
|
||||
// @Success 200 {object} modifyPasswordResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/modify_password [patch]
|
||||
func (h *handler) ModifyPassword() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(modifyPasswordRequest)
|
||||
res := new(modifyPasswordResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
userId := cast.ToInt32(c.UserID())
|
||||
|
||||
searchOneData := new(admin_service.SearchOneData)
|
||||
searchOneData.Id = userId
|
||||
searchOneData.Password = password.GeneratePassword(req.OldPassword)
|
||||
searchOneData.IsUsed = 1
|
||||
|
||||
info, err := h.adminService.Detail(c, searchOneData)
|
||||
if err != nil || info == nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminModifyPasswordError,
|
||||
code.Text(code.AdminModifyPasswordError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.adminService.ModifyPassword(c, userId, req.NewPassword); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminModifyPasswordError,
|
||||
code.Text(code.AdminModifyPasswordError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Username = c.UserName()
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"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/pkg/errno"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type modifyPersonalInfoRequest struct {
|
||||
Nickname string `form:"nickname"` // 昵称
|
||||
Mobile string `form:"mobile"` // 手机号
|
||||
}
|
||||
|
||||
type modifyPersonalInfoResponse struct {
|
||||
Username string `json:"username"` // 用户账号
|
||||
}
|
||||
|
||||
// ModifyPersonalInfo 修改个人信息
|
||||
// @Summary 修改个人信息
|
||||
// @Description 修改个人信息
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param nickname formData string true "昵称"
|
||||
// @Param mobile formData string true "手机号"
|
||||
// @Success 200 {object} modifyPersonalInfoResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/modify_password [patch]
|
||||
func (h *handler) ModifyPersonalInfo() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(modifyPersonalInfoRequest)
|
||||
res := new(modifyPersonalInfoResponse)
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
userId := cast.ToInt32(c.UserID())
|
||||
|
||||
modifyData := new(admin_service.ModifyData)
|
||||
modifyData.Nickname = req.Nickname
|
||||
modifyData.Mobile = req.Mobile
|
||||
|
||||
if err := h.adminService.ModifyPersonalInfo(c, userId, modifyData); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminModifyPersonalInfoError,
|
||||
code.Text(code.AdminModifyPersonalInfoError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Username = c.UserName()
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package admin_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 resetPasswordRequest struct {
|
||||
Id string `uri:"id"` // HashID
|
||||
}
|
||||
|
||||
type resetPasswordResponse struct {
|
||||
Id int32 `json:"id"` // 主键ID
|
||||
}
|
||||
|
||||
// ResetPassword 重置密码
|
||||
// @Summary 重置密码
|
||||
// @Description 重置密码
|
||||
// @Tags API.admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "hashId"
|
||||
// @Success 200 {object} resetPasswordResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/reset_password/{id} [patch]
|
||||
func (h *handler) ResetPassword() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(resetPasswordRequest)
|
||||
res := new(resetPasswordResponse)
|
||||
if err := c.ShouldBindURI(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.adminService.ResetPassword(c, id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminResetPasswordError,
|
||||
code.Text(code.AdminResetPasswordError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = id
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package admin_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 updateUsedRequest struct {
|
||||
Id string `form:"id"` // 主键ID
|
||||
Used int32 `form:"used"` // 是否启用 1:是 -1:否
|
||||
}
|
||||
|
||||
type updateUsedResponse struct {
|
||||
Id int32 `json:"id"` // 主键ID
|
||||
}
|
||||
|
||||
// UpdateUsed 更新管理员为启用/禁用
|
||||
// @Summary 更新管理员为启用/禁用
|
||||
// @Description 更新管理员为启用/禁用
|
||||
// @Tags API.admin
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param used formData int true "是否启用 1:是 -1:否"
|
||||
// @Success 200 {object} updateUsedResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/admin/used [patch]
|
||||
func (h *handler) UpdateUsed() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(updateUsedRequest)
|
||||
res := new(updateUsedResponse)
|
||||
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.adminService.UpdateUsed(c, id, req.Used)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AdminUpdateError,
|
||||
code.Text(code.AdminUpdateError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = id
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"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/db"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/hash"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ Handler = (*handler)(nil)
|
||||
|
||||
type Handler interface {
|
||||
i()
|
||||
|
||||
// Login 管理员登录
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/login [post]
|
||||
Login() core.HandlerFunc
|
||||
|
||||
// Logout 管理员登出
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/logout [post]
|
||||
Logout() core.HandlerFunc
|
||||
|
||||
// ModifyPassword 修改密码
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/modify_password [patch]
|
||||
ModifyPassword() core.HandlerFunc
|
||||
|
||||
// Detail 个人信息
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/info [get]
|
||||
Detail() core.HandlerFunc
|
||||
|
||||
// ModifyPersonalInfo 修改个人信息
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/modify_personal_info [patch]
|
||||
ModifyPersonalInfo() core.HandlerFunc
|
||||
|
||||
// Create 新增管理员
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin [post]
|
||||
Create() core.HandlerFunc
|
||||
|
||||
// List 管理员列表
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin [get]
|
||||
List() core.HandlerFunc
|
||||
|
||||
// Delete 删除管理员
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/{id} [delete]
|
||||
Delete() core.HandlerFunc
|
||||
|
||||
// UpdateUsed 更新管理员为启用/禁用
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/used [patch]
|
||||
UpdateUsed() core.HandlerFunc
|
||||
|
||||
// ResetPassword 重置密码
|
||||
// @Tags API.admin
|
||||
// @Router /api/admin/reset_password/{id} [patch]
|
||||
ResetPassword() core.HandlerFunc
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
logger *zap.Logger
|
||||
cache cache.Repo
|
||||
hashids hash.Hash
|
||||
adminService admin_service.Service
|
||||
}
|
||||
|
||||
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
|
||||
return &handler{
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
hashids: hash.New(configs.Get().HashIds.Secret, configs.Get().HashIds.Length),
|
||||
adminService: admin_service.New(db, cache),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) i() {}
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
)
|
||||
|
||||
type createRequest struct {
|
||||
BusinessKey string `json:"business_key"` // 调用方key
|
||||
BusinessDeveloper string `json:"business_developer"` // 调用方对接人
|
||||
Remark string `json:"remark"` // 备注
|
||||
BusinessKey string `form:"business_key"` // 调用方key
|
||||
BusinessDeveloper string `form:"business_developer"` // 调用方对接人
|
||||
Remark string `form:"remark"` // 备注
|
||||
}
|
||||
|
||||
type createResponse struct {
|
||||
@@ -23,9 +23,11 @@ type createResponse struct {
|
||||
// @Summary 新增调用方
|
||||
// @Description 新增调用方
|
||||
// @Tags API.authorized
|
||||
// @Accept json
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param Request body createRequest true "请求信息"
|
||||
// @Param business_key formData string true "调用方key"
|
||||
// @Param business_developer formData string true "调用方对接人"
|
||||
// @Param remark formData string true "备注"
|
||||
// @Success 200 {object} createResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized [post]
|
||||
@@ -33,7 +35,7 @@ func (h *handler) Create() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(createRequest)
|
||||
res := new(createResponse)
|
||||
if err := c.ShouldBindJSON(req); err != nil {
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
)
|
||||
|
||||
type createAPIRequest struct {
|
||||
Id string `json:"id"` // HashID
|
||||
Method string `json:"method"` // 请求方法
|
||||
API string `json:"api"` // 请求地址
|
||||
Id string `form:"id"` // HashID
|
||||
Method string `form:"method"` // 请求方法
|
||||
API string `form:"api"` // 请求地址
|
||||
}
|
||||
|
||||
type createAPIResponse struct {
|
||||
@@ -23,9 +23,11 @@ type createAPIResponse struct {
|
||||
// @Summary 授权调用方接口地址
|
||||
// @Description 授权调用方接口地址
|
||||
// @Tags API.authorized
|
||||
// @Accept json
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param Request body createAPIRequest true "请求信息"
|
||||
// @Param id formData string true "HashID"
|
||||
// @Param method formData string true "请求方法"
|
||||
// @Param api formData string true "请求地址"
|
||||
// @Success 200 {object} createAPIResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized_api [post]
|
||||
@@ -33,7 +35,7 @@ func (h *handler) CreateAPI() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(createAPIRequest)
|
||||
res := new(createAPIResponse)
|
||||
if err := c.ShouldBindJSON(req); err != nil {
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
|
||||
@@ -22,7 +22,7 @@ type deleteAPIResponse struct {
|
||||
// @Tags API.authorized
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "主键ID"
|
||||
// @Param id path string true "主键ID"
|
||||
// @Success 200 {object} deleteAPIResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized_api/{id} [delete]
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
)
|
||||
|
||||
type updateUsedRequest struct {
|
||||
Id string `json:"id"` // 主键ID
|
||||
Used int32 `json:"used"` // 是否启用 1:是 -1:否
|
||||
Id string `form:"id"` // 主键ID
|
||||
Used int32 `form:"used"` // 是否启用 1:是 -1:否
|
||||
}
|
||||
|
||||
type updateUsedResponse struct {
|
||||
@@ -21,9 +21,10 @@ type updateUsedResponse struct {
|
||||
// @Summary 更新调用方为启用/禁用
|
||||
// @Description 更新调用方为启用/禁用
|
||||
// @Tags API.authorized
|
||||
// @Accept json
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param Request body updateUsedRequest true "请求信息"
|
||||
// @Param id formData string true "Hashid"
|
||||
// @Param used formData int true "是否启用 1:是 -1:否"
|
||||
// @Success 200 {object} updateUsedResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /api/authorized/used [patch]
|
||||
@@ -31,7 +32,7 @@ func (h *handler) UpdateUsed() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(updateUsedRequest)
|
||||
res := new(updateUsedResponse)
|
||||
if err := c.ShouldBindJSON(req); err != nil {
|
||||
if err := c.ShouldBindForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
|
||||
+583
@@ -0,0 +1,583 @@
|
||||
///////////////////////////////////////////////////////////
|
||||
// THIS FILE IS AUTO GENERATED by gormgen, DON'T EDIT IT //
|
||||
// ANY CHANGES DONE HERE WILL BE LOST //
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
package admin_repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func NewModel() *Admin {
|
||||
return new(Admin)
|
||||
}
|
||||
|
||||
func NewQueryBuilder() *adminRepoQueryBuilder {
|
||||
return new(adminRepoQueryBuilder)
|
||||
}
|
||||
|
||||
func (t *Admin) Create(db *gorm.DB) (id int32, err error) {
|
||||
if err = db.Create(t).Error; err != nil {
|
||||
return 0, errors.Wrap(err, "create err")
|
||||
}
|
||||
return t.Id, nil
|
||||
}
|
||||
|
||||
func (t *Admin) Delete(db *gorm.DB) (err error) {
|
||||
if err = db.Delete(t).Error; err != nil {
|
||||
return errors.Wrap(err, "delete err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Admin) Updates(db *gorm.DB, m map[string]interface{}) (err error) {
|
||||
if err = db.Model(&Admin{}).Where("id = ?", t.Id).Updates(m).Error; err != nil {
|
||||
return errors.Wrap(err, "updates err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type adminRepoQueryBuilder struct {
|
||||
order []string
|
||||
where []struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}
|
||||
limit int
|
||||
offset int
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) buildQuery(db *gorm.DB) *gorm.DB {
|
||||
ret := db
|
||||
for _, where := range qb.where {
|
||||
ret = ret.Where(where.prefix, where.value)
|
||||
}
|
||||
for _, order := range qb.order {
|
||||
ret = ret.Order(order)
|
||||
}
|
||||
ret = ret.Limit(qb.limit).Offset(qb.offset)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) Count(db *gorm.DB) (int64, error) {
|
||||
var c int64
|
||||
res := qb.buildQuery(db).Model(&Admin{}).Count(&c)
|
||||
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
|
||||
c = 0
|
||||
}
|
||||
return c, res.Error
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) First(db *gorm.DB) (*Admin, error) {
|
||||
ret := &Admin{}
|
||||
res := qb.buildQuery(db).First(ret)
|
||||
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
|
||||
ret = nil
|
||||
}
|
||||
return ret, res.Error
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) QueryOne(db *gorm.DB) (*Admin, error) {
|
||||
qb.limit = 1
|
||||
ret, err := qb.QueryAll(db)
|
||||
if len(ret) > 0 {
|
||||
return ret[0], err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) QueryAll(db *gorm.DB) ([]*Admin, error) {
|
||||
var ret []*Admin
|
||||
err := qb.buildQuery(db).Find(&ret).Error
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) Limit(limit int) *adminRepoQueryBuilder {
|
||||
qb.limit = limit
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) Offset(offset int) *adminRepoQueryBuilder {
|
||||
qb.offset = offset
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereId(p db_repo.Predicate, value int32) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "id", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereIdIn(value []int32) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "id", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereIdNotIn(value []int32) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "id", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderById(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "id "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereUsername(p db_repo.Predicate, value string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "username", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereUsernameIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "username", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereUsernameNotIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "username", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderByUsername(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "username "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WherePassword(p db_repo.Predicate, value string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "password", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WherePasswordIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "password", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WherePasswordNotIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "password", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderByPassword(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "password "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereNickname(p db_repo.Predicate, value string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "nickname", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereNicknameIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "nickname", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereNicknameNotIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "nickname", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderByNickname(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "nickname "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereMobile(p db_repo.Predicate, value string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "mobile", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereMobileIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "mobile", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereMobileNotIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "mobile", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderByMobile(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "mobile "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereIsUsed(p db_repo.Predicate, value int32) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "is_used", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereIsUsedIn(value []int32) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "is_used", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereIsUsedNotIn(value []int32) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "is_used", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderByIsUsed(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "is_used "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereIsDeleted(p db_repo.Predicate, value int32) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "is_deleted", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereIsDeletedIn(value []int32) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "is_deleted", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereIsDeletedNotIn(value []int32) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "is_deleted", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderByIsDeleted(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "is_deleted "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereCreatedAt(p db_repo.Predicate, value time.Time) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "created_at", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereCreatedAtIn(value []time.Time) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "created_at", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereCreatedAtNotIn(value []time.Time) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "created_at", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderByCreatedAt(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "created_at "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereCreatedUser(p db_repo.Predicate, value string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "created_user", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereCreatedUserIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "created_user", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereCreatedUserNotIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "created_user", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderByCreatedUser(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "created_user "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereUpdatedAt(p db_repo.Predicate, value time.Time) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "updated_at", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereUpdatedAtIn(value []time.Time) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "updated_at", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereUpdatedAtNotIn(value []time.Time) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "updated_at", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderByUpdatedAt(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "updated_at "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereUpdatedUser(p db_repo.Predicate, value string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "updated_user", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereUpdatedUserIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "updated_user", "IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) WhereUpdatedUserNotIn(value []string) *adminRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "updated_user", "NOT IN"),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *adminRepoQueryBuilder) OrderByUpdatedUser(asc bool) *adminRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "updated_user "+order)
|
||||
return qb
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package admin_repo
|
||||
|
||||
import "time"
|
||||
|
||||
// 管理员表
|
||||
//go:generate gormgen -structs Admin -input .
|
||||
type Admin struct {
|
||||
Id int32 // 主键
|
||||
Username string // 用户名
|
||||
Password string // 密码
|
||||
Nickname string // 昵称
|
||||
Mobile string // 手机号
|
||||
IsUsed int32 // 是否启用 1:是 -1:否
|
||||
IsDeleted int32 // 是否删除 1:是 -1:否
|
||||
CreatedAt time.Time `gorm:"time"` // 创建时间
|
||||
CreatedUser string // 创建人
|
||||
UpdatedAt time.Time `gorm:"time"` // 更新时间
|
||||
UpdatedUser string // 更新人
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#### go_gin_api.admin
|
||||
管理员表
|
||||
|
||||
| 序号 | 名称 | 描述 | 类型 | 键 | 为空 | 额外 | 默认值 |
|
||||
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
|
||||
| 1 | id | 主键 | int(11) unsigned | PRI | NO | auto_increment | |
|
||||
| 2 | username | 用户名 | varchar(32) | UNI | NO | | |
|
||||
| 3 | password | 密码 | varchar(32) | | NO | | |
|
||||
| 4 | nickname | 昵称 | varchar(60) | | NO | | |
|
||||
| 5 | mobile | 手机号 | varchar(20) | | NO | | |
|
||||
| 6 | is_used | 是否启用 1:是 -1:否 | tinyint(1) | | NO | | 1 |
|
||||
| 7 | is_deleted | 是否删除 1:是 -1:否 | tinyint(1) | | NO | | -1 |
|
||||
| 8 | created_at | 创建时间 | timestamp | | NO | | CURRENT_TIMESTAMP |
|
||||
| 9 | created_user | 创建人 | varchar(60) | | NO | | |
|
||||
| 10 | updated_at | 更新时间 | timestamp | | NO | on update CURRENT_TIMESTAMP | CURRENT_TIMESTAMP |
|
||||
| 11 | updated_user | 更新人 | varchar(60) | | NO | | |
|
||||
@@ -0,0 +1,48 @@
|
||||
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/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
)
|
||||
|
||||
var _ Service = (*service)(nil)
|
||||
|
||||
// 定义缓存前缀
|
||||
var cacheKeyPrefix = configs.ProjectName() + ":admin:"
|
||||
|
||||
type Service interface {
|
||||
i()
|
||||
CacheKeyPrefix() (pre string)
|
||||
|
||||
Create(ctx core.Context, authorizedData *CreateAdminData) (id int32, err error)
|
||||
PageList(ctx core.Context, searchData *SearchData) (listData []*admin_repo.Admin, err error)
|
||||
PageListCount(ctx core.Context, searchData *SearchData) (total int64, err error)
|
||||
UpdateUsed(ctx core.Context, id int32, used int32) (err error)
|
||||
Delete(ctx core.Context, id int32) (err error)
|
||||
Detail(ctx core.Context, searchOneData *SearchOneData) (info *admin_repo.Admin, err error)
|
||||
ResetPassword(ctx core.Context, id int32) (err error)
|
||||
ModifyPassword(ctx core.Context, id int32, newPassword string) (err error)
|
||||
ModifyPersonalInfo(ctx core.Context, id int32, modifyData *ModifyData) (err error)
|
||||
}
|
||||
|
||||
type service struct {
|
||||
db db.Repo
|
||||
cache cache.Repo
|
||||
}
|
||||
|
||||
func New(db db.Repo, cache cache.Repo) Service {
|
||||
return &service{
|
||||
db: db,
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) i() {}
|
||||
|
||||
func (s *service) CacheKeyPrefix() (pre string) {
|
||||
pre = cacheKeyPrefix
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/password"
|
||||
)
|
||||
|
||||
type CreateAdminData struct {
|
||||
Username string // 用户名
|
||||
Nickname string // 昵称
|
||||
Mobile string // 手机号
|
||||
Password string // 密码
|
||||
}
|
||||
|
||||
func (s *service) Create(ctx core.Context, adminData *CreateAdminData) (id int32, err error) {
|
||||
model := admin_repo.NewModel()
|
||||
model.Username = adminData.Username
|
||||
model.Password = password.GeneratePassword(adminData.Password)
|
||||
model.Nickname = adminData.Nickname
|
||||
model.Mobile = adminData.Mobile
|
||||
model.CreatedUser = ctx.UserName()
|
||||
model.IsUsed = 1
|
||||
model.IsDeleted = -1
|
||||
|
||||
id, err = model.Create(s.db.GetDbW().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_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/password"
|
||||
)
|
||||
|
||||
func (s *service) Delete(ctx core.Context, id int32) (err error) {
|
||||
model := admin_repo.NewModel()
|
||||
model.Id = id
|
||||
|
||||
data := map[string]interface{}{
|
||||
"is_deleted": 1,
|
||||
"updated_user": ctx.UserName(),
|
||||
}
|
||||
|
||||
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
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_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
type SearchOneData struct {
|
||||
Id int32 // 用户ID
|
||||
Username string // 用户名
|
||||
Nickname string // 昵称
|
||||
Mobile string // 手机号
|
||||
Password string // 密码
|
||||
IsUsed int32 // 是否启用 1:是 -1:否
|
||||
}
|
||||
|
||||
func (s *service) Detail(ctx core.Context, searchOneData *SearchOneData) (info *admin_repo.Admin, err error) {
|
||||
|
||||
qb := admin_repo.NewQueryBuilder()
|
||||
qb.WhereIsDeleted(db_repo.EqualPredicate, -1)
|
||||
|
||||
if searchOneData.Id != 0 {
|
||||
qb.WhereId(db_repo.EqualPredicate, searchOneData.Id)
|
||||
}
|
||||
|
||||
if searchOneData.Username != "" {
|
||||
qb.WhereUsername(db_repo.EqualPredicate, searchOneData.Username)
|
||||
}
|
||||
|
||||
if searchOneData.Nickname != "" {
|
||||
qb.WhereNickname(db_repo.EqualPredicate, searchOneData.Nickname)
|
||||
}
|
||||
|
||||
if searchOneData.Mobile != "" {
|
||||
qb.WhereMobile(db_repo.EqualPredicate, searchOneData.Mobile)
|
||||
}
|
||||
|
||||
if searchOneData.Password != "" {
|
||||
qb.WherePassword(db_repo.EqualPredicate, searchOneData.Password)
|
||||
}
|
||||
|
||||
if searchOneData.IsUsed != 0 {
|
||||
qb.WhereIsUsed(db_repo.EqualPredicate, searchOneData.IsUsed)
|
||||
}
|
||||
|
||||
info, err = qb.QueryOne(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_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/password"
|
||||
)
|
||||
|
||||
func (s *service) ModifyPassword(ctx core.Context, id int32, newPassword string) (err error) {
|
||||
model := admin_repo.NewModel()
|
||||
model.Id = id
|
||||
|
||||
data := map[string]interface{}{
|
||||
"password": password.GeneratePassword(newPassword),
|
||||
"updated_user": ctx.UserName(),
|
||||
}
|
||||
|
||||
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
type ModifyData struct {
|
||||
Nickname string // 昵称
|
||||
Mobile string // 手机号
|
||||
}
|
||||
|
||||
func (s *service) ModifyPersonalInfo(ctx core.Context, id int32, modifyData *ModifyData) (err error) {
|
||||
model := admin_repo.NewModel()
|
||||
model.Id = id
|
||||
|
||||
data := map[string]interface{}{
|
||||
"nickname": modifyData.Nickname,
|
||||
"mobile": modifyData.Mobile,
|
||||
"updated_user": ctx.UserName(),
|
||||
}
|
||||
|
||||
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
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_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
type SearchData struct {
|
||||
Page int // 第几页
|
||||
PageSize int // 每页显示条数
|
||||
Username string // 用户名
|
||||
Nickname string // 昵称
|
||||
Mobile string // 手机号
|
||||
}
|
||||
|
||||
func (s *service) PageList(ctx core.Context, searchData *SearchData) (listData []*admin_repo.Admin, err error) {
|
||||
|
||||
page := searchData.Page
|
||||
if page == 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
pageSize := searchData.PageSize
|
||||
if pageSize == 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
qb := admin_repo.NewQueryBuilder()
|
||||
qb.WhereIsDeleted(db_repo.EqualPredicate, -1)
|
||||
|
||||
if searchData.Username != "" {
|
||||
qb.WhereUsername(db_repo.EqualPredicate, searchData.Username)
|
||||
}
|
||||
|
||||
if searchData.Nickname != "" {
|
||||
qb.WhereNickname(db_repo.EqualPredicate, searchData.Nickname)
|
||||
}
|
||||
|
||||
if searchData.Mobile != "" {
|
||||
qb.WhereMobile(db_repo.EqualPredicate, searchData.Mobile)
|
||||
}
|
||||
|
||||
listData, err = qb.
|
||||
Limit(pageSize).
|
||||
Offset(offset).
|
||||
OrderById(false).
|
||||
QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
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_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
func (s *service) PageListCount(ctx core.Context, searchData *SearchData) (total int64, err error) {
|
||||
qb := admin_repo.NewQueryBuilder()
|
||||
qb = qb.WhereIsDeleted(db_repo.EqualPredicate, -1)
|
||||
|
||||
if searchData.Username != "" {
|
||||
qb.WhereUsername(db_repo.EqualPredicate, searchData.Username)
|
||||
}
|
||||
|
||||
if searchData.Nickname != "" {
|
||||
qb.WhereNickname(db_repo.EqualPredicate, searchData.Nickname)
|
||||
}
|
||||
|
||||
if searchData.Mobile != "" {
|
||||
qb.WhereMobile(db_repo.EqualPredicate, searchData.Mobile)
|
||||
}
|
||||
|
||||
total, err = qb.Count(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_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/password"
|
||||
)
|
||||
|
||||
func (s *service) ResetPassword(ctx core.Context, id int32) (err error) {
|
||||
model := admin_repo.NewModel()
|
||||
model.Id = id
|
||||
|
||||
data := map[string]interface{}{
|
||||
"password": password.ResetPassword(),
|
||||
"updated_user": ctx.UserName(),
|
||||
}
|
||||
|
||||
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+password.GenerateLoginToken(id), cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package admin_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/admin_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/password"
|
||||
)
|
||||
|
||||
func (s *service) UpdateUsed(ctx core.Context, id int32, used int32) (err error) {
|
||||
model := admin_repo.NewModel()
|
||||
model.Id = id
|
||||
|
||||
data := map[string]interface{}{
|
||||
"is_used": used,
|
||||
"updated_user": ctx.UserName(),
|
||||
}
|
||||
|
||||
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+password.GenerateLoginToken(id), 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/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"
|
||||
@@ -10,6 +11,9 @@ import (
|
||||
|
||||
var _ Service = (*service)(nil)
|
||||
|
||||
// 定义缓存前缀
|
||||
var cacheKeyPrefix = configs.ProjectName() + ":authorized:"
|
||||
|
||||
type Service interface {
|
||||
i()
|
||||
|
||||
@@ -20,6 +24,7 @@ type Service interface {
|
||||
UpdateUsed(ctx core.Context, id int32, used int32) (err error)
|
||||
Delete(ctx core.Context, id int32) (err error)
|
||||
Detail(ctx core.Context, id int32) (info *authorized_repo.Authorized, err error)
|
||||
DetailByKey(ctx core.Context, key string) (data *CacheAuthorizedData, err error)
|
||||
|
||||
CreateAPI(ctx core.Context, authorizedAPIData *CreateAuthorizedAPIData) (id int32, err error)
|
||||
ListAPI(ctx core.Context, searchAPIData *SearchAPIData) (listData []*authorized_api_repo.AuthorizedApi, err error)
|
||||
|
||||
@@ -25,7 +25,7 @@ func (s *service) Create(ctx core.Context, authorizedData *CreateAuthorizedData)
|
||||
model.BusinessSecret = secret
|
||||
model.BusinessDeveloper = authorizedData.BusinessDeveloper
|
||||
model.Remark = authorizedData.Remark
|
||||
model.CreatedUser = "system" // TODO
|
||||
model.CreatedUser = ctx.UserName()
|
||||
model.IsUsed = 1
|
||||
model.IsDeleted = -1
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package authorized_service
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -16,12 +17,14 @@ func (s *service) CreateAPI(ctx core.Context, authorizedAPIData *CreateAuthorize
|
||||
model.BusinessKey = authorizedAPIData.BusinessKey
|
||||
model.Method = authorizedAPIData.Method
|
||||
model.Api = authorizedAPIData.API
|
||||
model.CreatedUser = "system" // TODO
|
||||
model.CreatedUser = ctx.UserName()
|
||||
model.IsDeleted = -1
|
||||
|
||||
id, err = model.Create(s.db.GetDbW().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
s.cache.Del(cacheKeyPrefix+authorizedAPIData.BusinessKey, cache.WithTrace(ctx.Trace()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
package authorized_service
|
||||
|
||||
import (
|
||||
"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"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (s *service) Delete(ctx core.Context, id int32) (err error) {
|
||||
// 先查询 id 是否存在
|
||||
authorizedInfo, err := authorized_repo.NewQueryBuilder().
|
||||
WhereIsDeleted(db_repo.EqualPredicate, -1).
|
||||
WhereId(db_repo.EqualPredicate, id).
|
||||
First(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
model := authorized_repo.NewModel()
|
||||
model.Id = id
|
||||
|
||||
data := map[string]interface{}{
|
||||
"is_deleted": 1,
|
||||
"updated_user": "system", // TODO
|
||||
"updated_user": ctx.UserName(),
|
||||
}
|
||||
|
||||
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
@@ -19,5 +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()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
package authorized_service
|
||||
|
||||
import (
|
||||
"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"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (s *service) DeleteAPI(ctx core.Context, id int32) (err error) {
|
||||
// 先查询 id 是否存在
|
||||
authorizedApiInfo, err := authorized_api_repo.NewQueryBuilder().
|
||||
WhereIsDeleted(db_repo.EqualPredicate, -1).
|
||||
WhereId(db_repo.EqualPredicate, id).
|
||||
First(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
model := authorized_api_repo.NewModel()
|
||||
model.Id = id
|
||||
|
||||
data := map[string]interface{}{
|
||||
"is_deleted": 1,
|
||||
"updated_user": "system", // TODO
|
||||
"updated_user": ctx.UserName(),
|
||||
}
|
||||
|
||||
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
@@ -19,5 +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()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ import (
|
||||
|
||||
func (s *service) Detail(ctx core.Context, id int32) (info *authorized_repo.Authorized, err error) {
|
||||
qb := authorized_repo.NewQueryBuilder()
|
||||
qb = qb.WhereIsDeleted(db_repo.EqualPredicate, -1)
|
||||
|
||||
qb.WhereIsDeleted(db_repo.EqualPredicate, -1)
|
||||
qb.WhereId(db_repo.EqualPredicate, id)
|
||||
|
||||
info, err = qb.First(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package authorized_service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"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"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
// 定义缓存结构
|
||||
type CacheAuthorizedData struct {
|
||||
Key string `json:"key"` // 调用方 key
|
||||
Secret string `json:"secret"` // 调用方 secret
|
||||
IsUsed int32 `json:"is_used"` // 调用方启用状态 1=启用 -1=禁用
|
||||
Apis []cacheApiData `json:"apis"` // 调用方授权的 Apis
|
||||
}
|
||||
|
||||
type cacheApiData struct {
|
||||
Method string `json:"method"` // 请求方式
|
||||
Api string `json:"api"` // 请求地址
|
||||
}
|
||||
|
||||
func (s *service) DetailByKey(ctx core.Context, key string) (cacheData *CacheAuthorizedData, err error) {
|
||||
// 查询缓存
|
||||
cacheKey := cacheKeyPrefix + key
|
||||
value, err := s.cache.Get(cacheKey, cache.WithTrace(ctx.RequestContext().Trace))
|
||||
|
||||
cacheData = new(CacheAuthorizedData)
|
||||
if err == nil && json.Unmarshal([]byte(value), cacheData) == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 查询调用方信息
|
||||
authorizedInfo, err := authorized_repo.NewQueryBuilder().
|
||||
WhereIsDeleted(db_repo.EqualPredicate, -1).
|
||||
WhereBusinessKey(db_repo.EqualPredicate, key).
|
||||
First(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 查询调用方授权 API 信息
|
||||
authorizedApiInfo, err := authorized_api_repo.NewQueryBuilder().
|
||||
WhereIsDeleted(db_repo.EqualPredicate, -1).
|
||||
WhereBusinessKey(db_repo.EqualPredicate, key).
|
||||
OrderById(false).
|
||||
QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置缓存 data
|
||||
cacheData = new(CacheAuthorizedData)
|
||||
cacheData.Key = key
|
||||
cacheData.Secret = authorizedInfo.BusinessSecret
|
||||
cacheData.IsUsed = authorizedInfo.IsUsed
|
||||
cacheData.Apis = make([]cacheApiData, len(authorizedApiInfo))
|
||||
|
||||
for k, v := range authorizedApiInfo {
|
||||
data := cacheApiData{
|
||||
Method: v.Method,
|
||||
Api: v.Api,
|
||||
}
|
||||
cacheData.Apis[k] = data
|
||||
}
|
||||
|
||||
cacheDataByte, _ := json.Marshal(cacheData)
|
||||
|
||||
err = s.cache.Set(cacheKey, string(cacheDataByte), 0, cache.WithTrace(ctx.Trace()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,17 +1,30 @@
|
||||
package authorized_service
|
||||
|
||||
import (
|
||||
"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"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (s *service) UpdateUsed(ctx core.Context, id int32, used int32) (err error) {
|
||||
authorizedInfo, err := authorized_repo.NewQueryBuilder().
|
||||
WhereIsDeleted(db_repo.EqualPredicate, -1).
|
||||
WhereId(db_repo.EqualPredicate, id).
|
||||
First(s.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
model := authorized_repo.NewModel()
|
||||
model.Id = id
|
||||
|
||||
data := map[string]interface{}{
|
||||
"is_used": used,
|
||||
"updated_user": "system", // TODO
|
||||
"updated_user": ctx.UserName(),
|
||||
}
|
||||
|
||||
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
@@ -19,5 +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()))
|
||||
return
|
||||
}
|
||||
|
||||
Vendored
+20
-5
@@ -33,7 +33,7 @@ type Repo interface {
|
||||
TTL(key string) (time.Duration, error)
|
||||
Expire(key string, ttl time.Duration) bool
|
||||
ExpireAt(key string, ttl time.Time) bool
|
||||
Del(keys ...string) bool
|
||||
Del(key string, options ...Option) bool
|
||||
Exists(keys ...string) bool
|
||||
Incr(key string, options ...Option) int64
|
||||
Close() error
|
||||
@@ -158,13 +158,28 @@ func (c *cacheRepo) Exists(keys ...string) bool {
|
||||
return value > 0
|
||||
}
|
||||
|
||||
// Del del some key from redis
|
||||
func (c *cacheRepo) Del(keys ...string) bool {
|
||||
if len(keys) == 0 {
|
||||
func (c *cacheRepo) Del(key string, options ...Option) bool {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "del"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
if key == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
value, _ := c.client.Del(keys...).Result()
|
||||
value, _ := c.client.Del(key).Result()
|
||||
return value > 0
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
_ "github.com/xinliangnote/go-gin-api/docs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/browser"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/color"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/env"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
@@ -48,6 +49,7 @@ type option struct {
|
||||
recordMetrics RecordMetrics
|
||||
enableCors bool
|
||||
enableRate bool
|
||||
enableOpenBrowser string
|
||||
}
|
||||
|
||||
// OnPanicNotify 发生panic时通知用
|
||||
@@ -93,6 +95,13 @@ func WithRecordMetrics(record RecordMetrics) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnableOpenBrowser 启动后在浏览器中打开 uri
|
||||
func WithEnableOpenBrowser(uri string) Option {
|
||||
return func(opt *option) {
|
||||
opt.enableOpenBrowser = uri
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnableCors 开启CORS
|
||||
func WithEnableCors() Option {
|
||||
return func(opt *option) {
|
||||
@@ -311,6 +320,11 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
}))
|
||||
}
|
||||
|
||||
if opt.enableOpenBrowser != "" {
|
||||
_ = browser.Open(opt.enableOpenBrowser)
|
||||
fmt.Println(color.Green("* [register open browser '" + opt.enableOpenBrowser + "']"))
|
||||
}
|
||||
|
||||
// recover两次,防止处理时发生panic,尤其是在OnPanicNotify中。
|
||||
mux.engine.Use(func(ctx *gin.Context) {
|
||||
defer func() {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package password
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const salt = "qkhPAGA13HocW3GAEWwb"
|
||||
|
||||
const defaultPassword = "123456"
|
||||
|
||||
func GeneratePassword(str string) (password string) {
|
||||
// md5
|
||||
m := md5.New()
|
||||
m.Write([]byte(str))
|
||||
mByte := m.Sum(nil)
|
||||
|
||||
// hmac
|
||||
h := hmac.New(sha256.New, []byte(salt))
|
||||
h.Write(mByte)
|
||||
password = hex.EncodeToString(h.Sum(nil))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ResetPassword() (password string) {
|
||||
m := md5.New()
|
||||
m.Write([]byte(defaultPassword))
|
||||
mStr := hex.EncodeToString(m.Sum(nil))
|
||||
|
||||
password = GeneratePassword(mStr)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func GenerateLoginToken(id int32) (token string) {
|
||||
m := md5.New()
|
||||
m.Write([]byte(fmt.Sprintf("%d%s", id, salt)))
|
||||
token = hex.EncodeToString(m.Sum(nil))
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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/signature"
|
||||
|
||||
"github.com/koketama/urltable"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const ttl = time.Minute * 2 // 签名超时时间 2 分钟
|
||||
|
||||
var whiteListPath = map[string]bool{
|
||||
"/login/web": true,
|
||||
}
|
||||
|
||||
func (m *middleware) Signature() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
// 签名信息
|
||||
authorization := c.GetHeader("Authorization")
|
||||
if authorization == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.SignatureError,
|
||||
code.Text(code.SignatureError)).WithErr(errors.New("Header 中缺少 Authorization 参数")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 时间信息
|
||||
date := c.GetHeader("Authorization-Date")
|
||||
if date == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.SignatureError,
|
||||
code.Text(code.SignatureError)).WithErr(errors.New("Header 中缺少 Date 参数")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 通过签名信息获取 key
|
||||
authorizationSplit := strings.Split(authorization, " ")
|
||||
if len(authorizationSplit) < 2 {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.SignatureError,
|
||||
code.Text(code.SignatureError)).WithErr(errors.New("Header 中 Authorization 格式错误")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
key := authorizationSplit[0]
|
||||
|
||||
data, err := m.authorizedService.DetailByKey(c, key)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.SignatureError,
|
||||
code.Text(code.SignatureError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证 cache 是否被调用
|
||||
if data.IsUsed == -1 {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.SignatureError,
|
||||
code.Text(code.SignatureError)).WithErr(errors.New(key + " 已被禁止调用")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if len(data.Apis) < 1 {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.SignatureError,
|
||||
code.Text(code.SignatureError)).WithErr(errors.New(key + " 未进行接口授权")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if !whiteListPath[c.Path()] {
|
||||
// 验证 c.Method() + c.Path() 是否授权
|
||||
table := urltable.NewTable()
|
||||
for _, v := range data.Apis {
|
||||
_ = table.Append(v.Method + v.Api)
|
||||
}
|
||||
|
||||
if pattern, _ := table.Mapping(c.Method() + c.Path()); pattern == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.SignatureError,
|
||||
code.Text(code.SignatureError)).WithErr(errors.New(c.Method() + c.Path() + " 未进行接口授权")),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ok, err := signature.New(key, data.Secret, ttl).Verify(authorization, date, c.Path(), c.Method(), c.RequestInputParams())
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.SignatureError,
|
||||
code.Text(code.SignatureError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if !ok {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.SignatureError,
|
||||
code.Text(code.SignatureError)).WithErr(errors.New("Header 中 Authorization 信息错误")),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func (m *middleware) Token(ctx core.Context) (userId int64, userName string, err errno.Error) {
|
||||
token := ctx.GetHeader("Token")
|
||||
if token == "" {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中缺少 Token 参数"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !m.cache.Exists(m.adminService.CacheKeyPrefix() + token) {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("请先登录"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
cacheData, cacheErr := m.cache.Get(m.adminService.CacheKeyPrefix()+token, cache.WithTrace(ctx.Trace()))
|
||||
if cacheErr != nil {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(cacheErr)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type userInfo struct {
|
||||
Id int64 `json:"id"` // 用户ID
|
||||
Username string `json:"username"` // 用户名
|
||||
}
|
||||
|
||||
var userData userInfo
|
||||
_ = json.Unmarshal([]byte(cacheData), &userData)
|
||||
|
||||
userId = userData.Id
|
||||
userName = userData.Username
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/admin_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_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/db"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"go.uber.org/zap"
|
||||
@@ -22,17 +25,29 @@ type Middleware interface {
|
||||
|
||||
// DisableLog 不记录日志
|
||||
DisableLog() core.HandlerFunc
|
||||
|
||||
// Signature 签名验证,对用签名算法 pkg/signature
|
||||
Signature() core.HandlerFunc
|
||||
|
||||
// Token 签名验证,对登录用户的验证
|
||||
Token(ctx core.Context) (userId int64, userName string, err errno.Error)
|
||||
}
|
||||
|
||||
type middleware struct {
|
||||
logger *zap.Logger
|
||||
cache cache.Repo
|
||||
logger *zap.Logger
|
||||
cache cache.Repo
|
||||
db db.Repo
|
||||
authorizedService authorized_service.Service
|
||||
adminService admin_service.Service
|
||||
}
|
||||
|
||||
func New(logger *zap.Logger, cache cache.Repo) Middleware {
|
||||
func New(logger *zap.Logger, cache cache.Repo, db db.Repo) Middleware {
|
||||
return &middleware{
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
db: db,
|
||||
authorizedService: authorized_service.New(db, cache),
|
||||
adminService: admin_service.New(db, cache),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ func NewHTTPMux(logger *zap.Logger, db db.Repo, cache cache.Repo, grpConn grpc.C
|
||||
}
|
||||
|
||||
mux, err := core.New(logger,
|
||||
core.WithEnableOpenBrowser("http://127.0.0.1:9999"),
|
||||
core.WithEnableCors(),
|
||||
core.WithEnableRate(),
|
||||
core.WithPanicNotify(notify.OnPanicNotify),
|
||||
@@ -45,7 +46,7 @@ func NewHTTPMux(logger *zap.Logger, db db.Repo, cache cache.Repo, grpConn grpc.C
|
||||
r.db = db
|
||||
r.cache = cache
|
||||
r.grpConn = grpConn
|
||||
r.middles = middleware.New(logger, cache)
|
||||
r.middles = middleware.New(logger, cache, db)
|
||||
|
||||
// 设置 WEB 路由
|
||||
setWebRouter(r)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/admin_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/authorized_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/demo_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/tool_handler"
|
||||
@@ -36,20 +37,40 @@ func setApiRouter(r *resource) {
|
||||
user.GET("/info/:username", core.AliasForRecordMetrics("/user/info"), userHandler.Detail())
|
||||
}
|
||||
|
||||
// authorized
|
||||
authorizedHandler := authorized_handler.New(r.logger, r.db, r.cache)
|
||||
|
||||
// admin
|
||||
adminHandler := admin_handler.New(r.logger, r.db, r.cache)
|
||||
|
||||
// 登录
|
||||
login := r.mux.Group("/login", r.middles.Signature())
|
||||
{
|
||||
login.POST("/web", adminHandler.Login())
|
||||
}
|
||||
|
||||
// api
|
||||
api := r.mux.Group("/api")
|
||||
api := r.mux.Group("/api", core.WrapAuthHandler(r.middles.Token), r.middles.Signature())
|
||||
{
|
||||
// authorized
|
||||
authorizedHandler := authorized_handler.New(r.logger, r.db, r.cache)
|
||||
api.POST("/authorized", authorizedHandler.Create())
|
||||
api.GET("/authorized", authorizedHandler.List())
|
||||
api.PATCH("/authorized/used", authorizedHandler.UpdateUsed())
|
||||
api.DELETE("/authorized/:id", authorizedHandler.Delete())
|
||||
|
||||
api.POST("/authorized_api", authorizedHandler.CreateAPI())
|
||||
api.GET("/authorized_list", authorizedHandler.ListAPI())
|
||||
api.GET("/authorized_api", authorizedHandler.ListAPI())
|
||||
api.DELETE("/authorized_api/:id", authorizedHandler.DeleteAPI())
|
||||
|
||||
api.POST("/admin", adminHandler.Create())
|
||||
api.GET("/admin", adminHandler.List())
|
||||
api.PATCH("/admin/used", adminHandler.UpdateUsed())
|
||||
api.PATCH("/admin/reset_password/:id", adminHandler.ResetPassword())
|
||||
api.DELETE("/admin/:id", adminHandler.Delete())
|
||||
api.POST("/admin/logout", adminHandler.Logout())
|
||||
api.PATCH("/admin/modify_password", adminHandler.ModifyPassword())
|
||||
api.GET("/admin/info", adminHandler.Detail())
|
||||
api.PATCH("/admin/modify_personal_info", adminHandler.ModifyPersonalInfo())
|
||||
|
||||
// tool
|
||||
toolHandler := tool_handler.New(r.logger, r.db, r.cache)
|
||||
api.GET("/tool/hashids/encode/:id", toolHandler.HashIdsEncode())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/web/controller/admin_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/web/controller/authorized_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/web/controller/configinfo_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/web/controller/dashboard_handler"
|
||||
@@ -17,6 +18,7 @@ func setWebRouter(r *resource) {
|
||||
configInfoHandler := configinfo_handler.New(r.logger, r.db, r.cache)
|
||||
authorizedHandler := authorized_handler.New(r.logger, r.db, r.cache)
|
||||
toolHandler := tool_handler.New(r.logger, r.db, r.cache)
|
||||
adminHandler := admin_handler.New(r.logger, r.db, r.cache)
|
||||
|
||||
web := r.mux.Group("", r.middles.DisableLog())
|
||||
{
|
||||
@@ -45,6 +47,13 @@ func setWebRouter(r *resource) {
|
||||
web.GET("/authorized/api/:id", authorizedHandler.ApiView())
|
||||
web.GET("/authorized/demo", authorizedHandler.DemoView())
|
||||
|
||||
// 管理员
|
||||
web.GET("/admin/list", adminHandler.ListView())
|
||||
web.GET("/admin/add", adminHandler.AddView())
|
||||
web.GET("/admin/modify_password", adminHandler.ModifyPasswordView())
|
||||
web.GET("/admin/modify_info", adminHandler.ModifyInfoView())
|
||||
web.GET("/login", adminHandler.LoginView())
|
||||
|
||||
// 工具箱
|
||||
web.GET("/tool/hashids", toolHandler.HashIdsView())
|
||||
web.GET("/tool/logs", toolHandler.LogsView())
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package admin_handler
|
||||
|
||||
import "github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
|
||||
func (h *handler) AddView() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
c.HTML("admin_add", nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package admin_handler
|
||||
|
||||
import "github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
|
||||
func (h *handler) ListView() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
c.HTML("admin_list", nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package admin_handler
|
||||
|
||||
import "github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
|
||||
func (h *handler) LoginView() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
c.HTML("admin_login", nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package admin_handler
|
||||
|
||||
import "github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
|
||||
func (h *handler) ModifyInfoView() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
c.HTML("admin_modifyinfo", nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package admin_handler
|
||||
|
||||
import "github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
|
||||
func (h *handler) ModifyPasswordView() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
c.HTML("admin_modifypassword", nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package admin_handler
|
||||
|
||||
import (
|
||||
"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"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ Handler = (*handler)(nil)
|
||||
|
||||
type Handler interface {
|
||||
i()
|
||||
|
||||
AddView() core.HandlerFunc
|
||||
ListView() core.HandlerFunc
|
||||
LoginView() core.HandlerFunc
|
||||
ModifyPasswordView() core.HandlerFunc
|
||||
ModifyInfoView() core.HandlerFunc
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
db db.Repo
|
||||
logger *zap.Logger
|
||||
cache cache.Repo
|
||||
}
|
||||
|
||||
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
|
||||
return &handler{
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) i() {}
|
||||
@@ -15,14 +15,15 @@ type logsViewResponse struct {
|
||||
}
|
||||
|
||||
type logData struct {
|
||||
Level string `json:"level"`
|
||||
Time string `json:"time"`
|
||||
Path string `json:"path"`
|
||||
HTTPCode int `json:"http_code"`
|
||||
Method string `json:"method"`
|
||||
Msg string `json:"msg"`
|
||||
TraceID string `json:"trace_id"`
|
||||
Content string `json:"content"`
|
||||
Level string `json:"level"`
|
||||
Time string `json:"time"`
|
||||
Path string `json:"path"`
|
||||
HTTPCode int `json:"http_code"`
|
||||
Method string `json:"method"`
|
||||
Msg string `json:"msg"`
|
||||
TraceID string `json:"trace_id"`
|
||||
Content string `json:"content"`
|
||||
CostSeconds float64 `json:"cost_seconds"`
|
||||
}
|
||||
|
||||
func (h *handler) LogsView() core.HandlerFunc {
|
||||
@@ -59,14 +60,15 @@ func (h *handler) LogsView() core.HandlerFunc {
|
||||
var logParse logParseData
|
||||
_ = json.Unmarshal(content, &logParse)
|
||||
data := logData{
|
||||
Content: string(content),
|
||||
Level: logParse.Level,
|
||||
Time: logParse.Time,
|
||||
Path: logParse.Path,
|
||||
Method: logParse.Method,
|
||||
Msg: logParse.Msg,
|
||||
HTTPCode: logParse.HTTPCode,
|
||||
TraceID: logParse.TraceID,
|
||||
Content: string(content),
|
||||
Level: logParse.Level,
|
||||
Time: logParse.Time,
|
||||
Path: logParse.Path,
|
||||
Method: logParse.Method,
|
||||
Msg: logParse.Msg,
|
||||
HTTPCode: logParse.HTTPCode,
|
||||
TraceID: logParse.TraceID,
|
||||
CostSeconds: logParse.CostSeconds,
|
||||
}
|
||||
|
||||
if string(content) != "" {
|
||||
|
||||
Reference in New Issue
Block a user