v1.0.0
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package api_v1
|
||||
|
||||
import (
|
||||
"sun-panel/api/api_v1/openness"
|
||||
"sun-panel/api/api_v1/panel"
|
||||
"sun-panel/api/api_v1/system"
|
||||
)
|
||||
|
||||
type ApiGroup struct {
|
||||
ApiSystem system.ApiSystem // 系统功能api
|
||||
ApiOpen openness.ApiPpenness
|
||||
ApiPanel panel.ApiPanel
|
||||
}
|
||||
|
||||
var ApiGroupApp = new(ApiGroup)
|
||||
@@ -0,0 +1,5 @@
|
||||
package adminApiStructs
|
||||
|
||||
type AboutSettingRequest struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package adminApiStructs
|
||||
|
||||
type GetStatisticsResp struct {
|
||||
UserCount int64 `json:"userCount"`
|
||||
UserToday int64 `json:"userToday"`
|
||||
RoleCount int64 `json:"roleCount"`
|
||||
RoleToday int64 `json:"roleToday"`
|
||||
DialogCount int64 `json:"dialogCount"`
|
||||
DialogToday int64 `json:"dialogToday"`
|
||||
DrawCount int64 `json:"drawCount"`
|
||||
DrawToday int64 `json:"drawToday"`
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package commonApiStructs
|
||||
|
||||
type RequestPage struct {
|
||||
Page int `json:"page"`
|
||||
Limit int `json:"limit"`
|
||||
Keyword string `json:"keyword"`
|
||||
}
|
||||
|
||||
type RequestDeleteIds[T int | uint] struct {
|
||||
Ids []T `json:"ids"`
|
||||
}
|
||||
|
||||
type VerificationRequest struct {
|
||||
CodeID string `json:"codeId"`
|
||||
VCode string `json:"vCode"`
|
||||
}
|
||||
|
||||
type VerificationResponse struct {
|
||||
CodeID string `json:"codeId"`
|
||||
Result bool `json:"result"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package adminApiStructs
|
||||
|
||||
import "sun-panel/models"
|
||||
|
||||
type ItemIconEditRequest struct {
|
||||
models.ItemIcon
|
||||
IconJson string
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package systemApiStructs
|
||||
|
||||
type NoticeGetListByDisplayTypeReq struct {
|
||||
DisplayType []int `json:"displayType"`
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package systemApiStructs
|
||||
|
||||
type GetReferralCodeResp struct {
|
||||
ReferralCode string `json:"referralCode"`
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package apiReturn
|
||||
|
||||
import (
|
||||
"sun-panel/api/api_v1/common/apiData/commonApiStructs"
|
||||
"sun-panel/global"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const ERROR_CODE_SUCCESS = 0 // 错误码 无任何错误
|
||||
|
||||
const (
|
||||
// 验证器类
|
||||
|
||||
ERROR_CODE_VERIFICATION_MUST = 1101 // 错误码 验证器类:必须需要验证或者验证数据为空
|
||||
ERROR_CODE_VERIFICATION_FAIL = 1102 // 错误码 验证器类:验证失败,验证错误
|
||||
|
||||
// 数据类
|
||||
|
||||
ERROR_CODE_DATA_DATABASE = 1110 // 错误码 数据类:数据库报错
|
||||
ERROR_CODE_DATA_RECORD_NOT_FOUND = 1111 // 错误码 数据类:数据记录未找到
|
||||
)
|
||||
|
||||
func ApiReturn(ctx *gin.Context, code int, msg string, data interface{}) {
|
||||
returnData := map[string]interface{}{
|
||||
"code": code,
|
||||
"msg": msg,
|
||||
}
|
||||
if data != nil {
|
||||
returnData["data"] = data
|
||||
}
|
||||
ctx.JSON(200, returnData)
|
||||
}
|
||||
|
||||
// 返回成功
|
||||
func SuccessData(ctx *gin.Context, data interface{}) {
|
||||
ApiReturn(ctx, 0, "OK", data)
|
||||
}
|
||||
|
||||
// 返回列表
|
||||
func SuccessListData(ctx *gin.Context, list interface{}, count int64) {
|
||||
ApiReturn(ctx, 0, "OK", gin.H{
|
||||
"list": list,
|
||||
"count": count,
|
||||
})
|
||||
}
|
||||
|
||||
// 返回成功,没有data数据
|
||||
func Success(ctx *gin.Context) {
|
||||
ApiReturn(ctx, 0, "OK", nil)
|
||||
}
|
||||
|
||||
// 返回列表数据
|
||||
func ListData(ctx *gin.Context, list interface{}, count int64) {
|
||||
data := map[string]interface{}{
|
||||
"list": list,
|
||||
"count": count,
|
||||
}
|
||||
ApiReturn(ctx, 0, "OK", data)
|
||||
}
|
||||
|
||||
// 返回错误 验证码相关错误错误
|
||||
func ErrorVerification(ctx *gin.Context, errCode int, codeID string) {
|
||||
msg := ""
|
||||
switch errCode {
|
||||
case ERROR_CODE_VERIFICATION_FAIL:
|
||||
msg = "验证失败,请重新验证"
|
||||
case ERROR_CODE_VERIFICATION_MUST:
|
||||
msg = "需要进一步验证"
|
||||
}
|
||||
ApiReturn(ctx, errCode, msg, gin.H{
|
||||
"verification": commonApiStructs.VerificationResponse{
|
||||
CodeID: codeID,
|
||||
Result: false,
|
||||
Message: msg,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 返回错误 需要个性化定义的错误|带返回数据的错误
|
||||
func ErrorCode(ctx *gin.Context, code int, errMsg string, data interface{}) {
|
||||
ApiReturn(ctx, code, errMsg, data)
|
||||
}
|
||||
|
||||
// 返回错误 普通提示错误
|
||||
func Error(ctx *gin.Context, errMsg string) {
|
||||
ErrorCode(ctx, -1, errMsg, nil)
|
||||
}
|
||||
|
||||
// 返回错误 需要个性化定义的错误|带返回数据的错误
|
||||
func ErrorNoAccess(ctx *gin.Context) {
|
||||
ErrorCode(ctx, 1005, global.Lang.Get("common.no_access"), nil)
|
||||
}
|
||||
|
||||
// 返回错误 参数错误
|
||||
func ErrorParamFomat(ctx *gin.Context, errMsg string) {
|
||||
Error(ctx, global.Lang.GetAndInsert("common.api_error_param_format", "[", errMsg, "]"))
|
||||
// Error(ctx, "参数错误")
|
||||
}
|
||||
|
||||
// // 返回错误 数据库
|
||||
func ErrorDatabase(ctx *gin.Context, errMsg string) {
|
||||
Error(ctx, global.Lang.GetAndInsert("common.db_error", "[", errMsg, "]"))
|
||||
}
|
||||
|
||||
// 返回错误 数据记录未找到
|
||||
func ErrorDataNotFound(ctx *gin.Context) {
|
||||
// ErrorCode(ctx,, global.Lang.GetAndInsert("common.db_error", "[", errMsg, "]"))
|
||||
ErrorCode(ctx, ERROR_CODE_DATA_RECORD_NOT_FOUND, "未找到数据记录", nil)
|
||||
}
|
||||
|
||||
// 返回错误 需要个性化定义的错误|带返回数据的错误
|
||||
// func ErrorNoAccess(ctx *gin.Context) {
|
||||
// ErrorCode(ctx, 1005, global.Lang.Get("common.no_access"), nil)
|
||||
// }
|
||||
|
||||
// // 返回错误 参数错误
|
||||
// func ErrorParamFomat(ctx *gin.Context, errMsg string) {
|
||||
// Error(ctx, global.Lang.GetAndInsert("common.api_error_param_format", "[", errMsg, "]"))
|
||||
// }
|
||||
|
||||
// // 返回错误 数据库
|
||||
// func ErrorDatabase(ctx *gin.Context, errMsg string) {
|
||||
// Error(ctx, global.Lang.GetAndInsert("common.db_error", "[", errMsg, "]"))
|
||||
// }
|
||||
@@ -0,0 +1,99 @@
|
||||
package base
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/lib/captcha"
|
||||
"sun-panel/lib/cmn"
|
||||
"sun-panel/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/locales/zh"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
zhTranslations "github.com/go-playground/validator/v10/translations/zh"
|
||||
)
|
||||
|
||||
type PageLimitVerify struct {
|
||||
Page int64
|
||||
Limit int64
|
||||
}
|
||||
|
||||
// 验证输入是否有效并返回错误
|
||||
func validateInputStruct(params interface{}) (errMsg string, err error) {
|
||||
var validate = validator.New()
|
||||
//通过label标签返回自定义错误内容
|
||||
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
|
||||
label := field.Tag.Get("label")
|
||||
if label == "" {
|
||||
return field.Name
|
||||
}
|
||||
return label
|
||||
})
|
||||
|
||||
// 自定义验证规则,使用 strings.TrimSpace 函数删除前后空格
|
||||
validate.RegisterValidation("trimmedRequired", func(fl validator.FieldLevel) bool {
|
||||
return strings.TrimSpace(fl.Field().String()) != ""
|
||||
})
|
||||
|
||||
if err = validate.Struct(params); err != nil {
|
||||
trans := validateTransInit(validate)
|
||||
verrs := err.(validator.ValidationErrors)
|
||||
// errs := make(map[string]string)
|
||||
for _, value := range verrs.Translate(trans) {
|
||||
// errs[key[strings.Index(key, ".")+1:]] = value
|
||||
errMsg += " " + value
|
||||
}
|
||||
// fmt.Println(errs)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 验证输入是否有效并返回错误
|
||||
func ValidateInputStruct(params interface{}) (errMsg string, err error) {
|
||||
return validateInputStruct(params)
|
||||
}
|
||||
|
||||
// 数据验证翻译器
|
||||
func validateTransInit(validate *validator.Validate) ut.Translator {
|
||||
// 万能翻译器,保存所有的语言环境和翻译数据
|
||||
uni := ut.New(zh.New())
|
||||
// 翻译器
|
||||
trans, _ := uni.GetTranslator("zh")
|
||||
//验证器注册翻译器
|
||||
err := zhTranslations.RegisterDefaultTranslations(validate, trans)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return trans
|
||||
}
|
||||
|
||||
func GetCurrentUserInfo(c *gin.Context) (userInfo models.User, exist bool) {
|
||||
if value, exist := c.Get("userInfo"); exist {
|
||||
if v, ok := value.(models.User); ok {
|
||||
return v, exist
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 验证器验证
|
||||
func VerificationCheck(verificationId, vCode string) (errCode int, verificationIdRes string) {
|
||||
|
||||
// 需要进一步验证并返回验证信息
|
||||
if verificationId == "" || vCode == "" {
|
||||
verificationIdRes = cmn.BuildRandCode(16, cmn.RAND_CODE_MODE1)
|
||||
errCode = apiReturn.ERROR_CODE_VERIFICATION_MUST
|
||||
return
|
||||
}
|
||||
|
||||
// 验证码错误
|
||||
if !captcha.CaptchaVerifyHandle(verificationId, vCode) {
|
||||
errCode = apiReturn.ERROR_CODE_VERIFICATION_FAIL
|
||||
return
|
||||
}
|
||||
errCode = apiReturn.ERROR_CODE_SUCCESS
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
// "calendar-note-gin/api/v1/common/apiReturn"
|
||||
// . "calendar-note-gin/api/v1/common/base"
|
||||
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/api/api_v1/common/base"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func AdminInterceptor(c *gin.Context) {
|
||||
currentUser, _ := base.GetCurrentUserInfo(c)
|
||||
if currentUser.Role != 1 {
|
||||
apiReturn.ErrorNoAccess(c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/global"
|
||||
"sun-panel/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func LoginInterceptor(c *gin.Context) {
|
||||
|
||||
// 继续执行后续的操作,再回来
|
||||
// c.Next()
|
||||
|
||||
// 获得token
|
||||
cToken := c.GetHeader("token")
|
||||
|
||||
// 没有token信息视为未登录
|
||||
if cToken == "" {
|
||||
apiReturn.ErrorCode(c, 1000, global.Lang.Get("login.err_not_login"), nil)
|
||||
c.Abort() // 终止执行后续的操作,一般配合return使用
|
||||
return
|
||||
}
|
||||
|
||||
token := ""
|
||||
{
|
||||
var ok bool
|
||||
token, ok = global.CUserToken.Get(cToken)
|
||||
// 可能已经安全退出或者很久没有使用已过期
|
||||
if !ok || token == "" {
|
||||
apiReturn.ErrorCode(c, 1001, global.Lang.Get("login.err_not_login"), nil)
|
||||
c.Abort() // 终止执行后续的操作,一般配合return使用
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 直接返回缓存的用户信息
|
||||
if userInfo, success := global.UserToken.Get(token); success {
|
||||
c.Set("userInfo", userInfo)
|
||||
return
|
||||
}
|
||||
|
||||
global.Logger.Debug("准备查询数据库的用户资料", token)
|
||||
|
||||
mUser := models.User{}
|
||||
// 去库中查询是否存在该用户;否则返回错误
|
||||
if info, err := mUser.GetUserInfoByToken(token); err != nil || info.Token == "" || info.ID == 0 {
|
||||
apiReturn.ErrorCode(c, 1001, global.Lang.Get("login.err_token_expire"), nil)
|
||||
c.Abort()
|
||||
return
|
||||
} else {
|
||||
// 通过 设置当前用户信息
|
||||
global.UserToken.SetDefault(info.Token, info)
|
||||
global.CUserToken.SetDefault(cToken, token)
|
||||
c.Set("userInfo", info)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 不验证缓存直接验证库省去没有缓存每次都要手动登录的问题
|
||||
func LoginInterceptorDev(c *gin.Context) {
|
||||
|
||||
// 获得token
|
||||
token := c.GetHeader("token")
|
||||
mUser := models.User{}
|
||||
|
||||
// 去库中查询是否存在该用户;否则返回错误
|
||||
if info, err := mUser.GetUserInfoByToken(token); err != nil || info.ID == 0 {
|
||||
apiReturn.ErrorCode(c, 1001, global.Lang.Get("login.err_token_expire"), nil)
|
||||
c.Abort()
|
||||
return
|
||||
} else {
|
||||
// 通过
|
||||
// 设置当前用户信息
|
||||
c.Set("userInfo", info)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package openness
|
||||
|
||||
type ApiPpenness struct {
|
||||
Openness Openness
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package openness
|
||||
|
||||
import (
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/global"
|
||||
"sun-panel/lib/cmn/systemSetting"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Openness struct {
|
||||
}
|
||||
|
||||
func (a *Openness) LoginConfig(c *gin.Context) {
|
||||
cfg := systemSetting.ApplicationSetting{}
|
||||
if err := global.SystemSetting.GetValueByInterface(systemSetting.SYSTEM_APPLICATION, &cfg); err != nil {
|
||||
apiReturn.Error(c, "配置查询失败:"+err.Error())
|
||||
return
|
||||
}
|
||||
apiReturn.SuccessData(c, gin.H{
|
||||
"loginCaptcha": cfg.LoginCaptcha,
|
||||
"register": cfg.Register,
|
||||
})
|
||||
}
|
||||
|
||||
func (a *Openness) GetDisclaimer(c *gin.Context) {
|
||||
if content, err := global.SystemSetting.GetValueString(systemSetting.DISCLAIMER); err != nil {
|
||||
global.SystemSetting.Set(systemSetting.DISCLAIMER, "")
|
||||
apiReturn.SuccessData(c, "")
|
||||
return
|
||||
} else {
|
||||
apiReturn.SuccessData(c, content)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Openness) GetAboutDescription(c *gin.Context) {
|
||||
if content, err := global.SystemSetting.GetValueString(systemSetting.WEB_ABOUT_DESCRIPTION); err != nil {
|
||||
global.SystemSetting.Set(systemSetting.WEB_ABOUT_DESCRIPTION, "")
|
||||
apiReturn.SuccessData(c, "")
|
||||
return
|
||||
} else {
|
||||
apiReturn.SuccessData(c, content)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package panel
|
||||
|
||||
type ApiPanel struct {
|
||||
ItemIcon ItemIcon
|
||||
UserConfig UserConfig
|
||||
UsersApi UsersApi
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package panel
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sun-panel/api/api_v1/common/apiData/commonApiStructs"
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/api/api_v1/common/base"
|
||||
"sun-panel/global"
|
||||
"sun-panel/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
type ItemIcon struct {
|
||||
}
|
||||
|
||||
func (a *ItemIcon) Edit(c *gin.Context) {
|
||||
userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
req := models.ItemIcon{}
|
||||
|
||||
if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil {
|
||||
apiReturn.ErrorParamFomat(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
req.UserId = userInfo.ID
|
||||
req.GroupId = 1
|
||||
req.Sort = 1
|
||||
|
||||
// json转字符串
|
||||
if j, err := json.Marshal(req.Icon); err == nil {
|
||||
req.IconJson = string(j)
|
||||
}
|
||||
|
||||
if req.ID != 0 {
|
||||
// 修改
|
||||
global.Db.Model(&models.ItemIcon{}).
|
||||
Select("IconJson", "Icon", "Title", "Url", "LanUrl", "Description", "OpenMethod", "Sort", "GroupId", "UserId").
|
||||
Where("id=?", req.ID).Updates(&req)
|
||||
} else {
|
||||
// 创建
|
||||
global.Db.Create(&req)
|
||||
}
|
||||
|
||||
apiReturn.SuccessData(c, req)
|
||||
}
|
||||
|
||||
// // 获取详情
|
||||
// func (a *ItemIcon) GetInfo(c *gin.Context) {
|
||||
// req := systemApiStructs.AiDrawGetInfoReq{}
|
||||
|
||||
// if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil {
|
||||
// apiReturn.ErrorParamFomat(c, err.Error())
|
||||
// return
|
||||
// }
|
||||
|
||||
// userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
|
||||
// aiDraw := models.AiDraw{}
|
||||
// aiDraw.ID = req.ID
|
||||
// if err := aiDraw.GetInfo(global.Db); err != nil {
|
||||
// if err == gorm.ErrRecordNotFound {
|
||||
// apiReturn.Error(c, "不存在记录")
|
||||
// return
|
||||
// }
|
||||
// apiReturn.ErrorDatabase(c, err.Error())
|
||||
// return
|
||||
// }
|
||||
|
||||
// if userInfo.ID != aiDraw.UserID {
|
||||
// apiReturn.ErrorNoAccess(c)
|
||||
// return
|
||||
// }
|
||||
|
||||
// apiReturn.SuccessData(c, aiDraw)
|
||||
// }
|
||||
|
||||
func (a *ItemIcon) GetListByGroupId(c *gin.Context) {
|
||||
req := commonApiStructs.RequestPage{}
|
||||
|
||||
if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil {
|
||||
apiReturn.ErrorParamFomat(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
itemIcons := []models.ItemIcon{}
|
||||
|
||||
if err := global.Db.Order("sort ,created_at DESC").Where("user_id=?", userInfo.ID).Find(&itemIcons, "group_id = ? AND user_id=?", 1, userInfo.ID).Error; err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range itemIcons {
|
||||
json.Unmarshal([]byte(v.IconJson), &itemIcons[k].Icon)
|
||||
}
|
||||
|
||||
apiReturn.SuccessListData(c, itemIcons, 0)
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package panel
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/api/api_v1/common/base"
|
||||
"sun-panel/global"
|
||||
"sun-panel/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UserConfig struct {
|
||||
}
|
||||
|
||||
func (a *UserConfig) Get(c *gin.Context) {
|
||||
userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
cfg := models.UserConfig{}
|
||||
if err := global.Db.First(&cfg, "user_id=?", userInfo.ID).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
apiReturn.ErrorDataNotFound(c)
|
||||
return
|
||||
} else {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 处理字段
|
||||
if err := json.Unmarshal([]byte(cfg.PanelJson), &cfg.Panel); err != nil {
|
||||
cfg.Panel = nil
|
||||
}
|
||||
if err := json.Unmarshal([]byte(cfg.SearchEngineJson), &cfg.SearchEngine); err != nil {
|
||||
cfg.SearchEngine = nil
|
||||
}
|
||||
apiReturn.SuccessData(c, cfg)
|
||||
|
||||
}
|
||||
|
||||
func (a *UserConfig) Set(c *gin.Context) {
|
||||
userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
req := models.UserConfig{}
|
||||
|
||||
if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil {
|
||||
apiReturn.ErrorParamFomat(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 处理字段
|
||||
if jb, err := json.Marshal(req.Panel); err != nil {
|
||||
req.PanelJson = "{}"
|
||||
} else {
|
||||
req.PanelJson = string(jb)
|
||||
}
|
||||
|
||||
if jb, err := json.Marshal(req.SearchEngine); err != nil {
|
||||
req.SearchEngineJson = "{}"
|
||||
} else {
|
||||
req.SearchEngineJson = string(jb)
|
||||
}
|
||||
|
||||
// 保存操作
|
||||
if err := global.Db.First(&models.UserConfig{}, "user_id=?", userInfo.ID).Error; err != nil {
|
||||
req.UserId = userInfo.ID
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
// 新增
|
||||
if err := global.Db.Create(&req).Error; err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 报错
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 修改
|
||||
if err := global.Db.Where("user_id=?", userInfo.ID).Updates(&req).Error; err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
apiReturn.Success(c)
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package panel
|
||||
|
||||
import (
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/api/api_v1/common/base"
|
||||
"sun-panel/global"
|
||||
"sun-panel/lib/cmn"
|
||||
"sun-panel/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
// 此API 临时使用,后期带有管理功能,将废除!!!
|
||||
type UsersApi struct {
|
||||
}
|
||||
|
||||
func (a UsersApi) Create(c *gin.Context) {
|
||||
param := models.User{}
|
||||
if err := c.ShouldBindBodyWith(¶m, binding.JSON); err != nil {
|
||||
apiReturn.ErrorParamFomat(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if errMsg, err := base.ValidateInputStruct(param); err != nil {
|
||||
apiReturn.ErrorParamFomat(c, errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
mUser := models.User{
|
||||
Username: param.Username,
|
||||
Password: cmn.PasswordEncryption(param.Password),
|
||||
Name: param.Username,
|
||||
HeadImage: param.HeadImage,
|
||||
Status: 1,
|
||||
Role: 1, // 固定管理员
|
||||
Mail: param.Username,
|
||||
}
|
||||
|
||||
// 验证账号是否存在
|
||||
if _, err := mUser.CheckUsernameExist(param.Username); err != nil {
|
||||
apiReturn.Error(c, global.Lang.Get("register.mail_exist"))
|
||||
return
|
||||
}
|
||||
|
||||
userInfo, err := mUser.CreateOne()
|
||||
|
||||
if err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
apiReturn.SuccessData(c, gin.H{"userId": userInfo.ID})
|
||||
}
|
||||
|
||||
func (a UsersApi) Deletes(c *gin.Context) {
|
||||
type UserIds struct {
|
||||
UserIds []uint
|
||||
}
|
||||
param := UserIds{}
|
||||
if err := c.ShouldBindBodyWith(¶m, binding.JSON); err != nil {
|
||||
apiReturn.Error(c, global.Lang.GetAndInsert("common.api_error_param_format", "[", err.Error(), "]"))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if err := global.Db.Delete(&models.User{}, ¶m.UserIds).Error; err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
apiReturn.Success(c)
|
||||
}
|
||||
|
||||
func (a UsersApi) Update(c *gin.Context) {
|
||||
param := models.User{}
|
||||
if err := c.ShouldBindBodyWith(¶m, binding.JSON); err != nil {
|
||||
apiReturn.Error(c, global.Lang.GetAndInsert("common.api_error_param_format", "[", err.Error(), "]"))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if param.Password == "" {
|
||||
param.Password = "-" // 修改不允许修改密码,为了验证通过
|
||||
}
|
||||
|
||||
param.Mail = param.Username // 密码邮箱同时修改
|
||||
if errMsg, err := base.ValidateInputStruct(param); err != nil {
|
||||
apiReturn.ErrorParamFomat(c, errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
allowField := []string{"Username", "Name", "Mail", "Token"}
|
||||
|
||||
// 密码不为默认“-”空,修改密码
|
||||
if param.Password != "-" {
|
||||
param.Password = cmn.PasswordEncryption(param.Password)
|
||||
allowField = append(allowField, "Password")
|
||||
}
|
||||
mUser := models.User{}
|
||||
|
||||
userInfo := models.User{}
|
||||
// 验证账号是否存在
|
||||
if user, err := mUser.CheckUsernameExist(param.Username); err != nil {
|
||||
userInfo = user
|
||||
if user.ID != param.ID {
|
||||
apiReturn.Error(c, global.Lang.Get("register.mail_exist"))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
userInfo = user
|
||||
}
|
||||
|
||||
param.Token = "" // 修改资料就重置token
|
||||
if err := global.Db.Select(allowField).Where("id=?", param.ID).Updates(¶m).Error; err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
// global.Logger.Debug("修改资料清空token", userInfo.Token)
|
||||
global.UserToken.Delete(userInfo.Token) // 更新用户信息
|
||||
// 返回token等基本信息
|
||||
apiReturn.SuccessData(c, param)
|
||||
}
|
||||
|
||||
func (a UsersApi) GetList(c *gin.Context) {
|
||||
|
||||
type ParamsStruct struct {
|
||||
models.User
|
||||
Limit int
|
||||
Page int
|
||||
Keyword string `json:"keyword"`
|
||||
}
|
||||
|
||||
param := ParamsStruct{}
|
||||
if err := c.ShouldBindBodyWith(¶m, binding.JSON); err != nil {
|
||||
apiReturn.Error(c, global.Lang.GetAndInsert("common.api_error_param_format", "[", err.Error(), "]"))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
list []models.User
|
||||
count int64
|
||||
)
|
||||
db := global.Db
|
||||
|
||||
// 查询条件
|
||||
if param.Keyword != "" {
|
||||
db = db.Where("name LIKE ? OR username LIKE ?", "%"+param.Keyword+"%", "%"+param.Keyword+"%")
|
||||
}
|
||||
|
||||
if err := db.Omit("Password").Limit(param.Limit).Offset((param.Page - 1) * param.Limit).Find(&list).Limit(-1).Offset(-1).Count(&count).Error; err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// resMap := []map[string]interface{}{}
|
||||
// for _, v := range list {
|
||||
// resMap = append(resMap, map[string]interface{}{
|
||||
// "userId": v.ID,
|
||||
// "name": v.Name,
|
||||
// "headImage": v.HeadImage,
|
||||
// "status": v.Status,
|
||||
// "role": v.Role,
|
||||
// "username": v.Username,
|
||||
// })
|
||||
// }
|
||||
|
||||
apiReturn.SuccessListData(c, list, count)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package system
|
||||
|
||||
type ApiSystem struct {
|
||||
About About
|
||||
LoginApi LoginApi
|
||||
UserApi UserApi
|
||||
FileApi FileApi
|
||||
CaptchaApi CaptchaApi
|
||||
RegisterApi RegisterApi
|
||||
NoticeApi NoticeApi
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/lib/cmn"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type About struct {
|
||||
}
|
||||
|
||||
func (a *About) Get(c *gin.Context) {
|
||||
version := cmn.GetSysVersionInfo()
|
||||
apiReturn.SuccessData(c, gin.H{
|
||||
"versionName": version.Version,
|
||||
"versionCode": version.Version_code,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strconv"
|
||||
"sun-panel/lib/captcha"
|
||||
"sun-panel/lib/cmn"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type CaptchaApi struct {
|
||||
ErrMsg string // 错误信息
|
||||
}
|
||||
|
||||
// 获取图像
|
||||
func (c *CaptchaApi) GetImage(ctx *gin.Context) {
|
||||
key := cmn.BuildRandCode(16, cmn.RAND_CODE_MODE2)
|
||||
width, _ := strconv.Atoi(ctx.Param("width"))
|
||||
height, _ := strconv.Atoi(ctx.Param("height"))
|
||||
if width == 0 || width > 500 {
|
||||
width = 120
|
||||
}
|
||||
if height == 0 || height > 500 {
|
||||
height = 44
|
||||
}
|
||||
// 设置网页验证码的cookie
|
||||
ctx.SetCookie("CaptchaId", key, 3600, "/", "", false, false)
|
||||
base64Str := captcha.GenerateCaptchaHandler(key, width, height)
|
||||
_ = base64Str
|
||||
// base64 字符串一般会包含头部 data:image/xxx;base64, 需要去除
|
||||
baseImg, _ := base64.StdEncoding.DecodeString(base64Str[22:])
|
||||
_, _ = ctx.Writer.WriteString(string(baseImg))
|
||||
}
|
||||
|
||||
// 获取图像根据验证器id,id从地址栏获取
|
||||
func (c *CaptchaApi) GetImageByCaptchaId(ctx *gin.Context) {
|
||||
// key := cmn.BuildRandCode(16, cmn.RAND_CODE_MODE2)
|
||||
width, _ := strconv.Atoi(ctx.Param("width"))
|
||||
height, _ := strconv.Atoi(ctx.Param("height"))
|
||||
captchaId := ctx.Param("captchaId")
|
||||
if width == 0 || width > 500 {
|
||||
width = 120
|
||||
}
|
||||
if height == 0 || height > 500 {
|
||||
height = 44
|
||||
}
|
||||
// 设置网页验证码的cookie
|
||||
base64Str := captcha.GenerateCaptchaHandler(captchaId, width, height)
|
||||
_ = base64Str
|
||||
// base64 字符串一般会包含头部 data:image/xxx;base64, 需要去除
|
||||
baseImg, _ := base64.StdEncoding.DecodeString(base64Str[22:])
|
||||
_, _ = ctx.Writer.WriteString(string(baseImg))
|
||||
}
|
||||
|
||||
func (c *CaptchaApi) CheckVCode(id, vcode string) {
|
||||
// Captcha.Store = base64Captcha.DefaultMemStore
|
||||
// if store.Verify(id, vcode, true) {
|
||||
// body = map[string]interface{}{"code": 1001, "msg": "ok"}
|
||||
// }
|
||||
// w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
// json.NewEncoder(w).Encode(body)
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/api/api_v1/common/base"
|
||||
"sun-panel/global"
|
||||
"sun-panel/lib/cmn"
|
||||
"sun-panel/models"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type FileApi struct{}
|
||||
|
||||
func (a *FileApi) UploadImg(c *gin.Context) {
|
||||
userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
configUpload := global.Config.GetValueString("base", "source_path")
|
||||
f, err := c.FormFile("imgfile")
|
||||
if err != nil {
|
||||
apiReturn.Error(c, "上传失败")
|
||||
return
|
||||
} else {
|
||||
fileExt := strings.ToLower(path.Ext(f.Filename))
|
||||
if fileExt != ".png" && fileExt != ".jpg" && fileExt != ".gif" && fileExt != ".jpeg" && fileExt != ".webp" && fileExt != ".svg" {
|
||||
apiReturn.Error(c, "上传失败!只允许png,jpg,gif,jpeg,svg文件")
|
||||
return
|
||||
}
|
||||
fileName := cmn.Md5(fmt.Sprintf("%s%s", f.Filename, time.Now().String()))
|
||||
fildDir := fmt.Sprintf("%s/%d/%d/%d/", configUpload, time.Now().Year(), time.Now().Month(), time.Now().Day())
|
||||
isExist, _ := cmn.PathExists(fildDir)
|
||||
if !isExist {
|
||||
os.MkdirAll(fildDir, os.ModePerm)
|
||||
}
|
||||
filepath := fmt.Sprintf("%s%s%s", fildDir, fileName, fileExt)
|
||||
c.SaveUploadedFile(f, filepath)
|
||||
|
||||
// 像数据库添加记录
|
||||
mFile := models.File{}
|
||||
mFile.AddFile(userInfo.ID, f.Filename, fileExt, filepath)
|
||||
apiReturn.SuccessData(c, gin.H{
|
||||
"imageUrl": filepath[1:],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (a *FileApi) UploadFiles(c *gin.Context) {
|
||||
userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
configUpload := global.Config.GetValueString("base", "source_path")
|
||||
|
||||
form, err := c.MultipartForm()
|
||||
if err != nil {
|
||||
apiReturn.Error(c, "上传失败")
|
||||
return
|
||||
}
|
||||
files := form.File["files[]"]
|
||||
errFiles := []string{}
|
||||
succMap := map[string]string{}
|
||||
for _, f := range files {
|
||||
fileExt := strings.ToLower(path.Ext(f.Filename))
|
||||
fileName := cmn.Md5(fmt.Sprintf("%s%s", f.Filename, time.Now().String()))
|
||||
fildDir := fmt.Sprintf("%s/%d/%d/%d/", configUpload, time.Now().Year(), time.Now().Month(), time.Now().Day())
|
||||
isExist, _ := cmn.PathExists(fildDir)
|
||||
if !isExist {
|
||||
os.MkdirAll(fildDir, os.ModePerm)
|
||||
}
|
||||
filepath := fmt.Sprintf("%s%s%s", fildDir, fileName, fileExt)
|
||||
if c.SaveUploadedFile(f, filepath) != nil {
|
||||
errFiles = append(errFiles, f.Filename)
|
||||
} else {
|
||||
// 成功
|
||||
// 像数据库添加记录
|
||||
mFile := models.File{}
|
||||
mFile.AddFile(userInfo.ID, f.Filename, fileExt, filepath)
|
||||
succMap[f.Filename] = filepath[1:]
|
||||
}
|
||||
}
|
||||
|
||||
apiReturn.SuccessData(c, gin.H{
|
||||
"succMap": succMap,
|
||||
"errFiles": errFiles,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"sun-panel/api/api_v1/common/apiData/commonApiStructs"
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/api/api_v1/common/base"
|
||||
"sun-panel/global"
|
||||
"sun-panel/lib/captcha"
|
||||
"sun-panel/lib/cmn"
|
||||
"sun-panel/lib/cmn/systemSetting"
|
||||
"sun-panel/lib/mail"
|
||||
"sun-panel/models"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type LoginApi struct {
|
||||
}
|
||||
|
||||
// 登录输入验证
|
||||
type LoginLoginVerify struct {
|
||||
Username string `json:"username" validate:"required,min=5"`
|
||||
Password string `json:"password" validate:"required,min=5,max=20"`
|
||||
VCode string `json:"vcode" validate:"max=6"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// @Summary 登录账号
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param LoginLoginVerify body LoginLoginVerify true "登陆验证信息"
|
||||
// @Tags user
|
||||
// @Router /login [post]
|
||||
func (l LoginApi) Login(c *gin.Context) {
|
||||
param := LoginLoginVerify{}
|
||||
if err := c.ShouldBindJSON(¶m); err != nil {
|
||||
apiReturn.Error(c, global.Lang.Get("common.api_error_param_format"))
|
||||
return
|
||||
}
|
||||
|
||||
if errMsg, err := base.ValidateInputStruct(param); err != nil {
|
||||
apiReturn.Error(c, errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
settings := systemSetting.ApplicationSetting{}
|
||||
global.SystemSetting.GetValueByInterface("system_application", &settings)
|
||||
|
||||
// 验证验证码
|
||||
if settings.Login.LoginCaptcha {
|
||||
var captchaId string
|
||||
var err error
|
||||
|
||||
// 获取captchaId
|
||||
if captchaId, err = captcha.CaptchaGetIdByCookieHeader(c, "CaptchaId"); err != nil {
|
||||
apiReturn.Error(c, global.Lang.Get("login.err_captcha_check_fail"))
|
||||
return
|
||||
}
|
||||
|
||||
// 验证码错误
|
||||
if !captcha.CaptchaVerifyHandle(captchaId, param.VCode) {
|
||||
apiReturn.Error(c, global.Lang.Get("captcha.api_captcha_fail"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
mUser := models.User{}
|
||||
var (
|
||||
err error
|
||||
info models.User
|
||||
)
|
||||
bToken := ""
|
||||
if info, err = mUser.GetUserInfoByUsernameAndPassword(param.Username, cmn.PasswordEncryption(param.Password)); err != nil {
|
||||
// 未找到记录 账号或密码错误
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
apiReturn.Error(c, global.Lang.Get("login.err_username_password"))
|
||||
return
|
||||
} else {
|
||||
// 未知错误
|
||||
apiReturn.Error(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 停用或未激活
|
||||
if info.Status != 1 {
|
||||
apiReturn.Error(c, global.Lang.Get("login.err_username_deactivation"))
|
||||
return
|
||||
}
|
||||
|
||||
bToken = info.Token
|
||||
if info.Token == "" {
|
||||
// 生成token
|
||||
buildTokenOver := false
|
||||
for !buildTokenOver {
|
||||
bToken = cmn.BuildRandCode(32, cmn.RAND_CODE_MODE2)
|
||||
if _, err := mUser.GetUserInfoByToken(bToken); err != nil {
|
||||
// 保存token
|
||||
mUser.UpdateUserInfoByUserId(info.ID, map[string]interface{}{
|
||||
"token": bToken,
|
||||
})
|
||||
buildTokenOver = true
|
||||
}
|
||||
}
|
||||
info.Token = bToken
|
||||
}
|
||||
|
||||
// global.UserToken.SetDefault(bToken, info)
|
||||
cToken := uuid.NewString() + "-" + cmn.Md5(cmn.Md5("userId"+strconv.Itoa(int(info.ID))))
|
||||
global.CUserToken.SetDefault(cToken, bToken)
|
||||
global.Logger.Debug("token:", cToken, "|", bToken)
|
||||
global.Logger.Debug(global.CUserToken.Get(cToken))
|
||||
|
||||
// 设置当前用户信息
|
||||
c.Set("userInfo", info)
|
||||
info.Token = cToken // 重要 采用cToken,隐藏真实token
|
||||
apiReturn.SuccessData(c, info)
|
||||
}
|
||||
|
||||
// 安全退出
|
||||
func (l *LoginApi) Logout(c *gin.Context) {
|
||||
// userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
cToken := c.GetHeader("token")
|
||||
global.CUserToken.Delete(cToken)
|
||||
apiReturn.Success(c)
|
||||
}
|
||||
|
||||
// 获取重置密码的验证码
|
||||
func (l *LoginApi) SendResetPasswordVCode(c *gin.Context) {
|
||||
type ResstRequest struct {
|
||||
LoginLoginVerify
|
||||
Verification commonApiStructs.VerificationRequest `json:"verification"`
|
||||
}
|
||||
req := ResstRequest{}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
apiReturn.Error(c, global.Lang.Get("common.api_error_param_format"))
|
||||
return
|
||||
}
|
||||
|
||||
// 验证码验证
|
||||
{
|
||||
errCode, verifcationId := base.VerificationCheck(req.Verification.CodeID, req.Verification.VCode)
|
||||
if errCode != apiReturn.ERROR_CODE_SUCCESS {
|
||||
apiReturn.ErrorVerification(c, errCode, verifcationId)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
emailVCode := cmn.BuildRandCode(6, cmn.RAND_CODE_MODE2)
|
||||
global.VerifyCodeCachePool.Set(req.Email, emailVCode, 10*time.Minute)
|
||||
|
||||
userCheck := &models.User{Mail: req.Email}
|
||||
userInfo := userCheck.GetUserInfoByMail()
|
||||
if userInfo == nil {
|
||||
apiReturn.Error(c, "账号不存在")
|
||||
return
|
||||
}
|
||||
emailInfoConfig := systemSetting.Email{}
|
||||
global.SystemSetting.GetValueByInterface("system_email", &emailInfoConfig)
|
||||
emailInfo := mail.EmailInfo{
|
||||
Username: emailInfoConfig.Mail,
|
||||
Password: emailInfoConfig.Password,
|
||||
Host: emailInfoConfig.Host,
|
||||
Port: emailInfoConfig.Port,
|
||||
}
|
||||
if err := mail.SendResetPasswordVCode(mail.NewEmailer(emailInfo), req.Email, emailVCode); err != nil {
|
||||
apiReturn.Error(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
apiReturn.Success(c)
|
||||
|
||||
}
|
||||
|
||||
// 使用邮箱验证码重置密码
|
||||
func (l *LoginApi) ResetPasswordByVCode(c *gin.Context) {
|
||||
req := registerInfo{}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
apiReturn.Error(c, global.Lang.Get("common.api_error_param_format"))
|
||||
return
|
||||
}
|
||||
|
||||
userCheck := &models.User{Mail: req.Email}
|
||||
userInfo := userCheck.GetUserInfoByMail()
|
||||
if userInfo == nil {
|
||||
apiReturn.Error(c, "账号不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 校验验证码
|
||||
{
|
||||
if emailVCode, ok := global.VerifyCodeCachePool.Get(req.Email); !ok || req.EmailVCode != emailVCode {
|
||||
apiReturn.Error(c, global.Lang.Get("common.captcha_code_error"))
|
||||
return
|
||||
}
|
||||
global.VerifyCodeCachePool.Delete(req.Email)
|
||||
}
|
||||
|
||||
updateData := map[string]interface{}{
|
||||
"password": cmn.PasswordEncryption(req.Password),
|
||||
"token": "",
|
||||
}
|
||||
global.UserToken.Delete(userInfo.Token) // 更新用户信息
|
||||
if err := userInfo.UpdateUserInfoByUserId(userInfo.ID, updateData); err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
apiReturn.Success(c)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"sun-panel/api/api_v1/common/apiData/systemApiStructs"
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/global"
|
||||
"sun-panel/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
type NoticeApi struct {
|
||||
}
|
||||
|
||||
func (a *NoticeApi) GetListByDisplayType(c *gin.Context) {
|
||||
req := systemApiStructs.NoticeGetListByDisplayTypeReq{}
|
||||
if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil {
|
||||
apiReturn.ErrorParamFomat(c, err.Error())
|
||||
return
|
||||
}
|
||||
noticeList := []models.Notice{}
|
||||
if err := global.Db.Find(¬iceList, "display_type in ?", req.DisplayType).Error; err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
apiReturn.SuccessListData(c, noticeList, 0)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package rateLimit
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sun-panel/global"
|
||||
)
|
||||
|
||||
const (
|
||||
ERROR_RATE_EXCEED_MINUTE = "minute exceed" // 分钟速率超出限制
|
||||
ERROR_RATE_EXCEED_HOUR = "minute hour" // 小时速率超出限制
|
||||
)
|
||||
|
||||
// 获取用户套餐的速率 此处正常根据用户套餐设定获取-暂时写死
|
||||
func GetUserPackageRate(userId uint) (minuteRate, hourRate int) {
|
||||
return 10, 200
|
||||
}
|
||||
|
||||
func CheckRateLimit(userId uint) error {
|
||||
minuteRate, hourRate := GetUserPackageRate(userId)
|
||||
if minuteRate != 0 && minuteRate <= global.RateLimit.MinuteGet(userId) {
|
||||
return errors.New(ERROR_RATE_EXCEED_MINUTE)
|
||||
}
|
||||
|
||||
if hourRate != 0 && hourRate <= global.RateLimit.HourGet(userId) {
|
||||
return errors.New(ERROR_RATE_EXCEED_HOUR)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 速率+1次 同时增加小时和分钟的次数
|
||||
func AddOnceRate(userId uint) error {
|
||||
global.RateLimit.MinuteAddOnce(userId)
|
||||
global.RateLimit.HourAddOnce(userId)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sun-panel/api/api_v1/common/apiData/commonApiStructs"
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/api/api_v1/common/base"
|
||||
"sun-panel/global"
|
||||
"sun-panel/lib/cmn"
|
||||
"sun-panel/lib/cmn/systemSetting"
|
||||
"sun-panel/lib/mail"
|
||||
"sun-panel/models"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type registerInfo struct {
|
||||
Email string `json:"email"`
|
||||
UserName string `json:"userName"`
|
||||
Password string `json:"password"`
|
||||
Vcode string `json:"vcode"`
|
||||
EmailVCode string `json:"emailVCode"`
|
||||
VCode string `json:"vCode"`
|
||||
Verification commonApiStructs.VerificationRequest `json:"verification"`
|
||||
ReferralCode string `json:"referralCode"`
|
||||
}
|
||||
|
||||
const EmailCodeCapacity = 1000
|
||||
|
||||
type RegisterApi struct{}
|
||||
|
||||
// 获取注册验证码
|
||||
func (l RegisterApi) SendRegisterVcode(c *gin.Context) {
|
||||
req := registerInfo{}
|
||||
err := c.ShouldBindJSON(&req)
|
||||
req.Email = req.UserName
|
||||
if err != nil {
|
||||
apiReturn.ErrorParamFomat(c, err.Error())
|
||||
return
|
||||
}
|
||||
errMsg, err := base.ValidateInputStruct(req)
|
||||
if err != nil {
|
||||
apiReturn.Error(c, errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证码验证
|
||||
{
|
||||
errCode, verifcationId := base.VerificationCheck(req.Verification.CodeID, req.Verification.VCode)
|
||||
if errCode != apiReturn.ERROR_CODE_SUCCESS {
|
||||
apiReturn.ErrorVerification(c, errCode, verifcationId)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 验证是否开启注册和后缀格式是否正确
|
||||
{
|
||||
systemSettingInfo := systemSetting.ApplicationSetting{}
|
||||
if err := global.SystemSetting.GetValueByInterface("system_application", &systemSettingInfo); err != nil || !systemSettingInfo.Register.OpenRegister {
|
||||
apiReturn.Error(c, global.Lang.Get("register.unopened_register"))
|
||||
return
|
||||
}
|
||||
|
||||
if systemSettingInfo.Register.EmailSuffix != "" && !cmn.VerifyFormat("^.*"+systemSettingInfo.Register.EmailSuffix+"$", req.Email) {
|
||||
apiReturn.Error(c, global.Lang.GetWithFields("register.emailSuffix_error", map[string]string{"EmailSuffix": systemSettingInfo.Register.EmailSuffix}))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 验证邮箱是否被注册
|
||||
{
|
||||
userCheck := &models.User{Mail: req.UserName}
|
||||
if _, err := userCheck.GetUserInfoByUsername(req.UserName); err == nil && err != gorm.ErrRecordNotFound {
|
||||
apiReturn.Error(c, global.Lang.Get("register.mail_exist"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
emailCode := generateEmailCode()
|
||||
count, err := global.VerifyCodeCachePool.ItemCount()
|
||||
if err != nil || count >= EmailCodeCapacity {
|
||||
global.VerifyCodeCachePool.Flush()
|
||||
}
|
||||
global.VerifyCodeCachePool.Set(req.Email, emailCode, 0)
|
||||
emailInfoConfig := systemSetting.Email{}
|
||||
global.SystemSetting.GetValueByInterface("system_email", &emailInfoConfig)
|
||||
emailInfo := mail.EmailInfo{
|
||||
Username: emailInfoConfig.Mail,
|
||||
Password: emailInfoConfig.Password,
|
||||
Host: emailInfoConfig.Host,
|
||||
Port: emailInfoConfig.Port,
|
||||
}
|
||||
err = mail.SendRegisterEmail(mail.NewEmailer(emailInfo), req.Email, emailCode)
|
||||
if err != nil {
|
||||
apiReturn.Error(c, global.Lang.Get("mail.send_mail_fail"))
|
||||
global.Logger.Errorf("[register] fail to send email to%s", req.UserName)
|
||||
return
|
||||
}
|
||||
apiReturn.Success(c)
|
||||
}
|
||||
|
||||
// 注册提交(开始注册)
|
||||
func (l *RegisterApi) Commit(c *gin.Context) {
|
||||
req := registerInfo{}
|
||||
err := c.ShouldBindJSON(&req)
|
||||
req.Email = req.UserName
|
||||
if err != nil {
|
||||
apiReturn.ErrorParamFomat(c, err.Error())
|
||||
return
|
||||
}
|
||||
errMsg, err := base.ValidateInputStruct(req)
|
||||
if err != nil {
|
||||
apiReturn.Error(c, errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证是否开启注册和后缀格式是否正确
|
||||
{
|
||||
systemSettingInfo := systemSetting.ApplicationSetting{}
|
||||
if err := global.SystemSetting.GetValueByInterface("system_application", &systemSettingInfo); err != nil || !systemSettingInfo.Register.OpenRegister {
|
||||
apiReturn.Error(c, global.Lang.Get("register.unopened_register"))
|
||||
return
|
||||
}
|
||||
|
||||
if systemSettingInfo.Register.EmailSuffix != "" && !cmn.VerifyFormat("^.*"+systemSettingInfo.Register.EmailSuffix+"$", req.Email) {
|
||||
apiReturn.Error(c, global.Lang.GetWithFields("register.emailSuffix_error", map[string]string{"EmailSuffix": systemSettingInfo.Register.EmailSuffix}))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 验证邮箱是否被注册
|
||||
{
|
||||
userCheck := &models.User{Mail: req.UserName}
|
||||
if _, err := userCheck.GetUserInfoByUsername(req.UserName); err == nil && err != gorm.ErrRecordNotFound {
|
||||
apiReturn.Error(c, global.Lang.Get("register.mail_exist"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 验证码验证
|
||||
{
|
||||
vCode, ok := global.VerifyCodeCachePool.Get(req.Email)
|
||||
if !ok {
|
||||
apiReturn.Error(c, global.Lang.Get("common.captcha_code_error"))
|
||||
//验证码不存在
|
||||
return
|
||||
}
|
||||
if vCode != req.EmailVCode {
|
||||
apiReturn.Error(c, global.Lang.Get("common.captcha_code_error"))
|
||||
return
|
||||
//验证码有误
|
||||
}
|
||||
}
|
||||
|
||||
// 自动生成用户昵称
|
||||
name := "用户" + cmn.BuildRandCode(4, cmn.RAND_CODE_MODE3)
|
||||
|
||||
//验证通过,注册
|
||||
user := &models.User{
|
||||
Mail: req.UserName,
|
||||
Name: name,
|
||||
Username: req.UserName,
|
||||
Password: cmn.PasswordEncryption(req.Password),
|
||||
Status: 1,
|
||||
Role: 2,
|
||||
}
|
||||
_, err = user.CreateOne()
|
||||
if err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
//删除旧的验证码
|
||||
global.VerifyCodeCachePool.Delete(req.Email)
|
||||
|
||||
apiReturn.Success(c)
|
||||
}
|
||||
|
||||
func generateEmailCode() string {
|
||||
return fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"sun-panel/api/api_v1/common/apiData/systemApiStructs"
|
||||
"sun-panel/api/api_v1/common/apiReturn"
|
||||
"sun-panel/api/api_v1/common/base"
|
||||
"sun-panel/global"
|
||||
"sun-panel/lib/cmn"
|
||||
"sun-panel/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
type UserApi struct{}
|
||||
|
||||
func (a *UserApi) GetInfo(c *gin.Context) {
|
||||
userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
apiReturn.SuccessData(c, gin.H{
|
||||
"userId": userInfo.ID,
|
||||
"id": userInfo.ID,
|
||||
"headImage": userInfo.HeadImage,
|
||||
"name": userInfo.Name,
|
||||
"role": userInfo.Role,
|
||||
// "token": userInfo.Token,
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// 修改资料
|
||||
func (a *UserApi) UpdateInfo(c *gin.Context) {
|
||||
userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
type UpdateUserInfoStruct struct {
|
||||
HeadImage string `json:"headImage"`
|
||||
Name string `json:"name" validate:"max=15,min=3,required"`
|
||||
}
|
||||
params := UpdateUserInfoStruct{}
|
||||
|
||||
err := c.ShouldBindBodyWith(¶ms, binding.JSON)
|
||||
if err != nil {
|
||||
apiReturn.ErrorParamFomat(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if errMsg, err := base.ValidateInputStruct(¶ms); err != nil {
|
||||
apiReturn.ErrorParamFomat(c, errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
mUser := models.User{}
|
||||
err = mUser.UpdateUserInfoByUserId(userInfo.ID, map[string]interface{}{
|
||||
"head_image": params.HeadImage,
|
||||
"name": params.Name,
|
||||
})
|
||||
// 删除缓存
|
||||
global.UserToken.Delete(userInfo.Token)
|
||||
if err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
}
|
||||
apiReturn.Success(c)
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
func (a *UserApi) UpdatePasssword(c *gin.Context) {
|
||||
type UpdatePasssStruct struct {
|
||||
OldPassword string `json:"oldPassword"`
|
||||
NewPassword string `json:"newPassword"`
|
||||
}
|
||||
|
||||
params := UpdatePasssStruct{}
|
||||
|
||||
err := c.ShouldBindBodyWith(¶ms, binding.JSON)
|
||||
if err != nil {
|
||||
apiReturn.ErrorParamFomat(c, err.Error())
|
||||
return
|
||||
}
|
||||
userInfo, _ := base.GetCurrentUserInfo(c)
|
||||
mUser := models.User{}
|
||||
if v, err := mUser.GetUserInfoByUid(userInfo.ID); err != nil {
|
||||
apiReturn.ErrorParamFomat(c, err.Error())
|
||||
return
|
||||
} else {
|
||||
if v.Password != cmn.PasswordEncryption(params.OldPassword) {
|
||||
// 旧密码不正确
|
||||
apiReturn.Error(c, global.Lang.Get("user.api_old_pass_error"))
|
||||
return
|
||||
}
|
||||
}
|
||||
res := global.Db.Model(&models.User{}).Where("id", userInfo.ID).Updates(map[string]interface{}{
|
||||
"password": cmn.PasswordEncryption(params.NewPassword),
|
||||
"token": "",
|
||||
})
|
||||
if res.Error != nil {
|
||||
apiReturn.ErrorDatabase(c, res.Error.Error())
|
||||
return
|
||||
}
|
||||
// 删除token
|
||||
global.UserToken.Delete(userInfo.Token)
|
||||
apiReturn.Success(c)
|
||||
}
|
||||
|
||||
// 获取推荐码
|
||||
func (a *UserApi) GetReferralCode(c *gin.Context) {
|
||||
currentUserInfo, _ := base.GetCurrentUserInfo(c)
|
||||
mUser := models.User{}
|
||||
userInfo, err := mUser.GetUserInfoByUid(currentUserInfo.ID)
|
||||
if err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 为空生成一个
|
||||
if userInfo.ReferralCode == "" {
|
||||
for {
|
||||
referralCode := cmn.BuildRandCode(8, cmn.RAND_CODE_MODE2)
|
||||
global.Logger.Debug("referralCode:", referralCode)
|
||||
|
||||
// 查询是否有重复的
|
||||
if row := global.Db.Find(&userInfo, "referral_code=?", referralCode).RowsAffected; row != 0 {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
// 创建新的邀请码
|
||||
if err := global.Db.Model(&models.User{}).Where("id=?", userInfo.ID).Update("referral_code", referralCode).Error; err != nil {
|
||||
apiReturn.ErrorDatabase(c, err.Error())
|
||||
return
|
||||
} else {
|
||||
userInfo.ReferralCode = referralCode
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apiReturn.SuccessData(c, systemApiStructs.GetReferralCodeResp{ReferralCode: userInfo.ReferralCode})
|
||||
}
|
||||
Reference in New Issue
Block a user