feat: 推广 V3.5 实时氢耗并完善导出

This commit is contained in:
lingniu
2026-09-04 15:42:02 +08:00
parent a26179c8fe
commit e402eb5e60
53 changed files with 2855 additions and 320 deletions
@@ -1,6 +1,7 @@
package app
import (
"crypto/sha256"
"encoding/json"
"net/http"
"net/http/httptest"
@@ -212,6 +213,39 @@ func TestAuthSelfServiceEndpointsAllowCustomerRole(t *testing.T) {
}
}
func TestRestrictedAdminCannotAccessAccountManagement(t *testing.T) {
token := "restricted-admin-token-at-least-16"
hash := sha256.Sum256([]byte(token))
authenticator := &apiAuthenticator{
mode: "enforce",
tokens: []tokenPrincipal{{
hash: hash,
principal: platform.Principal{
Name: "业务管理", Username: "ln-bm", Role: "admin", UserType: "admin",
MenuKeys: []string{"monitor", "vehicles", "tracks", "history", "statistics", "alerts", "access", "operations"},
},
}},
}
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) })
handler := authenticator.middleware(next)
usersRequest := httptest.NewRequest(http.MethodGet, "/api/v2/admin/users", nil)
usersRequest.Header.Set("Authorization", "Bearer "+token)
usersResponse := httptest.NewRecorder()
handler.ServeHTTP(usersResponse, usersRequest)
if usersResponse.Code != http.StatusForbidden || !strings.Contains(usersResponse.Body.String(), "MENU_PERMISSION_DENIED") {
t.Fatalf("restricted admin account management status=%d body=%s", usersResponse.Code, usersResponse.Body.String())
}
operationsRequest := httptest.NewRequest(http.MethodGet, "/api/v2/operations/source-rules", nil)
operationsRequest.Header.Set("Authorization", "Bearer "+token)
operationsResponse := httptest.NewRecorder()
handler.ServeHTTP(operationsResponse, operationsRequest)
if operationsResponse.Code != http.StatusNoContent {
t.Fatalf("restricted admin should retain other admin permissions, status=%d", operationsResponse.Code)
}
}
func TestMileagePostQueriesAllowCustomerRole(t *testing.T) {
for _, path := range []string{"/api/mileage/daily", "/api/v2/statistics/mileage"} {
req := httptest.NewRequest(http.MethodPost, path, nil)
@@ -224,6 +258,29 @@ func TestMileagePostQueriesAllowCustomerRole(t *testing.T) {
}
}
func TestBatchVehicleLookupAllowsEveryCustomerMenuScope(t *testing.T) {
const token = "customer-token-at-least-16"
hash := sha256.Sum256([]byte(token))
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) })
for _, menu := range customerMenuKeys {
t.Run(menu, func(t *testing.T) {
authenticator := &apiAuthenticator{mode: "enforce", tokens: []tokenPrincipal{{
hash: hash,
principal: platform.Principal{
Name: "客户甲", Role: "customer", UserType: "customer", MenuKeys: []string{menu},
},
}}}
req := httptest.NewRequest(http.MethodPost, "/api/vehicle-service/overviews", nil)
req.Header.Set("Authorization", "Bearer "+token)
rec := httptest.NewRecorder()
authenticator.middleware(next).ServeHTTP(rec, req)
if rec.Code != http.StatusNoContent {
t.Fatalf("customer with %s menu should reach batch lookup, status=%d body=%s", menu, rec.Code, rec.Body.String())
}
})
}
}
func TestAPIAuthMisconfigurationFailsClosed(t *testing.T) {
cases := []config.Config{
{AuthMode: "enforce"},