Files
go_blog/handlers/api.go
T
kevin a0061b14e3 feat: 评论接口 JSON 化——/api/article/:slug/comments 与 admin 审核操作
- comment.go:commentForm 加 json tag;PostComment 校验分支改 APIError
  (404 article_not_found、403 comments_disabled/comments_guests_disabled、
  400 校验码、500 article_error),保留 guest 令牌与 flash 机制,成功返回
  {ok,redirect:/article/:slug#comment-N,comment_id}
- api.go:新增 APIErrorf(支持 %d/%s 占位符键如 comments_too_long)
- admin_comment.go:approve/reject/delete 改 JSON(parseUintParam 拒绝非
  数值 id 400),成功带原 ?saved=1&msg= 查询串 redirect
- main.go:PostComment 迁入 /api;评论审核三操作迁入 /api/admin/comments
- article.html:评论表单改 blogAPI 提交,错误内联 commentError div
- comment_list.html:审核操作改 to commentAct() 委托(confirm 在函数内,
  取消不发请求),成功 reload 保持筛选状态
- 测试:security_test env 路由同步 /api;session_upload 评论用例改 JSON
- main_test 冒烟补评论 API 路由断言;go build/vet/test 全绿
2026-08-27 19:36:09 +08:00

71 lines
1.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handlers
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
// APIOK 返回统一成功响应。
// redirect 非空时附带相对跳转地址(原 302 目标,可含 ?saved=1 等 query);
// data 额外字段会合并进响应。
func APIOK(c *gin.Context, redirect string, data gin.H) {
resp := gin.H{"ok": true}
if redirect != "" {
resp["redirect"] = redirect
}
for k, v := range data {
resp[k] = v
}
c.JSON(http.StatusOK, resp)
}
// APIError 返回统一错误响应:{ok:false, code, error}。
// trKey 是 i18n 键,直接作为 code 返回;error 为该键按请求语言的翻译文案。
// trKey 为空时回退到通用键 "api_error"。
func APIError(c *gin.Context, status int, trKey string) {
tr := getTr(c)
code := trKey
if code == "" {
code = "api_error"
}
msg := tr[code]
if msg == "" {
msg = tr["api_error"]
}
c.JSON(status, gin.H{
"ok": false,
"code": code,
"error": msg,
})
}
// APIErrorf 同 APIError,但 i18n 文案可按 fmt.Sprintf 格式化
// (针对含 %d/%s 占位符的键,如 comments_too_long)。
func APIErrorf(c *gin.Context, status int, trKey string, args ...interface{}) {
tr := getTr(c)
msg := tr[trKey]
if msg == "" {
msg = tr["api_error"]
} else if len(args) > 0 {
msg = fmt.Sprintf(msg, args...)
}
c.JSON(status, gin.H{
"ok": false,
"code": trKey,
"error": msg,
})
}
// bindJSON 将 JSON 请求体绑定到 v。
// 绑定失败时返回 400 + api_invalid_request,并返回 false。
// 使用前必须保证请求是 JSONContent-Type: application/json)。
func bindJSON(c *gin.Context, v interface{}) bool {
if err := c.ShouldBindJSON(v); err != nil {
APIError(c, http.StatusBadRequest, "api_invalid_request")
return false
}
return true
}