mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-09-18 08:14:55 +08:00
fix(tm):建立 Trusted 唯一性与 Supersede 治理
This commit is contained in:
+116
-4
@@ -56,6 +56,7 @@ func (s *Server) handleAdminIndex(w http.ResponseWriter, r *http.Request) {
|
||||
"/admin/translation/handoff",
|
||||
"/admin/translation/memory/summary",
|
||||
"/admin/translation/memory/query",
|
||||
"/admin/translation/memory/conflicts",
|
||||
"/admin/translation/glossary/summary",
|
||||
"/admin/translation/glossary/query",
|
||||
"/admin/translation/glossary/diagnose",
|
||||
@@ -78,6 +79,7 @@ func (s *Server) handleAdminIndex(w http.ResponseWriter, r *http.Request) {
|
||||
"/admin/control/translation-worker-run",
|
||||
"/admin/control/translation-proofread",
|
||||
"/admin/control/translation-memory-confirm",
|
||||
"/admin/control/translation-memory-resolve-conflict",
|
||||
"/admin/control/translation-glossary-add",
|
||||
"/admin/control/translation-glossary-update",
|
||||
"/admin/control/translation-glossary-approve",
|
||||
@@ -133,6 +135,10 @@ func (s *Server) handleAdminControl(w http.ResponseWriter, r *http.Request) {
|
||||
s.handleAdminTranslationMemoryConfirm(w, r)
|
||||
return
|
||||
}
|
||||
if action == "translation-memory-resolve-conflict" {
|
||||
s.handleAdminTranslationMemoryResolveConflict(w, r)
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(action, "translation-glossary-") {
|
||||
s.handleAdminGlossaryControl(w, r, action)
|
||||
return
|
||||
@@ -222,6 +228,34 @@ func (s *Server) handleAdminControl(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) handleAdminTranslationMemoryResolveConflict(w http.ResponseWriter, r *http.Request) {
|
||||
backend, ok := s.backend.(TranslationMemoryBackend)
|
||||
if !ok || backend == nil {
|
||||
writeErrorJSON(w, http.StatusServiceUnavailable, "translation_memory_backend_unavailable", "Rust bat Translation Memory backend is unavailable")
|
||||
return
|
||||
}
|
||||
var params backendrpc.TranslationMemoryResolveConflictParams
|
||||
if !decodeAdminTranslationJSON(w, r, ¶ms) {
|
||||
return
|
||||
}
|
||||
if err := validateTranslationMemoryResolveConflictParams(params); err != nil {
|
||||
writeErrorJSON(w, http.StatusBadRequest, "invalid_translation_memory_params", err.Error())
|
||||
return
|
||||
}
|
||||
result, err := backend.TranslationMemoryResolveConflict(r.Context(), params)
|
||||
if err != nil {
|
||||
s.writeControlBackendError(w, "translation-memory-resolve-conflict", err)
|
||||
return
|
||||
}
|
||||
writeNoStoreJSON(w, http.StatusAccepted, AdminControlResponse{
|
||||
Service: "bat-api",
|
||||
Action: "translation-memory-resolve-conflict",
|
||||
RPCMethod: "translation.memory.resolve_conflict",
|
||||
Status: "accepted",
|
||||
Result: result,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) handleAdminTranslationTaskUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
backend, ok := s.backend.(TranslationBackend)
|
||||
if !ok || backend == nil {
|
||||
@@ -1016,6 +1050,37 @@ func (s *Server) handleAdminTranslationMemoryQuery(w http.ResponseWriter, r *htt
|
||||
writeNoStoreJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
func (s *Server) handleAdminTranslationMemoryConflicts(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet && r.Method != http.MethodHead {
|
||||
writeErrorJSON(w, http.StatusMethodNotAllowed, "method_not_allowed", "method not allowed")
|
||||
return
|
||||
}
|
||||
if !s.requireAdminToken(w, r) {
|
||||
return
|
||||
}
|
||||
backend, ok := s.backend.(TranslationMemoryBackend)
|
||||
if !ok || backend == nil {
|
||||
writeErrorJSON(w, http.StatusServiceUnavailable, "translation_memory_backend_unavailable", "Rust bat Translation Memory backend is unavailable")
|
||||
return
|
||||
}
|
||||
params, err := translationMemoryConflictsParams(r)
|
||||
if err != nil {
|
||||
writeErrorJSON(w, http.StatusBadRequest, "invalid_translation_memory_query", err.Error())
|
||||
return
|
||||
}
|
||||
result, err := backend.TranslationMemoryConflicts(r.Context(), params)
|
||||
if err != nil {
|
||||
s.writeControlBackendError(w, "translation-memory-conflicts", err)
|
||||
return
|
||||
}
|
||||
if r.Method == http.MethodHead {
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
writeNoStoreJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
func (s *Server) handleAdminSchedules(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet && r.Method != http.MethodHead {
|
||||
writeErrorJSON(w, http.StatusMethodNotAllowed, "method_not_allowed", "method not allowed")
|
||||
@@ -1139,6 +1204,20 @@ func translationMemoryQueryParams(r *http.Request) (backendrpc.TranslationMemory
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func translationMemoryConflictsParams(r *http.Request) (backendrpc.TranslationMemoryConflictsParams, error) {
|
||||
params := backendrpc.TranslationMemoryConflictsParams{
|
||||
TranslationMemoryPath: firstTrimmedQuery(r.URL.Query(), "translation_memory_path", "tm_path"),
|
||||
}
|
||||
if raw := strings.TrimSpace(r.URL.Query().Get("limit")); raw != "" {
|
||||
limit, err := strconv.ParseUint(raw, 10, 64)
|
||||
if err != nil || limit == 0 || limit > 1000 {
|
||||
return backendrpc.TranslationMemoryConflictsParams{}, errors.New("limit must be in 1..=1000")
|
||||
}
|
||||
params.Limit = &limit
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func parseTextUnitQueryParams(r *http.Request) (backendrpc.TextUnitQueryParams, error) {
|
||||
query := r.URL.Query()
|
||||
params := backendrpc.TextUnitQueryParams{
|
||||
@@ -1334,6 +1413,32 @@ func validateTranslationMemoryConfirmParams(params backendrpc.TranslationMemoryC
|
||||
if strings.TrimSpace(params.RecordID) == "" || strings.TrimSpace(params.Reviewer) == "" {
|
||||
return errors.New("translation memory confirm requires record_id and reviewer")
|
||||
}
|
||||
if strings.TrimSpace(params.SupersedeRecordID) != "" && strings.TrimSpace(params.Reason) == "" {
|
||||
return errors.New("translation memory supersede requires reason")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateTranslationMemoryResolveConflictParams(params backendrpc.TranslationMemoryResolveConflictParams) error {
|
||||
if strings.TrimSpace(params.WinnerRecordID) == "" ||
|
||||
strings.TrimSpace(params.Reviewer) == "" ||
|
||||
strings.TrimSpace(params.Reason) == "" {
|
||||
return errors.New("translation memory conflict resolution requires winner_record_id, reviewer, and reason")
|
||||
}
|
||||
if len(params.ExpectedTrustedRecordIDs) == 0 {
|
||||
return errors.New("translation memory conflict resolution requires expected_trusted_record_ids")
|
||||
}
|
||||
seen := make(map[string]struct{}, len(params.ExpectedTrustedRecordIDs))
|
||||
for _, id := range params.ExpectedTrustedRecordIDs {
|
||||
id = strings.TrimSpace(id)
|
||||
if id == "" {
|
||||
return errors.New("expected_trusted_record_ids cannot contain empty record IDs")
|
||||
}
|
||||
if _, ok := seen[id]; ok {
|
||||
return errors.New("expected_trusted_record_ids must be unique")
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1412,10 +1517,17 @@ func (s *Server) writeControlBackendError(w http.ResponseWriter, action string,
|
||||
message = "control request was canceled"
|
||||
default:
|
||||
var apiErr *backendrpc.APIError
|
||||
if errors.As(err, &apiErr) && apiErr.Kind == "not_implemented" {
|
||||
status = http.StatusNotImplemented
|
||||
code = "control_not_implemented"
|
||||
message = "Rust bat does not implement this control action"
|
||||
if errors.As(err, &apiErr) {
|
||||
switch apiErr.Kind {
|
||||
case "not_implemented":
|
||||
status = http.StatusNotImplemented
|
||||
code = "control_not_implemented"
|
||||
message = "Rust bat does not implement this control action"
|
||||
case "rpc_invalid_params":
|
||||
status = http.StatusBadRequest
|
||||
code = "invalid_control_params"
|
||||
message = apiErr.Message
|
||||
}
|
||||
}
|
||||
}
|
||||
s.logger.Printf("bat-api control action=%s error=%v", action, err)
|
||||
|
||||
Reference in New Issue
Block a user