fix(webui): encode automation update values

This commit is contained in:
chengyongru
2026-06-15 15:14:24 +08:00
parent 5892c6913b
commit f8bf6aea51
5 changed files with 41 additions and 16 deletions
+5 -1
View File
@@ -17,6 +17,7 @@ import time
from collections.abc import Callable
from pathlib import Path
from typing import TYPE_CHECKING, Any
from urllib.parse import unquote
from loguru import logger
from websockets.http11 import Request as WsRequest
@@ -782,7 +783,10 @@ def _automation_values_from_request(request: WsRequest) -> dict[str, Any] | None
try:
values = json.loads(raw)
except Exception:
return None
try:
values = json.loads(unquote(raw))
except Exception:
return None
return values if isinstance(values, dict) else None
+22 -2
View File
@@ -10,7 +10,7 @@ import time
from pathlib import Path
from typing import Any
from unittest.mock import AsyncMock, MagicMock
from urllib.parse import urlencode
from urllib.parse import quote, urlencode
import httpx
import pytest
@@ -942,6 +942,26 @@ async def test_webui_automations_route_lists_all_jobs_and_allows_user_actions(
assert by_id[user_job.id]["schedule"]["expr"] == "0 9 * * *"
assert by_id[user_job.id]["schedule"]["tz"] == "UTC"
unicode_update = await _http_get(
f"{base_url}/api/webui/automations/update?id={user_job.id}",
headers={
**auth,
"X-Nanobot-Automation-Values": quote(
json.dumps(
{
"name": "每日测验",
"message": "问今日测验",
},
ensure_ascii=False,
),
safe="",
),
},
)
assert unicode_update.status_code == 200
assert cron.get_job(user_job.id).name == "每日测验"
assert cron.get_job(user_job.id).payload.message == "问今日测验"
malformed_update = await _http_get(
f"{base_url}/api/webui/automations/update?id={user_job.id}",
headers={
@@ -950,7 +970,7 @@ async def test_webui_automations_route_lists_all_jobs_and_allows_user_actions(
},
)
assert malformed_update.status_code == 400
assert cron.get_job(user_job.id).payload.message == "Ask the daily quiz"
assert cron.get_job(user_job.id).payload.message == "问今日测验"
invalid_cron_update = await _http_get(
f"{base_url}/api/webui/automations/update?id={user_job.id}",
+5 -3
View File
@@ -89,6 +89,10 @@ function mcpValuesHeader(values: Record<string, unknown>): HeadersInit | undefin
return { "X-Nanobot-MCP-Values": JSON.stringify(payload) };
}
function automationValuesHeader(values: AutomationUpdatePayload): HeadersInit {
return { "X-Nanobot-Automation-Values": encodeURIComponent(JSON.stringify(values)) };
}
function splitKey(key: string): { channel: string; chatId: string } {
const idx = key.indexOf(":");
if (idx === -1) return { channel: "", chatId: key };
@@ -226,9 +230,7 @@ export async function updateAutomation(
`${base}/api/webui/automations/update?${query}`,
token,
{
headers: {
"X-Nanobot-Automation-Values": JSON.stringify(values),
},
headers: automationValuesHeader(values),
},
API_READ_TIMEOUT_MS,
);
+8 -9
View File
@@ -125,25 +125,24 @@ describe("webui API helpers", () => {
});
it("serializes workspace automation updates", async () => {
await updateAutomation("tok", "job 1/2", {
name: "Daily quiz",
message: "Ask the quiz",
const values = {
name: "每日测验",
message: "Ask 今日 quiz",
schedule: { kind: "cron", expr: "0 9 * * *", tz: "Asia/Shanghai" },
});
} as const;
await updateAutomation("tok", "job 1/2", values);
expect(fetch).toHaveBeenCalledWith(
"/api/webui/automations/update?id=job+1%2F2",
expect.objectContaining({
headers: {
Authorization: "Bearer tok",
"X-Nanobot-Automation-Values": JSON.stringify({
name: "Daily quiz",
message: "Ask the quiz",
schedule: { kind: "cron", expr: "0 9 * * *", tz: "Asia/Shanghai" },
}),
"X-Nanobot-Automation-Values": encodeURIComponent(JSON.stringify(values)),
},
}),
);
const header = vi.mocked(fetch).mock.calls[0][1]?.headers as Record<string, string>;
expect(header["X-Nanobot-Automation-Values"]).not.toContain("每日");
});
it("fetches the WebUI skill summary", async () => {
+1 -1
View File
@@ -518,7 +518,7 @@ describe("App layout", () => {
);
expect(updateCall).toBeTruthy();
const headers = updateCall?.[1]?.headers as Record<string, string>;
expect(JSON.parse(headers["X-Nanobot-Automation-Values"])).toEqual({
expect(JSON.parse(decodeURIComponent(headers["X-Nanobot-Automation-Values"]))).toEqual({
name: "Past one-shot",
message: "Updated one-shot message",
});