refactor(map): remove access gate

This commit is contained in:
lingniu
2026-08-11 19:24:32 +08:00
parent d1ba129e99
commit 357dd490e9
9 changed files with 140 additions and 580 deletions
+18
View File
@@ -138,6 +138,22 @@ assert.ok(stationNavigationUrl.startsWith('https://uri.amap.com/navigation?to=11
assert.match(stationNavigationUrl, /%E5%B9%BF%E5%B7%9E/);
assert.match(stationNavigationUrl, /coordinate=gaode&callnative=1$/);
assert.equal(navigationUrlForEntity('vehicle', { plateNumber: '无位置车辆' }), null);
const launchClassSet = new Set();
const launchOverlay = { hidden: true, classList: { add(name) { launchClassSet.add(name); }, remove(name) { launchClassSet.delete(name); } } };
const launchButton = { disabled: false, dataset: { navigationUrl: stationNavigationUrl }, classList: { add(name) { launchClassSet.add('button:' + name); }, remove(name) { launchClassSet.delete('button:' + name); }, contains(name) { return launchClassSet.has('button:' + name); } } };
const launchTimers = [];
document.getElementById = id => id === 'navigationLaunchOverlay' ? launchOverlay : id === 'detailNavigateBtn' ? launchButton : null;
window.requestAnimationFrame = callback => callback();
window.setTimeout = (callback, delay) => { launchTimers.push({ callback, delay }); return launchTimers.length; };
window.clearTimeout = () => {};
window.location = { assign() {} };
selectedEntity = { mode: 'station', entity: dashboard.stations[0] };
navigateToSelectedEntity();
assert.equal(launchOverlay.hidden, false);
assert.ok(launchClassSet.has('is-visible'));
assert.ok(launchClassSet.has('button:is-launching'));
assert.equal(launchButton.disabled, true);
assert.deepEqual(launchTimers.map(timer => timer.delay), [140, 4000]);
const stationView = stationViewportSummary();
assert.equal(stationView.level, 'station');
assert.equal(stationView.visibleNodes.length, 2);
@@ -170,5 +186,7 @@ const sandbox = {
setInterval() {},
clearInterval() {}
};
assert.match(source, /navigationLaunchOverlay/);
assert.match(source, /正在打开高德地图/);
vm.runInNewContext(`${source}\n${checks}`, sandbox, { filename: 'app.js' });
console.log('vehicle hierarchy aggregation tests: ok');
+1 -49
View File
@@ -1,9 +1,5 @@
import importlib.util
import hashlib
import hmac
import json
from pathlib import Path
import time
import unittest
from unittest.mock import patch
@@ -14,7 +10,7 @@ SPEC.loader.exec_module(server)
class DashboardTest(unittest.TestCase):
def test_dashboard_aggregates_authorized_vehicle_and_station_data(self):
def test_dashboard_aggregates_public_vehicle_and_station_data(self):
def fake_post(path, body):
if path.endswith("realtime/query"):
return [
@@ -45,55 +41,11 @@ class DashboardTest(unittest.TestCase):
self.assertEqual(result["vehicles"][0]["dailyMileageKm"], 12.345)
self.assertEqual(result["vehicles"][2]["dailyMileageKm"], 0)
def test_public_station_directory_uses_an_allowlist(self):
stations = [{
"id": "GD-1", "name": "广州合作站", "shortName": "合作站", "province": "广东省",
"city": "广州市", "district": "黄埔区", "address": "开源大道1号", "longitude": 113.2,
"latitude": 23.1, "cooperative": True, "monthlyHydrogenKg": 88.8,
"totalHydrogenKg": 999.9, "internalOwner": "must-not-leak",
}]
with patch.object(server, "_post_open_platform", return_value=stations):
with patch.object(server, "_cache", {}):
result = server._load_public_stations()
station = result["stations"][0]
self.assertEqual(result["access"]["level"], "public")
self.assertEqual(station["name"], "广州合作站")
self.assertTrue(station["cooperative"])
self.assertNotIn("monthlyHydrogenKg", station)
self.assertNotIn("totalHydrogenKg", station)
self.assertNotIn("internalOwner", station)
def test_static_asset_version_is_a_content_fingerprint(self):
self.assertEqual(len(server.STATIC_ASSET_VERSION), 16)
self.assertRegex(server.STATIC_ASSET_VERSION, r"^[0-9a-f]{16}$")
index_template = (Path(__file__).parents[1] / "index.html").read_text(encoding="utf-8")
self.assertEqual(index_template.count("__ASSET_VERSION__"), 2)
def test_signed_operations_session_requires_the_operations_scope(self):
with patch.object(server, "LOCAL_ACCESS_CODE", "LN-map-test-code"), patch.object(server, "SESSION_SECRET", b"test-session-secret"), patch.object(server, "SESSION_TTL_SECONDS", 600):
principal = server._authorizer().authorize_access_code("LN-map-test-code")
token = server._create_session(principal)
session = server._read_session(f"{server.SESSION_COOKIE_NAME}={token}")
self.assertEqual(session["subject"], "local-access-code")
self.assertIn(server.OPERATIONS_READ_SCOPE, session["scopes"])
self.assertIsNone(server._read_session(f"{server.SESSION_COOKIE_NAME}={token}tampered"))
legacy_payload = {"v": 1, "sub": "legacy", "scopes": [server.OPERATIONS_READ_SCOPE], "exp": 4_102_444_800}
legacy_encoded = server._b64encode(server._json_bytes(legacy_payload))
legacy_signature = server._b64encode(hmac.new(server.SESSION_SECRET, legacy_encoded.encode("ascii"), hashlib.sha256).digest())
self.assertIsNone(server._read_session(f"{server.SESSION_COOKIE_NAME}={legacy_encoded}.{legacy_signature}"))
def test_default_operations_session_expires_after_thirty_minutes(self):
self.assertEqual(server.SESSION_TTL_SECONDS, 1800)
with patch.object(server, "SESSION_SECRET", b"test-session-secret"), patch.object(server, "SESSION_TTL_SECONDS", 1800):
token = server._create_session({"subject": "test", "scopes": [server.OPERATIONS_READ_SCOPE]})
encoded, _ = token.split(".", 1)
payload = json.loads(server._b64decode(encoded))
self.assertGreaterEqual(payload["exp"], int(time.time()) + 1798)
self.assertLessEqual(payload["exp"], int(time.time()) + 1801)
if __name__ == "__main__":
unittest.main()