refactor: separate backend domains and storage adapters

This commit is contained in:
2026-08-14 01:37:56 +08:00
parent e6775f0966
commit 8c4c6ba661
102 changed files with 6644 additions and 5735 deletions
+58
View File
@@ -0,0 +1,58 @@
package handler
import (
"kra/internal/server/httpx"
"kra/internal/service"
"kra/internal/service/dto"
"github.com/gin-gonic/gin"
)
type APIToken struct {
service *service.SettingsService
}
func NewAPIToken(service *service.SettingsService) *APIToken {
return &APIToken{service: service}
}
func (h *APIToken) Create(c *gin.Context) {
var req dto.CreateAPITokenRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
token, err := h.service.CreateAPIToken(c.Request.Context(), req.UserID, req.AuthorityID, req.Days, req.Remark)
if err != nil {
httpx.Fail(c, "签发失败:"+err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"token": token}, "签发成功")
}
func (h *APIToken) List(c *gin.Context) {
var req dto.APITokenListRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
items, total, err := h.service.APITokens(c.Request.Context(), req.Page, req.PageSize, req.UserID, req.Status)
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
}
func (h *APIToken) Delete(c *gin.Context) {
var req dto.IDRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DisableAPIToken(c.Request.Context(), req.ID); err != nil {
httpx.Fail(c, "作废失败")
return
}
httpx.OK(c)
}
+241
View File
@@ -0,0 +1,241 @@
package handler
import (
"strconv"
"kra/internal/server/httpx"
"kra/internal/service"
"kra/internal/service/dto"
"github.com/gin-gonic/gin"
)
type Audit struct{ service *service.AuditService }
func NewAudit(service *service.AuditService) *Audit { return &Audit{service: service} }
func page(c *gin.Context) (int, int) {
value, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
size, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
return value, size
}
func IDsFromQuery(c *gin.Context) []uint {
values := c.QueryArray("IDs[]")
if len(values) == 0 {
values = c.QueryArray("ids[]")
}
ids := make([]uint, 0, len(values))
for _, value := range values {
id, _ := strconv.ParseUint(value, 10, 64)
if id > 0 {
ids = append(ids, uint(id))
}
}
return ids
}
func (h *Audit) Operations(c *gin.Context) {
p, size := page(c)
status, _ := strconv.Atoi(c.Query("status"))
userID, _ := strconv.ParseUint(c.Query("user_id"), 10, 64)
items, total, err := h.service.OperationsFilter(c.Request.Context(), p, size, c.Query("path"), c.Query("method"), status, c.Query("ip"), uint(userID))
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: p, PageSize: size}, "获取成功")
}
func (h *Audit) Operation(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := h.service.Operation(c.Request.Context(), uint(id))
if err != nil {
httpx.Fail(c, "查询失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"resysOperationRecord": item}, "查询成功")
}
func (h *Audit) DeleteOperation(c *gin.Context) {
var req dto.IDRequest
if c.ShouldBindJSON(&req) != nil || req.ID == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteOperations(c.Request.Context(), []uint{req.ID}); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Audit) DeleteOperations(c *gin.Context) {
var req dto.IDsRequest
if c.ShouldBindJSON(&req) != nil || len(req.IDs) == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteOperations(c.Request.Context(), req.IDs); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Audit) Logins(c *gin.Context) {
p, size := page(c)
items, total, err := h.service.LoginsFilter(c.Request.Context(), p, size, c.Query("username"), c.Query("ip"))
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: p, PageSize: size}, "获取成功")
}
func (h *Audit) Login(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := h.service.Login(c.Request.Context(), uint(id))
if err != nil {
httpx.Fail(c, "查询失败")
return
}
httpx.Write(c, httpx.CodeSuccess, item, "查询成功")
}
func (h *Audit) DeleteLogin(c *gin.Context) {
var req dto.IDRequest
if c.ShouldBindJSON(&req) != nil || req.ID == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteLogins(c.Request.Context(), []uint{req.ID}); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Audit) DeleteLogins(c *gin.Context) {
var req dto.IDsRequest
if c.ShouldBindJSON(&req) != nil || len(req.IDs) == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteLogins(c.Request.Context(), req.IDs); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Audit) DataAccess(c *gin.Context) {
var req dto.DataAccessListRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
items, total, err := h.service.DataAccessRequest(c.Request.Context(), &req)
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
}
func (h *Audit) DeleteDataAccess(c *gin.Context) {
var req dto.IDsRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteDataAccess(c.Request.Context(), req.IDs); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Audit) LogDates(c *gin.Context) {
data, err := h.service.LogDates(c.Request.Context(), c.Query("month"))
if err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, data, "获取成功")
}
func (h *Audit) LogFiles(c *gin.Context) {
data, err := h.service.LogFiles(c.Request.Context(), c.Query("date"))
if err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, data, "获取成功")
}
func (h *Audit) LogContent(c *gin.Context) {
var cursor *int64
if raw := c.Query("cursor"); raw != "" {
value, err := strconv.ParseInt(raw, 10, 64)
if err != nil || value < 0 {
httpx.Fail(c, "参数错误")
return
}
cursor = &value
}
data, err := h.service.LogContent(c.Request.Context(), c.Query("date"), c.Query("path"), cursor)
if err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, data, "获取成功")
}
func (h *Audit) DeleteError(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
if err := h.service.DeleteErrors(c.Request.Context(), []uint{uint(id)}); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Audit) DeleteErrors(c *gin.Context) {
if err := h.service.DeleteErrors(c.Request.Context(), IDsFromQuery(c)); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Audit) UpdateError(c *gin.Context) {
var req dto.ErrorRecordRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.UpdateErrorRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "更新失败")
return
}
httpx.OK(c)
}
func (h *Audit) Error(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := h.service.Error(c.Request.Context(), uint(id))
if err != nil {
httpx.Fail(c, "查询失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"resysError": item}, "查询成功")
}
func (h *Audit) Errors(c *gin.Context) {
p, size := page(c)
items, total, err := h.service.ErrorsFilter(c.Request.Context(), p, size, c.Query("form"), c.Query("level"), c.Query("status"))
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: p, PageSize: size}, "获取成功")
}
func (h *Audit) CreateError(c *gin.Context) {
var req dto.ErrorRecordRequest
if c.ShouldBindJSON(&req) != nil || req.Form == "" {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.CreateErrorRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "创建失败")
return
}
httpx.OK(c)
}
+189
View File
@@ -0,0 +1,189 @@
package handler
import (
"strconv"
"kra/internal/server/httpx"
"kra/internal/service"
"kra/internal/service/dto"
"github.com/gin-gonic/gin"
)
type Dictionary struct{ service *service.SettingsService }
func NewDictionary(service *service.SettingsService) *Dictionary {
return &Dictionary{service: service}
}
func (h *Dictionary) Create(c *gin.Context) {
var req dto.DictionaryRequest
if c.ShouldBindJSON(&req) != nil || req.Name == "" || req.Type == "" {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.CreateDictionaryRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "创建失败:"+err.Error())
return
}
httpx.OK(c)
}
func (h *Dictionary) Update(c *gin.Context) {
var req dto.DictionaryRequest
if c.ShouldBindJSON(&req) != nil || req.ID == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.UpdateDictionaryRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "更新失败")
return
}
httpx.OK(c)
}
func (h *Dictionary) Delete(c *gin.Context) {
var req dto.DictionaryRequest
if c.ShouldBindJSON(&req) != nil || req.ID == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteDictionary(c.Request.Context(), req.ID); err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.OK(c)
}
func (h *Dictionary) Find(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := h.service.Dictionary(c.Request.Context(), uint(id), c.Query("type"), true)
if err != nil {
httpx.Fail(c, "查询失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"reSysDictionary": item}, "查询成功")
}
func (h *Dictionary) List(details bool) gin.HandlerFunc {
return func(c *gin.Context) {
p, size := page(c)
items, total, err := h.service.Dictionaries(c.Request.Context(), p, size, c.Query("name"), c.Query("type"), details)
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: p, PageSize: size}, "获取成功")
}
}
func (h *Dictionary) Export(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := h.service.Dictionary(c.Request.Context(), uint(id), "", true)
if err != nil {
httpx.Fail(c, "导出失败")
return
}
delete(item, "ID")
delete(item, "CreatedAt")
delete(item, "UpdatedAt")
delete(item, "DeletedAt")
httpx.Write(c, httpx.CodeSuccess, item, "导出成功")
}
func (h *Dictionary) Import(c *gin.Context) {
var req dto.ImportDictionaryRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.ImportDictionaryJSON(c.Request.Context(), req.JSON); err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.OK(c)
}
func (h *Dictionary) CreateDetail(c *gin.Context) {
var req dto.DictionaryDetailRequest
if c.ShouldBindJSON(&req) != nil || req.DictionaryID == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.CreateDictionaryDetailRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "创建失败")
return
}
httpx.OK(c)
}
func (h *Dictionary) UpdateDetail(c *gin.Context) {
var req dto.DictionaryDetailRequest
if c.ShouldBindJSON(&req) != nil || req.ID == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.UpdateDictionaryDetailRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.OK(c)
}
func (h *Dictionary) DeleteDetail(c *gin.Context) {
var req dto.DictionaryDetailRequest
if c.ShouldBindJSON(&req) != nil || req.ID == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteDictionaryDetail(c.Request.Context(), req.ID); err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.OK(c)
}
func (h *Dictionary) FindDetail(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := h.service.DictionaryDetail(c.Request.Context(), uint(id))
if err != nil {
httpx.Fail(c, "查询失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"reSysDictionaryDetail": item}, "查询成功")
}
func (h *Dictionary) Details(c *gin.Context) {
p, size := page(c)
dictionaryID, _ := strconv.ParseUint(c.Query("sysDictionaryID"), 10, 64)
items, total, err := h.service.DictionaryDetails(c.Request.Context(), p, size, uint(dictionaryID), c.Query("label"), c.Query("value"))
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: p, PageSize: size}, "获取成功")
}
func (h *Dictionary) Tree(byType bool) gin.HandlerFunc {
return func(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("sysDictionaryID"), 10, 64)
typ := ""
if byType {
typ = c.Query("type")
}
items, err := h.service.DictionaryTree(c.Request.Context(), uint(id), typ)
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, items, "获取成功")
}
}
func (h *Dictionary) DetailsByParent(c *gin.Context) {
parentID, _ := strconv.ParseUint(c.Query("parentID"), 10, 64)
dictionaryID, _ := strconv.ParseUint(c.Query("sysDictionaryID"), 10, 64)
items, err := h.service.DictionaryDetailsByParent(c.Request.Context(), uint(dictionaryID), uint(parentID))
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, items, "获取成功")
}
func (h *Dictionary) Path(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := h.service.DictionaryDetail(c.Request.Context(), uint(id))
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"path": item["path"]}, "获取成功")
}
+193
View File
@@ -0,0 +1,193 @@
package handler
import (
"encoding/json"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"kra/internal/server/httpx"
"kra/internal/service"
"kra/internal/service/dto"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type Export struct {
system *service.SystemService
service *service.ExportService
}
func NewExport(system *service.SystemService, service *service.ExportService) *Export {
return &Export{system: system, service: service}
}
type exportToken struct {
TemplateID string `json:"templateID"`
Params map[string]string `json:"params"`
Blank bool `json:"blank"`
}
func exportParams(values url.Values) map[string]string {
out := map[string]string{}
nested, _ := url.ParseQuery(values.Get("params"))
for key, items := range nested {
if len(items) > 0 {
out[key] = items[0]
}
}
for key, items := range values {
if key != "params" && len(items) > 0 {
out[key] = items[0]
}
}
return out
}
func (h *Export) Create(c *gin.Context) {
var req dto.ExportTemplateRequest
if c.ShouldBindJSON(&req) != nil || req.Name == "" || req.TemplateID == "" {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.CreateRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "创建失败:"+err.Error())
return
}
httpx.OK(c)
}
func (h *Export) Update(c *gin.Context) {
var req dto.ExportTemplateRequest
if c.ShouldBindJSON(&req) != nil || req.ID == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.UpdateRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "更新失败:"+err.Error())
return
}
httpx.OK(c)
}
func (h *Export) Delete(c *gin.Context) {
var req dto.IDRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.Delete(c.Request.Context(), []uint{req.ID}); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Export) DeleteMany(c *gin.Context) {
var req dto.IDsRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.Delete(c.Request.Context(), req.IDs); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Export) Find(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := h.service.Template(c.Request.Context(), uint(id), "")
if err != nil {
httpx.Fail(c, "查询失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"resysExportTemplate": item}, "查询成功")
}
func (h *Export) List(c *gin.Context) {
p, size := page(c)
items, total, err := h.service.TemplatesFilter(c.Request.Context(), p, size, c.Query("name"), c.Query("tableName"), c.Query("templateID"))
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: p, PageSize: size}, "获取成功")
}
func (h *Export) Preview(c *gin.Context) {
sql, err := h.service.Preview(c.Request.Context(), c.Query("templateID"), exportParams(c.Request.URL.Query()))
if err != nil {
httpx.Fail(c, "预览失败:"+err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"sql": sql}, "获取成功")
}
func (h *Export) Issue(blank bool) gin.HandlerFunc {
return func(c *gin.Context) {
templateID := c.Query("templateID")
if templateID == "" {
httpx.Fail(c, "模板ID不能为空")
return
}
token := strings.ReplaceAll(uuid.NewString(), "-", "")
raw, _ := json.Marshal(exportToken{TemplateID: templateID, Params: exportParams(c.Request.URL.Query()), Blank: blank})
if err := h.system.CacheSet(c.Request.Context(), "export:"+token, string(raw), 5*time.Minute); err != nil {
httpx.Fail(c, "导出令牌创建失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"token": token}, "获取成功")
}
}
func (h *Export) Import(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
httpx.Fail(c, "请选择导入文件")
return
}
opened, err := file.Open()
if err != nil {
httpx.Fail(c, "读取文件失败")
return
}
defer opened.Close()
templateID := c.PostForm("templateID")
if templateID == "" {
templateID = c.Query("templateID")
}
if err = h.service.Import(c.Request.Context(), templateID, opened); err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.OK(c)
}
func (h *Export) Download(expectBlank bool) gin.HandlerFunc {
return func(c *gin.Context) {
token := c.Query("token")
raw, ok, err := h.system.CacheGet(c.Request.Context(), "export:"+token)
if err != nil || !ok {
httpx.Fail(c, "导出令牌无效或已过期")
return
}
_ = h.system.CacheDelete(c.Request.Context(), "export:"+token)
var value exportToken
if json.Unmarshal([]byte(raw), &value) != nil || value.Blank != expectBlank {
httpx.Fail(c, "导出令牌无效")
return
}
var data []byte
var name string
if expectBlank {
data, name, err = h.service.ExportBlankTemplate(c.Request.Context(), value.TemplateID)
} else {
data, name, err = h.service.Export(c.Request.Context(), value.TemplateID, value.Params)
}
if err != nil {
httpx.Fail(c, "导出失败:"+err.Error())
return
}
c.Header("Content-Disposition", "attachment; filename*=UTF-8''"+url.QueryEscape(name))
c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", data)
}
}
+230
View File
@@ -0,0 +1,230 @@
package handler
import (
"strconv"
"kra/internal/server/httpx"
servermiddleware "kra/internal/server/middleware"
"kra/internal/service"
"kra/internal/service/dto"
"github.com/gin-gonic/gin"
)
type Media struct{ service *service.MediaService }
func NewMedia(service *service.MediaService) *Media { return &Media{service: service} }
func (h *Media) Upload(c *gin.Context) {
claims := servermiddleware.Claims(c)
header, err := c.FormFile("file")
if claims == nil || err != nil {
httpx.Fail(c, "接收文件失败")
return
}
opened, err := header.Open()
if err != nil {
httpx.Fail(c, "读取文件失败")
return
}
defer opened.Close()
category, _ := strconv.Atoi(c.DefaultPostForm("classId", "0"))
save := c.DefaultQuery("noSave", "0") == "0"
item, err := h.service.Upload(c.Request.Context(), claims.ID, header.Filename, header.Header.Get("Content-Type"), category, opened, save)
if err != nil {
httpx.Fail(c, "上传失败:"+err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"file": item}, "上传成功")
}
func (h *Media) List(c *gin.Context) {
var req dto.MediaListRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
items, total, err := h.service.MediaList(c.Request.Context(), req.Page, req.PageSize, req.Keyword, req.ClassID, req.Tag, req.UserID)
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
}
func (h *Media) Delete(c *gin.Context) {
var req dto.IDRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.Delete(c.Request.Context(), req.ID); err != nil {
httpx.Fail(c, "删除失败:"+err.Error())
return
}
httpx.OK(c)
}
func (h *Media) DeleteMany(c *gin.Context) {
var req dto.IDsRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
failed := []uint{}
for _, id := range req.IDs {
if h.service.Delete(c.Request.Context(), id) != nil {
failed = append(failed, id)
}
}
if len(failed) > 0 {
httpx.Write(c, httpx.CodeSuccess, gin.H{"failedIds": failed}, "部分文件删除失败")
return
}
httpx.OK(c)
}
func (h *Media) Find(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("id"), 10, 64)
item, err := h.service.Media(c.Request.Context(), uint(id))
if err != nil {
httpx.Fail(c, "查询失败")
return
}
httpx.Write(c, httpx.CodeSuccess, item, "获取成功")
}
func (h *Media) Rename(c *gin.Context) {
var req dto.RenameMediaRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.Rename(c.Request.Context(), req.ID, req.Name); err != nil {
httpx.Fail(c, "编辑失败")
return
}
httpx.OK(c)
}
func (h *Media) ImportURLs(c *gin.Context) {
var req []dto.ImportMediaRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
claims := servermiddleware.Claims(c)
if claims == nil {
httpx.Fail(c, "未登录")
return
}
if err := h.service.ImportURLRequests(c.Request.Context(), claims.ID, req); err != nil {
httpx.Fail(c, "导入失败")
return
}
httpx.OK(c)
}
func (h *Media) Storage(c *gin.Context) {
var req dto.StorageListRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
items, next, more, err := h.service.Storage(c.Request.Context(), req.Prefix, req.Cursor, req.Limit)
if err != nil {
httpx.Fail(c, "列举失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"list": items, "nextCursor": next, "hasMore": more}, "获取成功")
}
func (h *Media) Categories(c *gin.Context) {
items, err := h.service.Categories(c.Request.Context())
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, items, "获取成功")
}
func (h *Media) SaveCategory(c *gin.Context) {
var req dto.CategoryRequest
if c.ShouldBindJSON(&req) != nil || req.Name == "" {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.SaveCategoryRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.OK(c)
}
func (h *Media) DeleteCategory(c *gin.Context) {
var req dto.IDRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteCategory(c.Request.Context(), req.ID); err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.OK(c)
}
func (h *Media) InitUpload(c *gin.Context) {
claims := servermiddleware.Claims(c)
var req dto.InitUploadRequest
if claims == nil || c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
result, err := h.service.InitUpload(c.Request.Context(), claims.ID, req.FileName, req.FileHash, req.FileSize, req.ChunkSize, req.ChunkTotal)
if err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, result, "获取成功")
}
func (h *Media) SaveChunk(c *gin.Context) {
claims := servermiddleware.Claims(c)
uploadID, _ := strconv.ParseUint(c.PostForm("uploadId"), 10, 64)
index, _ := strconv.Atoi(c.PostForm("chunkIndex"))
header, err := c.FormFile("chunk")
if claims == nil || err != nil {
httpx.Fail(c, "接收分片失败")
return
}
opened, err := header.Open()
if err != nil {
httpx.Fail(c, "读取分片失败")
return
}
defer opened.Close()
if err = h.service.SaveChunk(c.Request.Context(), claims.ID, uint(uploadID), index, c.PostForm("chunkHash"), opened); err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.OK(c)
}
func (h *Media) CompleteUpload(c *gin.Context) {
claims := servermiddleware.Claims(c)
var req dto.CompleteUploadRequest
if claims == nil || c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
item, err := h.service.CompleteUpload(c.Request.Context(), claims.ID, req.UploadID)
if err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"media": item}, "上传成功")
}
func (h *Media) CancelUpload(c *gin.Context) {
claims := servermiddleware.Claims(c)
id, _ := strconv.ParseUint(c.Param("uploadId"), 10, 64)
if claims == nil {
httpx.Fail(c, "未登录")
return
}
if err := h.service.CancelUpload(c.Request.Context(), claims.ID, uint(id)); err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.OK(c)
}
+26
View File
@@ -0,0 +1,26 @@
package handler
import (
"kra/internal/server/httpx"
"kra/internal/server/middleware"
"kra/internal/service"
"github.com/gin-gonic/gin"
)
type Navigation struct{ service *service.SystemService }
func NewNavigation(service *service.SystemService) *Navigation { return &Navigation{service: service} }
func (h *Navigation) Menu(c *gin.Context) {
claims := middleware.Claims(c)
if claims == nil {
httpx.NoAuth(c, "未登录或非法访问")
return
}
menus, err := h.service.Menus(c.Request.Context(), claims.AuthorityID)
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"menus": menus}, "获取成功")
}
+100
View File
@@ -0,0 +1,100 @@
package handler
import (
"strconv"
"kra/internal/server/httpx"
"kra/internal/service"
"kra/internal/service/dto"
"github.com/gin-gonic/gin"
)
type Parameter struct {
service *service.SettingsService
}
func NewParameter(service *service.SettingsService) *Parameter {
return &Parameter{service: service}
}
func (h *Parameter) Create(c *gin.Context) {
var req dto.SystemParameterRequest
if c.ShouldBindJSON(&req) != nil || req.Key == "" {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.CreateParameterRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "创建失败")
return
}
httpx.OK(c)
}
func (h *Parameter) Update(c *gin.Context) {
var req dto.SystemParameterRequest
if c.ShouldBindJSON(&req) != nil || req.ID == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.UpdateParameterRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "更新失败")
return
}
httpx.OK(c)
}
func (h *Parameter) Delete(c *gin.Context) {
id, err := strconv.ParseUint(c.Query("ID"), 10, 64)
if err != nil || id == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteParameters(c.Request.Context(), []uint{uint(id)}); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Parameter) DeleteMany(c *gin.Context) {
ids := IDsFromQuery(c)
if len(ids) == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteParameters(c.Request.Context(), ids); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Parameter) Find(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := h.service.Parameter(c.Request.Context(), uint(id), "")
if err != nil {
httpx.Fail(c, "查询失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"resysParams": item}, "查询成功")
}
func (h *Parameter) Get(c *gin.Context) {
item, err := h.service.Parameter(c.Request.Context(), 0, c.Query("key"))
if err != nil {
httpx.Fail(c, "查询失败")
return
}
httpx.Write(c, httpx.CodeSuccess, item, "查询成功")
}
func (h *Parameter) List(c *gin.Context) {
p, size := page(c)
items, total, err := h.service.ParametersFilter(c.Request.Context(), p, size, c.Query("name"), c.Query("key"))
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: p, PageSize: size}, "获取成功")
}
+200
View File
@@ -0,0 +1,200 @@
package handler
import (
"context"
"net/http"
"strconv"
"strings"
"time"
"kra/internal/conf"
"kra/internal/server/httpx"
"kra/internal/service"
"kra/internal/service/dto"
"kra/internal/worker"
"github.com/gin-gonic/gin"
"github.com/mojocn/base64Captcha"
)
type Public struct {
system *service.SystemService
settings *service.SettingsService
audit *service.AuditService
scheduler *worker.TaskScheduler
store *captchaStore
keyLong int
imageWidth int
imageHeight int
}
func NewPublic(config *conf.AdminBackend, system *service.SystemService, settings *service.SettingsService, audit *service.AuditService, scheduler *worker.TaskScheduler) *Public {
expiration := 3 * time.Minute
keyLong, width, height := 6, 240, 80
if config != nil && config.Captcha != nil {
if config.Captcha.StoreExpiration != nil {
expiration = config.Captcha.StoreExpiration.AsDuration()
}
if config.Captcha.KeyLong > 0 {
keyLong = int(config.Captcha.KeyLong)
}
if config.Captcha.ImgWidth > 0 {
width = int(config.Captcha.ImgWidth)
}
if config.Captcha.ImgHeight > 0 {
height = int(config.Captcha.ImgHeight)
}
}
return &Public{system: system, settings: settings, audit: audit, scheduler: scheduler, store: &captchaStore{service: system, expiration: expiration}, keyLong: keyLong, imageWidth: width, imageHeight: height}
}
func (h *Public) Captcha(c *gin.Context) {
keyLong, width, height := h.keyLong, h.imageWidth, h.imageHeight
security, _ := h.settings.CurrentSecurity(c.Request.Context())
openCaptcha := true
if security != nil {
keyLong, width, height = security.KeyLong, security.ImgWidth, security.ImgHeight
if security.CaptchaOpen > 0 {
failures, _ := cachedInt(c.Request.Context(), h.system, "login:fail:"+c.ClientIP())
openCaptcha = failures >= security.CaptchaOpen
}
}
if !openCaptcha {
httpx.Write(c, httpx.CodeSuccess, gin.H{"captchaId": "", "picPath": "", "captchaLength": keyLong, "openCaptcha": false}, "验证码获取成功")
return
}
driver := base64Captcha.NewDriverDigit(height, width, keyLong, 0.7, 80)
id, picture, _, err := base64Captcha.NewCaptcha(driver, h.store).Generate()
if err != nil {
httpx.Fail(c, "验证码获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"captchaId": id, "picPath": picture, "captchaLength": keyLong, "openCaptcha": openCaptcha}, "验证码获取成功")
}
func (h *Public) Login(c *gin.Context) {
var req dto.LoginRequest
if c.ShouldBindJSON(&req) != nil || req.Username == "" || req.Password == "" {
httpx.Fail(c, "请输入用户名和密码")
return
}
security, _ := h.settings.CurrentSecurity(c.Request.Context())
if security != nil && security.LockEnable {
if _, locked, _ := h.system.CacheGet(c.Request.Context(), "login:lock:"+req.Username); locked {
httpx.Fail(c, "账户已锁定,请稍后重试")
return
}
}
requireCaptcha := security == nil || security.CaptchaOpen == 0
if security != nil && security.CaptchaOpen > 0 {
failures, _ := cachedInt(c.Request.Context(), h.system, "login:fail:"+c.ClientIP())
requireCaptcha = failures >= security.CaptchaOpen
}
if requireCaptcha && (req.CaptchaID == "" || req.Captcha == "" || !h.store.Verify(req.CaptchaID, req.Captcha, true)) {
httpx.Fail(c, "验证码错误")
return
}
result, err := h.system.Login(c.Request.Context(), req.Username, req.Password)
if err != nil {
_ = h.audit.RecordLoginRequest(c.Request.Context(), &dto.LoginLogRequest{Username: req.Username, IP: c.ClientIP(), Status: false, ErrorMessage: "用户名不存在或者密码错误", Agent: c.Request.UserAgent()})
ttl := time.Hour
if security != nil && security.CaptchaTimeout > 0 {
ttl = time.Duration(security.CaptchaTimeout) * time.Second
}
failures, _ := incrementCached(c.Request.Context(), h.system, "login:fail:"+c.ClientIP(), ttl)
if security != nil && security.LockEnable && failures >= security.LockThreshold {
_ = h.system.CacheSet(c.Request.Context(), "login:lock:"+req.Username, "1", time.Duration(security.LockDuration)*time.Minute)
}
httpx.Fail(c, "用户名不存在或者密码错误")
return
}
userID, _ := result.User["ID"].(uint)
_ = h.audit.RecordLoginRequest(c.Request.Context(), &dto.LoginLogRequest{Username: req.Username, IP: c.ClientIP(), Status: true, Agent: c.Request.UserAgent(), UserID: userID})
_ = h.system.CacheDelete(c.Request.Context(), "login:fail:"+c.ClientIP())
_ = h.system.CacheDelete(c.Request.Context(), "login:lock:"+req.Username)
maxAge := int(time.Until(time.UnixMilli(result.ExpiresAt)).Seconds())
http.SetCookie(c.Writer, &http.Cookie{Name: "x-token", Value: result.Token, Path: "/", MaxAge: maxAge, HttpOnly: true, SameSite: http.SameSiteStrictMode})
httpx.Write(c, httpx.CodeSuccess, result, "登录成功")
}
func (h *Public) CheckDatabase(c *gin.Context) {
initialized, err := h.system.IsInitialized(c.Request.Context())
if err != nil {
httpx.Fail(c, "数据库状态检查失败")
return
}
message := "数据库无需初始化"
if !initialized {
message = "前往初始化数据库"
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"needInit": !initialized}, message)
}
func (h *Public) InitializeDatabase(engine *gin.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
initialized, err := h.system.IsInitialized(c.Request.Context())
if err != nil {
httpx.Fail(c, "数据库状态检查失败")
return
}
if initialized {
httpx.Fail(c, "数据库已初始化,无需重复初始化")
return
}
var input service.DatabaseInit
if c.ShouldBindJSON(&input) != nil {
httpx.Fail(c, "数据库初始化参数无效")
return
}
routes := engine.Routes()
values := make([]dto.Route, 0, len(routes))
for _, route := range routes {
values = append(values, dto.Route{Path: route.Path, Method: route.Method})
}
if err := h.system.InitializeRoutes(c.Request.Context(), &input, values); err != nil {
httpx.Fail(c, "自动创建数据库失败: "+err.Error())
return
}
if err := h.scheduler.Reload(c.Request.Context()); err != nil {
httpx.Fail(c, "数据库已初始化,但定时任务加载失败:"+err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{}, "自动创建数据库成功")
}
}
func cachedInt(ctx context.Context, system *service.SystemService, key string) (int, error) {
value, ok, err := system.CacheGet(ctx, key)
if err != nil || !ok {
return 0, err
}
return strconv.Atoi(value)
}
func incrementCached(ctx context.Context, system *service.SystemService, key string, ttl time.Duration) (int, error) {
value, err := system.CacheIncrement(ctx, key, ttl)
return int(value), err
}
type captchaStore struct {
service *service.SystemService
expiration time.Duration
}
func (s *captchaStore) key(id string) string { return "captcha:" + id }
func (s *captchaStore) Set(id, value string) error {
return s.service.CacheSet(context.Background(), s.key(id), value, s.expiration)
}
func (s *captchaStore) Get(id string, clear bool) string {
value, ok, err := s.service.CacheGet(context.Background(), s.key(id))
if err != nil || !ok {
return ""
}
if clear {
_ = s.service.CacheDelete(context.Background(), s.key(id))
}
return value
}
func (s *captchaStore) Verify(id, answer string, clear bool) bool {
return id != "" && answer != "" && strings.EqualFold(s.Get(id, clear), answer)
}
+26
View File
@@ -0,0 +1,26 @@
package handler
import (
"net/http"
"kra/internal/server/httpx"
"kra/internal/service"
"github.com/gin-gonic/gin"
)
type Session struct{ settings *service.SettingsService }
func NewSession(settings *service.SettingsService) *Session { return &Session{settings: settings} }
func (h *Session) Logout(c *gin.Context) {
token := c.GetHeader("x-token")
if token == "" {
token, _ = c.Cookie("x-token")
}
if err := h.settings.BlacklistToken(c.Request.Context(), token); err != nil {
httpx.Fail(c, "退出失败")
return
}
http.SetCookie(c.Writer, &http.Cookie{Name: "x-token", Value: "", Path: "/", MaxAge: -1, HttpOnly: true})
httpx.OK(c)
}
+101
View File
@@ -0,0 +1,101 @@
package handler
import (
"runtime"
"syscall"
"time"
"kra/internal/server/httpx"
"kra/internal/service"
"kra/internal/service/dto"
"kra/internal/worker"
"github.com/gin-gonic/gin"
"github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/mem"
)
type SystemConfig struct {
system *service.SystemService
settings *service.SettingsService
scheduler *worker.TaskScheduler
}
func NewSystemConfig(system *service.SystemService, settings *service.SettingsService, scheduler *worker.TaskScheduler) *SystemConfig {
return &SystemConfig{system: system, settings: settings, scheduler: scheduler}
}
func (h *SystemConfig) GetSecurity(c *gin.Context) {
value, err := h.settings.Security(c.Request.Context())
if err != nil {
httpx.Fail(c, "获取安全配置失败")
return
}
httpx.Write(c, httpx.CodeSuccess, value, "获取成功")
}
func (h *SystemConfig) SetSecurity(c *gin.Context) {
var req dto.SecurityConfigRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
result, err := h.settings.SaveSecurityRequest(c.Request.Context(), &req)
if err != nil {
httpx.Fail(c, err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, result, "设置成功")
}
func (h *SystemConfig) Get(c *gin.Context) {
httpx.Write(c, httpx.CodeSuccess, h.system.SystemConfig(), "获取成功")
}
func (h *SystemConfig) Set(c *gin.Context) {
var req dto.SetSystemConfigRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.system.SaveSystemConfig(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "配置保存失败: "+err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{}, "设置成功")
}
func (h *SystemConfig) Reload(c *gin.Context) {
if err := h.system.ReloadConfig(c.Request.Context()); err != nil {
httpx.Fail(c, "重载系统失败:"+err.Error())
return
}
if err := h.scheduler.Reload(c.Request.Context()); err != nil {
httpx.Fail(c, "系统配置已重载,但定时任务重载失败:"+err.Error())
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{}, "重载系统成功")
}
func (h *SystemConfig) ServerInfo(c *gin.Context) {
cpuPercent, _ := cpu.Percent(200*time.Millisecond, false)
memory, _ := mem.VirtualMemory()
disk := []gin.H{}
var stat syscall.Statfs_t
if syscall.Statfs(".", &stat) == nil {
total := uint64(stat.Blocks) * uint64(stat.Bsize)
free := uint64(stat.Bavail) * uint64(stat.Bsize)
used := total - free
percent := 0
if total > 0 {
percent = int(used * 100 / total)
}
disk = append(disk, gin.H{"mountPoint": ".", "usedMb": used / 1024 / 1024, "usedGb": used / 1024 / 1024 / 1024, "totalMb": total / 1024 / 1024, "totalGb": total / 1024 / 1024 / 1024, "usedPercent": percent})
}
usedMB, totalMB, memoryPercent := uint64(0), uint64(0), float64(0)
if memory != nil {
usedMB, totalMB, memoryPercent = memory.Used/1024/1024, memory.Total/1024/1024, memory.UsedPercent
}
server := gin.H{"os": gin.H{"goos": runtime.GOOS, "numCpu": runtime.NumCPU(), "compiler": runtime.Compiler, "goVersion": runtime.Version(), "numGoroutine": runtime.NumGoroutine()}, "cpu": gin.H{"cpus": cpuPercent, "cores": runtime.NumCPU()}, "ram": gin.H{"usedMb": usedMB, "totalMb": totalMB, "usedPercent": memoryPercent}, "disk": disk}
httpx.Write(c, httpx.CodeSuccess, gin.H{"server": server}, "获取成功")
}
+178
View File
@@ -0,0 +1,178 @@
package handler
import (
"net/http"
"strconv"
"time"
"kra/internal/server/httpx"
"kra/internal/server/middleware"
"kra/internal/service"
"kra/internal/service/dto"
"github.com/gin-gonic/gin"
)
type User struct{ service *service.SystemService }
func NewUser(service *service.SystemService) *User { return &User{service: service} }
func (h *User) List(c *gin.Context) {
var req dto.UserListRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
items, total, err := h.service.ListUsersRequest(c.Request.Context(), &req)
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: req.Page, PageSize: req.PageSize}, "获取成功")
}
func (h *User) Create(c *gin.Context) {
var req dto.UserRequest
if c.ShouldBindJSON(&req) != nil || req.Username == "" || req.Password == "" {
httpx.Fail(c, "参数错误")
return
}
result, err := h.service.CreateUserRequest(c.Request.Context(), &req)
if err != nil {
httpx.Fail(c, "注册失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"user": result}, "注册成功")
}
func (h *User) Update(c *gin.Context) {
var req dto.UserRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.UpdateUserRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "修改失败")
return
}
httpx.OK(c)
}
func (h *User) UpdateSelf(c *gin.Context) {
claims := middleware.Claims(c)
if claims == nil {
httpx.NoAuth(c, "未登录或非法访问")
return
}
var req dto.SelfUserRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
value := &dto.UserRequest{ID: claims.ID, NickName: req.NickName, HeaderImg: req.HeaderImg, Phone: req.Phone, Email: req.Email, Enable: 1}
if err := h.service.UpdateUserRequest(c.Request.Context(), value); err != nil {
httpx.Fail(c, "修改失败")
return
}
httpx.OK(c)
}
func (h *User) Delete(c *gin.Context) {
var req dto.IDRequest
if c.ShouldBind(&req) != nil || req.ID == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.DeleteUser(c.Request.Context(), req.ID); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *User) ResetPassword(c *gin.Context) {
var req dto.ResetPasswordRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.ResetPassword(c.Request.Context(), req.ID, req.Password); err != nil {
httpx.Fail(c, "重置失败")
return
}
httpx.OK(c)
}
func (h *User) ChangePassword(c *gin.Context) {
claims := middleware.Claims(c)
var req dto.ChangePasswordRequest
if claims == nil || c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.ChangePassword(c.Request.Context(), claims.ID, req.Password, req.NewPassword); err != nil {
httpx.Fail(c, "修改失败,原密码与当前账户不符")
return
}
httpx.OK(c)
}
func (h *User) SetSelfSetting(c *gin.Context) {
claims := middleware.Claims(c)
var setting map[string]any
if claims == nil || c.ShouldBindJSON(&setting) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.SetUserSetting(c.Request.Context(), claims.ID, setting); err != nil {
httpx.Fail(c, "设置失败")
return
}
httpx.OK(c)
}
func (h *User) SetAuthorities(c *gin.Context) {
var req dto.UserAuthoritiesRequest
if c.ShouldBindJSON(&req) != nil || req.ID == 0 || len(req.AuthorityIDs) == 0 {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.SetUserAuthorities(c.Request.Context(), req.ID, req.AuthorityIDs); err != nil {
httpx.Fail(c, "修改失败")
return
}
httpx.OK(c)
}
func (h *User) SwitchAuthority(c *gin.Context) {
claims := middleware.Claims(c)
var req dto.SwitchAuthorityRequest
if claims == nil || c.ShouldBindJSON(&req) != nil || req.AuthorityID == 0 {
httpx.Fail(c, "参数错误")
return
}
login, err := h.service.SwitchAuthority(c.Request.Context(), claims.ID, req.AuthorityID)
if err != nil {
httpx.Fail(c, err.Error())
return
}
c.Header("new-token", login.Token)
c.Header("new-expires-at", strconv.FormatInt(login.ExpiresAt/1000, 10))
maxAge := int(time.Until(time.UnixMilli(login.ExpiresAt)).Seconds())
http.SetCookie(c.Writer, &http.Cookie{Name: "x-token", Value: login.Token, Path: "/", MaxAge: maxAge, HttpOnly: true, SameSite: http.SameSiteStrictMode})
httpx.OK(c)
}
func (h *User) Get(c *gin.Context) {
claims := middleware.Claims(c)
if claims == nil {
httpx.NoAuth(c, "未登录或非法访问")
return
}
result, err := h.service.User(c.Request.Context(), claims.ID)
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, gin.H{"userInfo": result}, "获取成功")
}
+93
View File
@@ -0,0 +1,93 @@
package handler
import (
"fmt"
"net/http"
"strconv"
"time"
"kra/internal/server/httpx"
"kra/internal/service"
"kra/internal/service/dto"
"github.com/gin-gonic/gin"
)
type Version struct{ service *service.VersionService }
func NewVersion(service *service.VersionService) *Version { return &Version{service: service} }
func (h *Version) Delete(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
if err := h.service.DeleteVersions(c.Request.Context(), []uint{uint(id)}); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Version) DeleteMany(c *gin.Context) {
raw := c.QueryArray("IDs[]")
ids := make([]uint, 0, len(raw))
for _, value := range raw {
id, _ := strconv.ParseUint(value, 10, 64)
ids = append(ids, uint(id))
}
if err := h.service.DeleteVersions(c.Request.Context(), ids); err != nil {
httpx.Fail(c, "删除失败")
return
}
httpx.OK(c)
}
func (h *Version) Find(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
item, err := h.service.Version(c.Request.Context(), uint(id))
if err != nil {
httpx.Fail(c, "查询失败")
return
}
httpx.Write(c, httpx.CodeSuccess, item, "查询成功")
}
func (h *Version) List(c *gin.Context) {
p, size := page(c)
items, total, err := h.service.Versions(c.Request.Context(), p, size, c.Query("versionName"), c.Query("versionCode"))
if err != nil {
httpx.Fail(c, "获取失败")
return
}
httpx.Write(c, httpx.CodeSuccess, httpx.PageResult{List: items, Total: total, Page: p, PageSize: size}, "获取成功")
}
func (h *Version) Export(c *gin.Context) {
var req dto.ExportVersionRequest
if c.ShouldBindJSON(&req) != nil || req.VersionName == "" || req.VersionCode == "" {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.Export(c.Request.Context(), req.VersionName, req.VersionCode, req.Description, req.MenuIDs, req.APIIDs, req.DictIDs); err != nil {
httpx.Fail(c, "创建发版失败:"+err.Error())
return
}
httpx.OK(c)
}
func (h *Version) Download(c *gin.Context) {
id, _ := strconv.ParseUint(c.Query("ID"), 10, 64)
raw, code, err := h.service.VersionData(c.Request.Context(), uint(id))
if err != nil {
httpx.Fail(c, "下载失败")
return
}
name := fmt.Sprintf("version_%s_%s.json", code, time.Now().Format("20060102150405"))
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", name))
c.Data(http.StatusOK, "application/json; charset=utf-8", []byte(raw))
}
func (h *Version) Import(c *gin.Context) {
var req dto.ImportVersionRequest
if c.ShouldBindJSON(&req) != nil {
httpx.Fail(c, "参数错误")
return
}
if err := h.service.ImportRequest(c.Request.Context(), &req); err != nil {
httpx.Fail(c, "导入失败:"+err.Error())
return
}
httpx.OK(c)
}