merge: maestro/tsk_tFMU7-hKzfOf [tsk_tFMU7-hKzfOf] codes 激活码模块
解决与 1A 骨架的冲突:module 统一为 github.com/wangjia/pangolin/server (codes 分支原用 pangolin/server,7 个源文件 import 已改写); go.mod require 并集(redis 取 9.20.1);Makefile 以骨架为基底并入 build-codegen/test-unit/test-integration target。 go build/vet 通过,codes 单测通过。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
// Package apierr defines the bilingual error response type used across all API modules.
|
||||
// Error messages follow the desensitisation rules: no "VPN" / "翻墙" / "科学上网" wording.
|
||||
package apierr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Error is the canonical API error body: {code, message_zh, message_en}.
|
||||
type Error struct {
|
||||
Code string `json:"code"`
|
||||
MessageZH string `json:"message_zh"`
|
||||
MessageEn string `json:"message_en"`
|
||||
}
|
||||
|
||||
func (e *Error) Error() string { return e.Code + ": " + e.MessageEn }
|
||||
|
||||
// Standard code-module errors.
|
||||
var (
|
||||
ErrInvalidCode = &Error{
|
||||
Code: "INVALID_CODE",
|
||||
MessageZH: "激活码格式无效,请检查后重试",
|
||||
MessageEn: "Invalid code format, please verify and try again",
|
||||
}
|
||||
ErrCodeNotFound = &Error{
|
||||
Code: "CODE_NOT_FOUND",
|
||||
MessageZH: "激活码无效或已使用",
|
||||
MessageEn: "Code not found or already used",
|
||||
}
|
||||
ErrCodeRedeemed = &Error{
|
||||
Code: "CODE_REDEEMED",
|
||||
MessageZH: "该激活码已被其他账户使用",
|
||||
MessageEn: "This code has already been redeemed by another account",
|
||||
}
|
||||
ErrCodeVoid = &Error{
|
||||
Code: "CODE_VOID",
|
||||
MessageZH: "该激活码已失效",
|
||||
MessageEn: "This code is no longer valid",
|
||||
}
|
||||
ErrRateLimited = &Error{
|
||||
Code: "RATE_LIMITED",
|
||||
MessageZH: "操作过于频繁,请稍后再试",
|
||||
MessageEn: "Too many attempts, please try again later",
|
||||
}
|
||||
ErrLocked = &Error{
|
||||
Code: "ACCOUNT_LOCKED",
|
||||
MessageZH: "账户已临时锁定,请1小时后重试",
|
||||
MessageEn: "Account temporarily locked, please retry in 1 hour",
|
||||
}
|
||||
ErrInternal = &Error{
|
||||
Code: "INTERNAL_ERROR",
|
||||
MessageZH: "服务器内部错误,请稍后重试",
|
||||
MessageEn: "Internal server error, please try again later",
|
||||
}
|
||||
ErrBadRequest = &Error{
|
||||
Code: "BAD_REQUEST",
|
||||
MessageZH: "请求参数有误",
|
||||
MessageEn: "Invalid request parameters",
|
||||
}
|
||||
|
||||
// Webhook-specific errors.
|
||||
ErrWebhookSignature = &Error{
|
||||
Code: "WEBHOOK_INVALID_SIGNATURE",
|
||||
MessageZH: "签名校验失败",
|
||||
MessageEn: "Invalid webhook signature",
|
||||
}
|
||||
ErrWebhookTimestamp = &Error{
|
||||
Code: "WEBHOOK_TIMESTAMP_EXPIRED",
|
||||
MessageZH: "请求时间戳超出允许窗口",
|
||||
MessageEn: "Webhook timestamp outside allowed window",
|
||||
}
|
||||
ErrWebhookReplay = &Error{
|
||||
Code: "WEBHOOK_REPLAY",
|
||||
MessageZH: "重复请求已忽略",
|
||||
MessageEn: "Duplicate webhook request ignored",
|
||||
}
|
||||
)
|
||||
|
||||
// WriteJSON writes the given status code and error body as JSON.
|
||||
func WriteJSON(w http.ResponseWriter, status int, e *Error) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(status)
|
||||
_ = json.NewEncoder(w).Encode(e)
|
||||
}
|
||||
Reference in New Issue
Block a user