platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func handleTransportOwnerLocksClear(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var body TransportOwnerLocksClearRequest
|
||||
if r.Body != nil {
|
||||
defer r.Body.Close()
|
||||
if err := json.NewDecoder(io.LimitReader(r.Body, 1<<20)).Decode(&body); err != nil && err != io.EOF {
|
||||
http.Error(w, "bad json", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
filter, err := normalizeTransportOwnerLockClearRequest(body)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
||||
OK: false,
|
||||
Message: err.Error(),
|
||||
Code: "OWNER_LOCK_CLEAR_INVALID_REQUEST",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
transportMu.Lock()
|
||||
defer transportMu.Unlock()
|
||||
|
||||
locks := loadTransportOwnerLocksState()
|
||||
baseRevision := locks.PolicyRevision
|
||||
if body.BaseRevision > 0 && body.BaseRevision != baseRevision {
|
||||
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
||||
OK: false,
|
||||
Message: "stale owner-lock revision",
|
||||
Code: "OWNER_LOCK_CLEAR_REVISION_MISMATCH",
|
||||
BaseRevision: baseRevision,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
matched, remaining := splitTransportOwnerLocksByFilter(locks.Items, filter)
|
||||
if len(matched) == 0 {
|
||||
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
||||
OK: true,
|
||||
Message: "no matching owner locks",
|
||||
BaseRevision: baseRevision,
|
||||
MatchCount: 0,
|
||||
ClearedCount: 0,
|
||||
RemainingCount: len(locks.Items),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
digest := digestTransportOwnerLocksClear(baseRevision, filter, matched)
|
||||
confirmToken := strings.TrimSpace(body.ConfirmToken)
|
||||
if !consumeTransportOwnerLocksClearToken(confirmToken, baseRevision, digest) {
|
||||
nextToken := issueTransportOwnerLocksClearToken(baseRevision, digest)
|
||||
code := "OWNER_LOCK_CLEAR_CONFIRM_REQUIRED"
|
||||
msg := "confirm token required to clear owner locks"
|
||||
if confirmToken != "" {
|
||||
code = "OWNER_LOCK_CLEAR_CONFIRM_INVALID"
|
||||
msg = "invalid or expired confirm token"
|
||||
}
|
||||
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
||||
OK: false,
|
||||
Message: msg,
|
||||
Code: code,
|
||||
BaseRevision: baseRevision,
|
||||
ConfirmRequired: true,
|
||||
ConfirmToken: nextToken,
|
||||
MatchCount: len(matched),
|
||||
RemainingCount: len(locks.Items),
|
||||
Items: matched,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
next := locks
|
||||
next.Items = append([]TransportOwnerLockRecord(nil), remaining...)
|
||||
next.PolicyRevision = baseRevision
|
||||
if err := saveTransportOwnerLocksState(next); err != nil {
|
||||
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
||||
OK: false,
|
||||
Message: "owner-lock save failed: " + err.Error(),
|
||||
Code: "OWNER_LOCK_CLEAR_SAVE_FAILED",
|
||||
BaseRevision: baseRevision,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
events.push("transport_owner_locks_cleared", map[string]any{
|
||||
"base_revision": baseRevision,
|
||||
"cleared_count": len(matched),
|
||||
"remaining_count": len(next.Items),
|
||||
"client_id": filter.ClientID,
|
||||
})
|
||||
|
||||
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
||||
OK: true,
|
||||
Message: "owner locks cleared",
|
||||
BaseRevision: baseRevision,
|
||||
MatchCount: len(matched),
|
||||
ClearedCount: len(matched),
|
||||
RemainingCount: len(next.Items),
|
||||
Items: matched,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user