@josephyan/qingflow-cli 0.2.0-beta.1000
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/docs/local-agent-install.md +309 -0
- package/entry_point.py +13 -0
- package/npm/bin/qingflow.mjs +5 -0
- package/npm/lib/runtime.mjs +346 -0
- package/npm/scripts/postinstall.mjs +16 -0
- package/package.json +34 -0
- package/pyproject.toml +67 -0
- package/qingflow +15 -0
- package/src/qingflow_mcp/__init__.py +37 -0
- package/src/qingflow_mcp/__main__.py +5 -0
- package/src/qingflow_mcp/backend_client.py +649 -0
- package/src/qingflow_mcp/builder_facade/__init__.py +3 -0
- package/src/qingflow_mcp/builder_facade/models.py +1846 -0
- package/src/qingflow_mcp/builder_facade/service.py +16502 -0
- package/src/qingflow_mcp/cli/__init__.py +1 -0
- package/src/qingflow_mcp/cli/commands/__init__.py +18 -0
- package/src/qingflow_mcp/cli/commands/app.py +40 -0
- package/src/qingflow_mcp/cli/commands/auth.py +112 -0
- package/src/qingflow_mcp/cli/commands/builder.py +539 -0
- package/src/qingflow_mcp/cli/commands/chart.py +18 -0
- package/src/qingflow_mcp/cli/commands/common.py +62 -0
- package/src/qingflow_mcp/cli/commands/imports.py +96 -0
- package/src/qingflow_mcp/cli/commands/portal.py +25 -0
- package/src/qingflow_mcp/cli/commands/record.py +331 -0
- package/src/qingflow_mcp/cli/commands/repo.py +80 -0
- package/src/qingflow_mcp/cli/commands/task.py +141 -0
- package/src/qingflow_mcp/cli/commands/view.py +18 -0
- package/src/qingflow_mcp/cli/commands/workspace.py +110 -0
- package/src/qingflow_mcp/cli/context.py +60 -0
- package/src/qingflow_mcp/cli/formatters.py +573 -0
- package/src/qingflow_mcp/cli/json_io.py +50 -0
- package/src/qingflow_mcp/cli/main.py +186 -0
- package/src/qingflow_mcp/cli/qingflow_login.py +116 -0
- package/src/qingflow_mcp/cli/terminal_ui.py +173 -0
- package/src/qingflow_mcp/config.py +407 -0
- package/src/qingflow_mcp/errors.py +66 -0
- package/src/qingflow_mcp/id_utils.py +49 -0
- package/src/qingflow_mcp/import_store.py +121 -0
- package/src/qingflow_mcp/json_types.py +18 -0
- package/src/qingflow_mcp/list_type_labels.py +76 -0
- package/src/qingflow_mcp/public_surface.py +243 -0
- package/src/qingflow_mcp/repository_store.py +71 -0
- package/src/qingflow_mcp/response_trim.py +841 -0
- package/src/qingflow_mcp/server.py +216 -0
- package/src/qingflow_mcp/server_app_builder.py +543 -0
- package/src/qingflow_mcp/server_app_user.py +386 -0
- package/src/qingflow_mcp/session_store.py +369 -0
- package/src/qingflow_mcp/solution/__init__.py +6 -0
- package/src/qingflow_mcp/solution/build_assembly_store.py +181 -0
- package/src/qingflow_mcp/solution/compiler/__init__.py +282 -0
- package/src/qingflow_mcp/solution/compiler/chart_compiler.py +96 -0
- package/src/qingflow_mcp/solution/compiler/form_compiler.py +495 -0
- package/src/qingflow_mcp/solution/compiler/icon_utils.py +187 -0
- package/src/qingflow_mcp/solution/compiler/navigation_compiler.py +57 -0
- package/src/qingflow_mcp/solution/compiler/package_compiler.py +19 -0
- package/src/qingflow_mcp/solution/compiler/portal_compiler.py +60 -0
- package/src/qingflow_mcp/solution/compiler/view_compiler.py +51 -0
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
- package/src/qingflow_mcp/solution/design_session.py +222 -0
- package/src/qingflow_mcp/solution/design_store.py +100 -0
- package/src/qingflow_mcp/solution/executor.py +2398 -0
- package/src/qingflow_mcp/solution/normalizer.py +23 -0
- package/src/qingflow_mcp/solution/requirements_builder.py +536 -0
- package/src/qingflow_mcp/solution/run_store.py +244 -0
- package/src/qingflow_mcp/solution/spec_models.py +855 -0
- package/src/qingflow_mcp/tools/__init__.py +1 -0
- package/src/qingflow_mcp/tools/ai_builder_tools.py +3449 -0
- package/src/qingflow_mcp/tools/app_tools.py +926 -0
- package/src/qingflow_mcp/tools/approval_tools.py +1062 -0
- package/src/qingflow_mcp/tools/auth_tools.py +1133 -0
- package/src/qingflow_mcp/tools/base.py +281 -0
- package/src/qingflow_mcp/tools/code_block_tools.py +777 -0
- package/src/qingflow_mcp/tools/custom_button_tools.py +202 -0
- package/src/qingflow_mcp/tools/directory_tools.py +675 -0
- package/src/qingflow_mcp/tools/feedback_tools.py +238 -0
- package/src/qingflow_mcp/tools/file_tools.py +409 -0
- package/src/qingflow_mcp/tools/import_tools.py +2223 -0
- package/src/qingflow_mcp/tools/navigation_tools.py +210 -0
- package/src/qingflow_mcp/tools/package_tools.py +326 -0
- package/src/qingflow_mcp/tools/portal_tools.py +158 -0
- package/src/qingflow_mcp/tools/qingbi_report_tools.py +374 -0
- package/src/qingflow_mcp/tools/record_tools.py +14291 -0
- package/src/qingflow_mcp/tools/repository_dev_tools.py +552 -0
- package/src/qingflow_mcp/tools/resource_read_tools.py +503 -0
- package/src/qingflow_mcp/tools/role_tools.py +112 -0
- package/src/qingflow_mcp/tools/solution_tools.py +4054 -0
- package/src/qingflow_mcp/tools/task_context_tools.py +2986 -0
- package/src/qingflow_mcp/tools/task_tools.py +889 -0
- package/src/qingflow_mcp/tools/view_tools.py +335 -0
- package/src/qingflow_mcp/tools/workflow_tools.py +376 -0
- package/src/qingflow_mcp/tools/workspace_tools.py +266 -0
|
@@ -0,0 +1,841 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from copy import deepcopy
|
|
5
|
+
from functools import wraps
|
|
6
|
+
from typing import Any, Callable
|
|
7
|
+
|
|
8
|
+
from .public_surface import (
|
|
9
|
+
BUILDER_DOMAIN,
|
|
10
|
+
USER_DOMAIN,
|
|
11
|
+
cli_trim_key_from_namespace,
|
|
12
|
+
server_method_map,
|
|
13
|
+
tool_key,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
JSONObject = dict[str, Any]
|
|
18
|
+
TransformFn = Callable[[JSONObject], None]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
COMMON_SUCCESS_DROP_TOP = {
|
|
22
|
+
"request_route",
|
|
23
|
+
"profile",
|
|
24
|
+
"ws_id",
|
|
25
|
+
"output_profile",
|
|
26
|
+
"qf_version_source",
|
|
27
|
+
"persisted",
|
|
28
|
+
"base_url",
|
|
29
|
+
"normalized_args",
|
|
30
|
+
"suggested_next_call",
|
|
31
|
+
"noop",
|
|
32
|
+
"allowed_values",
|
|
33
|
+
"missing_fields",
|
|
34
|
+
"ok",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
COMMON_ERROR_DROP_TOP = {
|
|
38
|
+
"request_route",
|
|
39
|
+
"base_url",
|
|
40
|
+
"normalized_args",
|
|
41
|
+
"suggested_next_call",
|
|
42
|
+
"profile",
|
|
43
|
+
"ws_id",
|
|
44
|
+
"output_profile",
|
|
45
|
+
"qf_version_source",
|
|
46
|
+
"persisted",
|
|
47
|
+
"allowed_values",
|
|
48
|
+
"missing_fields",
|
|
49
|
+
"noop",
|
|
50
|
+
"ok",
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
SUCCESS_POLICY_BY_TOOL: dict[str, TransformFn] = {}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def trim_public_response(tool_name: str | None, payload: dict[str, Any]) -> dict[str, Any]:
|
|
57
|
+
if not isinstance(payload, dict):
|
|
58
|
+
return payload
|
|
59
|
+
if _looks_like_failure_payload(payload):
|
|
60
|
+
return _trim_returned_failure(payload)
|
|
61
|
+
return trim_success_response(tool_name, payload)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def trim_success_response(tool_name: str | None, payload: dict[str, Any]) -> dict[str, Any]:
|
|
65
|
+
if not isinstance(payload, dict):
|
|
66
|
+
return payload
|
|
67
|
+
trimmed = deepcopy(payload)
|
|
68
|
+
_drop_top_keys(trimmed, COMMON_SUCCESS_DROP_TOP)
|
|
69
|
+
transformer = SUCCESS_POLICY_BY_TOOL.get(tool_name or "")
|
|
70
|
+
if transformer is not None:
|
|
71
|
+
transformer(trimmed)
|
|
72
|
+
_drop_empty_optional_keys(trimmed)
|
|
73
|
+
return trimmed
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def trim_error_response(payload: dict[str, Any]) -> dict[str, Any]:
|
|
77
|
+
if not isinstance(payload, dict):
|
|
78
|
+
return payload
|
|
79
|
+
trimmed = deepcopy(payload)
|
|
80
|
+
_drop_top_keys(trimmed, COMMON_ERROR_DROP_TOP)
|
|
81
|
+
_drop_deep_keys(trimmed.get("details"), {"request_route", "base_url", "normalized_args", "suggested_next_call", "transport", "response", "body", "raw"})
|
|
82
|
+
details = trimmed.get("details")
|
|
83
|
+
if isinstance(details, dict):
|
|
84
|
+
compact_details = _compact_scalar_dict(details)
|
|
85
|
+
if compact_details:
|
|
86
|
+
trimmed["details"] = compact_details
|
|
87
|
+
else:
|
|
88
|
+
trimmed.pop("details", None)
|
|
89
|
+
if trimmed.get("backend_code") is not None:
|
|
90
|
+
trimmed.pop("http_status", None)
|
|
91
|
+
_drop_empty_optional_keys(trimmed)
|
|
92
|
+
return trimmed
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def wrap_trimmed_methods(instance: object, method_map: dict[str, str]) -> object:
|
|
96
|
+
for method_name, tool_name in method_map.items():
|
|
97
|
+
original = getattr(instance, method_name, None)
|
|
98
|
+
if original is None or not callable(original):
|
|
99
|
+
continue
|
|
100
|
+
setattr(instance, method_name, _wrap_callable(original, tool_name))
|
|
101
|
+
return instance
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def resolve_cli_tool_name(args: Any) -> str | None:
|
|
105
|
+
return cli_trim_key_from_namespace(args)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
USER_SERVER_METHOD_MAP = server_method_map(USER_DOMAIN)
|
|
109
|
+
BUILDER_SERVER_METHOD_MAP = server_method_map(BUILDER_DOMAIN)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _wrap_callable(original: Callable[..., Any], tool_name: str) -> Callable[..., Any]:
|
|
113
|
+
@wraps(original)
|
|
114
|
+
def wrapped(*args: Any, **kwargs: Any) -> Any:
|
|
115
|
+
try:
|
|
116
|
+
result = original(*args, **kwargs)
|
|
117
|
+
except RuntimeError as exc:
|
|
118
|
+
payload = _parse_runtime_error_payload(exc)
|
|
119
|
+
if payload is None:
|
|
120
|
+
raise
|
|
121
|
+
raise RuntimeError(json.dumps(trim_error_response(payload), ensure_ascii=False)) from None
|
|
122
|
+
return trim_public_response(tool_name, result) if isinstance(result, dict) else result
|
|
123
|
+
|
|
124
|
+
return wrapped
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _parse_runtime_error_payload(exc: RuntimeError) -> dict[str, Any] | None:
|
|
128
|
+
raw = str(exc)
|
|
129
|
+
try:
|
|
130
|
+
payload = json.loads(raw)
|
|
131
|
+
except json.JSONDecodeError:
|
|
132
|
+
return None
|
|
133
|
+
return payload if isinstance(payload, dict) else None
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _looks_like_failure_payload(payload: dict[str, Any]) -> bool:
|
|
137
|
+
if payload.get("ok") is False:
|
|
138
|
+
return True
|
|
139
|
+
status = str(payload.get("status") or "").lower()
|
|
140
|
+
return status in {"failed", "blocked", "verification_failed"}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _trim_returned_failure(payload: dict[str, Any]) -> dict[str, Any]:
|
|
144
|
+
trimmed = deepcopy(payload)
|
|
145
|
+
_drop_top_keys(trimmed, COMMON_ERROR_DROP_TOP)
|
|
146
|
+
_drop_deep_keys(trimmed.get("details"), {"request_route", "base_url", "normalized_args", "suggested_next_call", "transport", "response", "body", "raw"})
|
|
147
|
+
details = trimmed.get("details")
|
|
148
|
+
if isinstance(details, dict):
|
|
149
|
+
compact_details = _compact_scalar_dict(details)
|
|
150
|
+
if compact_details:
|
|
151
|
+
trimmed["details"] = compact_details
|
|
152
|
+
else:
|
|
153
|
+
trimmed.pop("details", None)
|
|
154
|
+
if trimmed.get("backend_code") is not None:
|
|
155
|
+
trimmed.pop("http_status", None)
|
|
156
|
+
_drop_empty_optional_keys(trimmed)
|
|
157
|
+
return trimmed
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _drop_top_keys(payload: JSONObject, keys: set[str]) -> None:
|
|
161
|
+
for key in keys:
|
|
162
|
+
payload.pop(key, None)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _drop_empty_optional_keys(payload: JSONObject) -> None:
|
|
166
|
+
for key in ("warnings", "verification", "details"):
|
|
167
|
+
value = payload.get(key)
|
|
168
|
+
if value in (None, [], {}, ""):
|
|
169
|
+
payload.pop(key, None)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _compact_scalar_dict(payload: dict[str, Any]) -> dict[str, Any]:
|
|
173
|
+
compact: dict[str, Any] = {}
|
|
174
|
+
for key, value in payload.items():
|
|
175
|
+
if isinstance(value, (str, int, float, bool)) or value is None:
|
|
176
|
+
compact[key] = value
|
|
177
|
+
continue
|
|
178
|
+
if isinstance(value, dict):
|
|
179
|
+
nested = {
|
|
180
|
+
nested_key: nested_value
|
|
181
|
+
for nested_key, nested_value in value.items()
|
|
182
|
+
if isinstance(nested_value, (str, int, float, bool)) or nested_value is None
|
|
183
|
+
}
|
|
184
|
+
if nested:
|
|
185
|
+
compact[key] = nested
|
|
186
|
+
return compact
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _trim_item_list(payload: JSONObject, key: str, *, allowed: tuple[str, ...]) -> None:
|
|
190
|
+
items = payload.get(key)
|
|
191
|
+
if not isinstance(items, list):
|
|
192
|
+
return
|
|
193
|
+
payload[key] = [_pick(item, allowed) for item in items if isinstance(item, dict)]
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _trim_nested_item_list(payload: JSONObject, path: tuple[str, ...], *, allowed: tuple[str, ...]) -> None:
|
|
197
|
+
parent = _nested_dict(payload, path[:-1])
|
|
198
|
+
if not isinstance(parent, dict):
|
|
199
|
+
return
|
|
200
|
+
key = path[-1]
|
|
201
|
+
items = parent.get(key)
|
|
202
|
+
if not isinstance(items, list):
|
|
203
|
+
return
|
|
204
|
+
parent[key] = [_pick(item, allowed) for item in items if isinstance(item, dict)]
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _keep_nested_keys(payload: JSONObject, path: tuple[str, ...], *, allowed: tuple[str, ...]) -> None:
|
|
208
|
+
parent = _nested_dict(payload, path[:-1])
|
|
209
|
+
if not isinstance(parent, dict):
|
|
210
|
+
return
|
|
211
|
+
node = parent.get(path[-1])
|
|
212
|
+
if isinstance(node, dict):
|
|
213
|
+
parent[path[-1]] = _pick(node, allowed)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _drop_nested_keys(payload: JSONObject, path: tuple[str, ...], *, keys: tuple[str, ...]) -> None:
|
|
217
|
+
parent = _nested_dict(payload, path[:-1])
|
|
218
|
+
if not isinstance(parent, dict):
|
|
219
|
+
return
|
|
220
|
+
node = parent.get(path[-1])
|
|
221
|
+
if not isinstance(node, dict):
|
|
222
|
+
return
|
|
223
|
+
for key in keys:
|
|
224
|
+
node.pop(key, None)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _drop_deep_keys(payload: Any, keys: set[str]) -> None:
|
|
228
|
+
if isinstance(payload, dict):
|
|
229
|
+
for key in list(payload.keys()):
|
|
230
|
+
if key in keys:
|
|
231
|
+
payload.pop(key, None)
|
|
232
|
+
continue
|
|
233
|
+
_drop_deep_keys(payload.get(key), keys)
|
|
234
|
+
elif isinstance(payload, list):
|
|
235
|
+
for item in payload:
|
|
236
|
+
_drop_deep_keys(item, keys)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _nested_dict(payload: JSONObject, path: tuple[str, ...]) -> JSONObject | None:
|
|
240
|
+
node: Any = payload
|
|
241
|
+
for key in path:
|
|
242
|
+
if not isinstance(node, dict):
|
|
243
|
+
return None
|
|
244
|
+
node = node.get(key)
|
|
245
|
+
return node if isinstance(node, dict) else None
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _pick(payload: JSONObject, allowed: tuple[str, ...]) -> JSONObject:
|
|
249
|
+
return {key: payload.get(key) for key in allowed if key in payload}
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _trim_auth_payload(payload: JSONObject) -> None:
|
|
253
|
+
pass
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _trim_auth_logout(payload: JSONObject) -> None:
|
|
257
|
+
pass
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _trim_workspace_list(payload: JSONObject) -> None:
|
|
261
|
+
page = payload.get("page")
|
|
262
|
+
if isinstance(page, dict):
|
|
263
|
+
_trim_item_list(page, "list", allowed=("wsId", "workspaceName", "remark"))
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _trim_workspace_get(payload: JSONObject) -> None:
|
|
267
|
+
workspace = payload.get("workspace")
|
|
268
|
+
if isinstance(workspace, dict):
|
|
269
|
+
payload["workspace"] = _pick(
|
|
270
|
+
workspace,
|
|
271
|
+
allowed=("wsId", "workspaceName", "remark", "systemVersion", "auth"),
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _trim_app_search_like(payload: JSONObject) -> None:
|
|
276
|
+
payload.pop("apps", None)
|
|
277
|
+
_trim_item_list(payload, "items", allowed=("app_key", "app_name", "package_name"))
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _trim_app_get(payload: JSONObject) -> None:
|
|
281
|
+
_trim_builder_envelope(payload)
|
|
282
|
+
_trim_nested_item_list(
|
|
283
|
+
payload,
|
|
284
|
+
("data", "accessible_views"),
|
|
285
|
+
allowed=("view_id", "name", "analysis_supported", "list_supported", "kind"),
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _trim_file_upload_info(payload: JSONObject) -> None:
|
|
290
|
+
pass
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _trim_file_upload_local(payload: JSONObject) -> None:
|
|
294
|
+
payload.pop("result", None)
|
|
295
|
+
payload.pop("upload_result", None)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _trim_import_schema(payload: JSONObject) -> None:
|
|
299
|
+
columns: list[JSONObject] | None = None
|
|
300
|
+
if isinstance(payload.get("columns"), list):
|
|
301
|
+
columns = [item for item in payload.get("columns", []) if isinstance(item, dict)]
|
|
302
|
+
elif isinstance(payload.get("expected_columns"), list):
|
|
303
|
+
columns = [item for item in payload.get("expected_columns", []) if isinstance(item, dict)]
|
|
304
|
+
if columns is not None:
|
|
305
|
+
payload["columns"] = [_compact_import_column(item) for item in columns]
|
|
306
|
+
payload.pop("expected_columns", None)
|
|
307
|
+
payload.pop("schema_fingerprint", None)
|
|
308
|
+
payload.pop("import_capability", None)
|
|
309
|
+
payload.pop("request_route", None)
|
|
310
|
+
payload.pop("verification", None)
|
|
311
|
+
|
|
312
|
+
if _looks_like_import_verify(payload):
|
|
313
|
+
_trim_import_verify_payload(payload)
|
|
314
|
+
return
|
|
315
|
+
if "applied_repairs" in payload or "repaired_file_path" in payload:
|
|
316
|
+
_trim_import_repair_payload(payload)
|
|
317
|
+
return
|
|
318
|
+
if "template_url" in payload or "downloaded_to_path" in payload:
|
|
319
|
+
_trim_import_template_payload(payload)
|
|
320
|
+
return
|
|
321
|
+
if "import_id" in payload or "process_id_str" in payload:
|
|
322
|
+
_trim_import_status_payload(payload)
|
|
323
|
+
return
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _trim_record_schema(payload: JSONObject) -> None:
|
|
327
|
+
payload.pop("legacy_schema", None)
|
|
328
|
+
template_map = payload.get("payload_template")
|
|
329
|
+
if not isinstance(template_map, dict):
|
|
330
|
+
template_map = None
|
|
331
|
+
|
|
332
|
+
if "writable_fields" in payload:
|
|
333
|
+
writable_fields = payload.get("writable_fields")
|
|
334
|
+
payload.pop("writable_fields", None)
|
|
335
|
+
required_fields: list[JSONObject] = []
|
|
336
|
+
optional_fields: list[JSONObject] = []
|
|
337
|
+
if isinstance(writable_fields, list):
|
|
338
|
+
for item in writable_fields:
|
|
339
|
+
compact = _compact_schema_field(item, template_map=template_map)
|
|
340
|
+
if not compact:
|
|
341
|
+
continue
|
|
342
|
+
if compact.get("required") is True:
|
|
343
|
+
required_fields.append(compact)
|
|
344
|
+
else:
|
|
345
|
+
optional_fields.append(compact)
|
|
346
|
+
payload["required_fields"] = required_fields
|
|
347
|
+
payload["optional_fields"] = optional_fields
|
|
348
|
+
|
|
349
|
+
for key in ("required_fields", "optional_fields", "runtime_linked_required_fields", "fields", "ambiguous_fields"):
|
|
350
|
+
if key in payload:
|
|
351
|
+
payload[key] = _compact_schema_fields(payload.get(key), template_map=template_map)
|
|
352
|
+
|
|
353
|
+
for key in ("suggested_dimensions", "suggested_metrics", "suggested_time_fields"):
|
|
354
|
+
if isinstance(payload.get(key), list):
|
|
355
|
+
payload[key] = [
|
|
356
|
+
_pick(item, ("field_id", "title")) for item in payload.get(key) if isinstance(item, dict)
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
for key in ("workflow_node", "view_resolution", "field_count"):
|
|
360
|
+
payload.pop(key, None)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def _trim_record_write(payload: JSONObject) -> None:
|
|
364
|
+
payload.pop("verification", None)
|
|
365
|
+
data = payload.get("data")
|
|
366
|
+
if not isinstance(data, dict):
|
|
367
|
+
return
|
|
368
|
+
data.pop("debug", None)
|
|
369
|
+
data.pop("normalized_payload", None)
|
|
370
|
+
data.pop("human_review", None)
|
|
371
|
+
data.pop("action", None)
|
|
372
|
+
resource = _compact_record_resource(data.get("resource"))
|
|
373
|
+
if resource:
|
|
374
|
+
data["resource"] = resource
|
|
375
|
+
else:
|
|
376
|
+
data.pop("resource", None)
|
|
377
|
+
verification = data.get("verification")
|
|
378
|
+
if isinstance(verification, dict):
|
|
379
|
+
compact_verification = _pick(
|
|
380
|
+
verification,
|
|
381
|
+
(
|
|
382
|
+
"verified",
|
|
383
|
+
"verification_mode",
|
|
384
|
+
"field_level_verified",
|
|
385
|
+
),
|
|
386
|
+
)
|
|
387
|
+
if compact_verification:
|
|
388
|
+
data["verification"] = compact_verification
|
|
389
|
+
else:
|
|
390
|
+
data.pop("verification", None)
|
|
391
|
+
for key in ("blockers", "field_errors", "confirmation_requests", "resolved_fields"):
|
|
392
|
+
value = data.get(key)
|
|
393
|
+
if value in (None, [], {}, ""):
|
|
394
|
+
data.pop(key, None)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def _trim_record_get(payload: JSONObject) -> None:
|
|
398
|
+
data = payload.get("data")
|
|
399
|
+
if not isinstance(data, dict):
|
|
400
|
+
return
|
|
401
|
+
compact: dict[str, Any] = {}
|
|
402
|
+
app_key = data.get("app_key")
|
|
403
|
+
if app_key:
|
|
404
|
+
compact["app_key"] = app_key
|
|
405
|
+
record_id = data.get("record_id")
|
|
406
|
+
if record_id not in (None, ""):
|
|
407
|
+
compact["record_id"] = str(record_id)
|
|
408
|
+
record = data.get("record")
|
|
409
|
+
if isinstance(record, dict):
|
|
410
|
+
compact["record"] = record
|
|
411
|
+
normalized_record = data.get("normalized_record")
|
|
412
|
+
if isinstance(normalized_record, dict):
|
|
413
|
+
compact["normalized_record"] = normalized_record
|
|
414
|
+
normalized_ambiguous_fields = data.get("normalized_ambiguous_fields")
|
|
415
|
+
if isinstance(normalized_ambiguous_fields, dict):
|
|
416
|
+
compact["normalized_ambiguous_fields"] = normalized_ambiguous_fields
|
|
417
|
+
payload["data"] = compact
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def _trim_record_list(payload: JSONObject) -> None:
|
|
421
|
+
data = payload.get("data")
|
|
422
|
+
if not isinstance(data, dict):
|
|
423
|
+
return
|
|
424
|
+
pagination = data.get("pagination") if isinstance(data.get("pagination"), dict) else {}
|
|
425
|
+
returned_items = pagination.get("returned_items")
|
|
426
|
+
result_amount = pagination.get("result_amount")
|
|
427
|
+
limit = pagination.get("limit")
|
|
428
|
+
truncated = False
|
|
429
|
+
if isinstance(result_amount, int) and isinstance(returned_items, int):
|
|
430
|
+
truncated = result_amount > returned_items
|
|
431
|
+
compact_pagination = {
|
|
432
|
+
"loaded": True,
|
|
433
|
+
"page_size": limit,
|
|
434
|
+
"fetched_pages": 1,
|
|
435
|
+
"reported_total": result_amount,
|
|
436
|
+
"truncated": truncated,
|
|
437
|
+
}
|
|
438
|
+
selection = data.get("selection") if isinstance(data.get("selection"), dict) else {}
|
|
439
|
+
view = selection.get("view") if isinstance(selection.get("view"), dict) else {}
|
|
440
|
+
compact: dict[str, Any] = {
|
|
441
|
+
"app_key": data.get("app_key"),
|
|
442
|
+
"items": data.get("items") if isinstance(data.get("items"), list) else [],
|
|
443
|
+
"pagination": compact_pagination,
|
|
444
|
+
}
|
|
445
|
+
if view:
|
|
446
|
+
compact["view"] = _pick(view, ("view_id", "name"))
|
|
447
|
+
payload["data"] = compact
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def _trim_record_analyze(payload: JSONObject) -> None:
|
|
451
|
+
summary: dict[str, Any] = {}
|
|
452
|
+
completeness = payload.get("completeness")
|
|
453
|
+
if isinstance(completeness, dict):
|
|
454
|
+
summary["completeness"] = completeness
|
|
455
|
+
presentation = payload.get("presentation")
|
|
456
|
+
if isinstance(presentation, dict):
|
|
457
|
+
summary["presentation"] = presentation
|
|
458
|
+
ranking = payload.get("ranking")
|
|
459
|
+
if isinstance(ranking, dict):
|
|
460
|
+
summary["ranking"] = ranking
|
|
461
|
+
error = payload.get("error")
|
|
462
|
+
if isinstance(error, dict):
|
|
463
|
+
summary["error"] = error
|
|
464
|
+
if summary:
|
|
465
|
+
payload["summary"] = summary
|
|
466
|
+
for key in ("query", "ranking", "ratios", "completeness", "presentation", "error", "debug"):
|
|
467
|
+
payload.pop(key, None)
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def _trim_code_block_schema(payload: JSONObject) -> None:
|
|
471
|
+
payload.pop("legacy_schema", None)
|
|
472
|
+
_trim_nested_item_list(payload, ("code_block_fields",), allowed=("title", "selector", "bound_output_fields", "configured_aliases"))
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def _trim_code_block_run(payload: JSONObject) -> None:
|
|
476
|
+
_drop_deep_keys(payload, {"debug", "request_route"})
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def _trim_task_list(payload: JSONObject) -> None:
|
|
480
|
+
_drop_nested_keys(payload, ("data", "selection"), keys=("query",))
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def _trim_task_get(payload: JSONObject) -> None:
|
|
484
|
+
_drop_deep_keys(payload, {"request_route", "output_profile"})
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
def _trim_task_context_detail(payload: JSONObject) -> None:
|
|
488
|
+
_drop_deep_keys(payload, {"request_route", "output_profile"})
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def _trim_record_delete(payload: JSONObject) -> None:
|
|
492
|
+
data = payload.get("data")
|
|
493
|
+
if not isinstance(data, dict):
|
|
494
|
+
return
|
|
495
|
+
resource = data.get("resource")
|
|
496
|
+
deleted_ids: list[str] = []
|
|
497
|
+
if isinstance(resource, dict):
|
|
498
|
+
raw_ids = resource.get("record_ids") or resource.get("apply_ids") or resource.get("applyIds")
|
|
499
|
+
if isinstance(raw_ids, list):
|
|
500
|
+
deleted_ids = [str(item) for item in raw_ids if item not in (None, "")]
|
|
501
|
+
data["deleted_ids"] = deleted_ids
|
|
502
|
+
data.setdefault("failed_ids", [])
|
|
503
|
+
for key in (
|
|
504
|
+
"resource",
|
|
505
|
+
"action",
|
|
506
|
+
"normalized_payload",
|
|
507
|
+
"human_review",
|
|
508
|
+
"verification",
|
|
509
|
+
"blockers",
|
|
510
|
+
"field_errors",
|
|
511
|
+
"confirmation_requests",
|
|
512
|
+
"resolved_fields",
|
|
513
|
+
"debug",
|
|
514
|
+
):
|
|
515
|
+
data.pop(key, None)
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def _compact_record_resource(resource: Any) -> dict[str, Any] | None:
|
|
519
|
+
if not isinstance(resource, dict):
|
|
520
|
+
return None
|
|
521
|
+
compact: dict[str, Any] = {}
|
|
522
|
+
if resource.get("type") not in (None, ""):
|
|
523
|
+
compact["type"] = resource.get("type")
|
|
524
|
+
app_key = resource.get("app_key") or resource.get("appKey")
|
|
525
|
+
if app_key not in (None, ""):
|
|
526
|
+
compact["app_key"] = app_key
|
|
527
|
+
record_id = resource.get("record_id")
|
|
528
|
+
if record_id not in (None, ""):
|
|
529
|
+
compact["record_id"] = str(record_id)
|
|
530
|
+
apply_id = resource.get("apply_id") or resource.get("applyId")
|
|
531
|
+
if apply_id not in (None, "") and "record_id" not in compact:
|
|
532
|
+
compact["record_id"] = str(apply_id)
|
|
533
|
+
record_ids = resource.get("record_ids")
|
|
534
|
+
if isinstance(record_ids, list):
|
|
535
|
+
compact["record_ids"] = [str(item) for item in record_ids if item not in (None, "")]
|
|
536
|
+
apply_ids = resource.get("apply_ids") or resource.get("applyIds")
|
|
537
|
+
if isinstance(apply_ids, list) and "record_ids" not in compact:
|
|
538
|
+
compact["record_ids"] = [str(item) for item in apply_ids if item not in (None, "")]
|
|
539
|
+
return compact or None
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
def _compact_schema_fields(items: Any, *, template_map: dict[str, Any] | None) -> list[JSONObject]:
|
|
543
|
+
if not isinstance(items, list):
|
|
544
|
+
return []
|
|
545
|
+
compacted: list[JSONObject] = []
|
|
546
|
+
for item in items:
|
|
547
|
+
compact = _compact_schema_field(item, template_map=template_map)
|
|
548
|
+
if compact:
|
|
549
|
+
compacted.append(compact)
|
|
550
|
+
return compacted
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
def _compact_schema_field(item: Any, *, template_map: dict[str, Any] | None) -> JSONObject | None:
|
|
554
|
+
if not isinstance(item, dict):
|
|
555
|
+
return None
|
|
556
|
+
compact: dict[str, Any] = {}
|
|
557
|
+
field_id = item.get("field_id")
|
|
558
|
+
if field_id not in (None, ""):
|
|
559
|
+
compact["field_id"] = field_id
|
|
560
|
+
title = item.get("title")
|
|
561
|
+
if title not in (None, ""):
|
|
562
|
+
compact["title"] = title
|
|
563
|
+
kind = item.get("kind") or item.get("write_kind")
|
|
564
|
+
if kind not in (None, ""):
|
|
565
|
+
compact["kind"] = kind
|
|
566
|
+
if "required" in item:
|
|
567
|
+
compact["required"] = bool(item.get("required"))
|
|
568
|
+
if template_map is not None and isinstance(title, str) and title in template_map:
|
|
569
|
+
compact["template"] = template_map.get(title)
|
|
570
|
+
candidate_hint = item.get("candidate_hint")
|
|
571
|
+
if isinstance(candidate_hint, dict):
|
|
572
|
+
compact["candidate_hint"] = candidate_hint
|
|
573
|
+
options = item.get("options")
|
|
574
|
+
if isinstance(options, list) and options:
|
|
575
|
+
compact["options"] = options
|
|
576
|
+
target_app_key = item.get("target_app_key")
|
|
577
|
+
if isinstance(target_app_key, str) and target_app_key:
|
|
578
|
+
compact["target_app_key"] = target_app_key
|
|
579
|
+
searchable_fields = item.get("searchable_fields")
|
|
580
|
+
if isinstance(searchable_fields, list) and searchable_fields:
|
|
581
|
+
compact["searchable_fields"] = searchable_fields
|
|
582
|
+
row_fields = item.get("row_fields")
|
|
583
|
+
if isinstance(row_fields, list) and row_fields:
|
|
584
|
+
compact["row_fields"] = _compact_schema_fields(row_fields, template_map=None)
|
|
585
|
+
return compact or None
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def _compact_import_column(item: dict[str, Any]) -> dict[str, Any]:
|
|
589
|
+
compact: dict[str, Any] = {}
|
|
590
|
+
title = item.get("title")
|
|
591
|
+
if title not in (None, ""):
|
|
592
|
+
compact["title"] = title
|
|
593
|
+
kind = item.get("kind") or item.get("write_kind")
|
|
594
|
+
if kind not in (None, ""):
|
|
595
|
+
compact["kind"] = kind
|
|
596
|
+
compact["required"] = bool(item.get("required"))
|
|
597
|
+
options = item.get("options")
|
|
598
|
+
if isinstance(options, list) and options:
|
|
599
|
+
compact["options"] = options
|
|
600
|
+
if bool(item.get("accepts_natural_input")):
|
|
601
|
+
compact["accepts_natural_input"] = True
|
|
602
|
+
if bool(item.get("requires_upload")):
|
|
603
|
+
compact["requires_upload"] = True
|
|
604
|
+
target_app_key = item.get("target_app_key")
|
|
605
|
+
if isinstance(target_app_key, str) and target_app_key:
|
|
606
|
+
compact["target_app_key"] = target_app_key
|
|
607
|
+
target_app_name = item.get("target_app_name")
|
|
608
|
+
if isinstance(target_app_name, str) and target_app_name:
|
|
609
|
+
compact["target_app_name"] = target_app_name
|
|
610
|
+
searchable_fields = item.get("searchable_fields")
|
|
611
|
+
if isinstance(searchable_fields, list) and searchable_fields:
|
|
612
|
+
compact["searchable_fields"] = searchable_fields
|
|
613
|
+
return compact
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def _looks_like_import_verify(payload: JSONObject) -> bool:
|
|
617
|
+
return "verification_id" in payload and "can_import" in payload
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
def _trim_import_verify_payload(payload: JSONObject) -> None:
|
|
621
|
+
issues = payload.get("issues") if isinstance(payload.get("issues"), list) else []
|
|
622
|
+
issue_summary = _summarize_import_issues(issues)
|
|
623
|
+
payload["issue_summary"] = issue_summary
|
|
624
|
+
columns = payload.get("columns")
|
|
625
|
+
if "expected_columns" not in payload and isinstance(columns, list):
|
|
626
|
+
payload["expected_columns"] = columns
|
|
627
|
+
file_name = payload.get("file_name")
|
|
628
|
+
if not file_name:
|
|
629
|
+
file_path = payload.get("file_path")
|
|
630
|
+
if isinstance(file_path, str) and file_path:
|
|
631
|
+
payload["file_name"] = file_path.split("/")[-1]
|
|
632
|
+
for key in ("apply_rows", "schema_fingerprint", "import_capability", "file_sha256", "verified_file_sha256", "file_format", "local_precheck_limited"):
|
|
633
|
+
payload.pop(key, None)
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
def _trim_import_repair_payload(payload: JSONObject) -> None:
|
|
637
|
+
payload["verification_id"] = payload.get("new_verification_id") or payload.get("verification_id")
|
|
638
|
+
post_repair_issues = payload.get("post_repair_issues")
|
|
639
|
+
if isinstance(post_repair_issues, list):
|
|
640
|
+
payload["post_repair_issue_summary"] = _summarize_import_issues(post_repair_issues)
|
|
641
|
+
for key in ("new_verification_id", "verification"):
|
|
642
|
+
payload.pop(key, None)
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
def _trim_import_template_payload(payload: JSONObject) -> None:
|
|
646
|
+
for key in ("schema_fingerprint", "verification"):
|
|
647
|
+
payload.pop(key, None)
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
def _trim_import_status_payload(payload: JSONObject) -> None:
|
|
651
|
+
total_rows = payload.get("total_rows")
|
|
652
|
+
success_rows = payload.get("success_rows")
|
|
653
|
+
failed_rows = payload.get("failed_rows")
|
|
654
|
+
payload["total"] = total_rows
|
|
655
|
+
if isinstance(success_rows, int) and isinstance(failed_rows, int):
|
|
656
|
+
payload["finished"] = success_rows + failed_rows
|
|
657
|
+
elif isinstance(success_rows, int):
|
|
658
|
+
payload["finished"] = success_rows
|
|
659
|
+
else:
|
|
660
|
+
payload["finished"] = None
|
|
661
|
+
payload["succeeded"] = success_rows
|
|
662
|
+
payload["failed"] = failed_rows
|
|
663
|
+
for key in (
|
|
664
|
+
"matched_by",
|
|
665
|
+
"source_file_name",
|
|
666
|
+
"total_rows",
|
|
667
|
+
"success_rows",
|
|
668
|
+
"failed_rows",
|
|
669
|
+
"error_file_urls",
|
|
670
|
+
"operate_time",
|
|
671
|
+
"operate_user",
|
|
672
|
+
"verification",
|
|
673
|
+
):
|
|
674
|
+
payload.pop(key, None)
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
def _summarize_import_issues(issues: list[Any]) -> dict[str, Any]:
|
|
678
|
+
total = 0
|
|
679
|
+
error_count = 0
|
|
680
|
+
warning_count = 0
|
|
681
|
+
sample: list[dict[str, Any]] = []
|
|
682
|
+
for item in issues:
|
|
683
|
+
if not isinstance(item, dict):
|
|
684
|
+
continue
|
|
685
|
+
total += 1
|
|
686
|
+
severity = str(item.get("severity") or "").lower()
|
|
687
|
+
if severity == "error":
|
|
688
|
+
error_count += 1
|
|
689
|
+
if severity == "warning":
|
|
690
|
+
warning_count += 1
|
|
691
|
+
if len(sample) < 3:
|
|
692
|
+
sample.append(
|
|
693
|
+
{
|
|
694
|
+
"code": item.get("code"),
|
|
695
|
+
"message": item.get("message"),
|
|
696
|
+
"severity": item.get("severity"),
|
|
697
|
+
}
|
|
698
|
+
)
|
|
699
|
+
return {
|
|
700
|
+
"total": total,
|
|
701
|
+
"errors": error_count,
|
|
702
|
+
"warnings": warning_count,
|
|
703
|
+
"sample": sample,
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
def _trim_directory(payload: JSONObject) -> None:
|
|
708
|
+
pass
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
def _trim_feedback(payload: JSONObject) -> None:
|
|
712
|
+
payload.pop("normalized_payload", None)
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
def _trim_builder_envelope(payload: JSONObject) -> None:
|
|
716
|
+
if str(payload.get("status") or "").lower() == "success":
|
|
717
|
+
details = payload.get("details")
|
|
718
|
+
if isinstance(details, dict):
|
|
719
|
+
_drop_deep_keys(details, {"request_route", "base_url", "normalized_args", "suggested_next_call", "transport", "response", "body", "raw"})
|
|
720
|
+
compact = _compact_scalar_dict(details)
|
|
721
|
+
if compact:
|
|
722
|
+
payload["details"] = compact
|
|
723
|
+
else:
|
|
724
|
+
payload.pop("details", None)
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
def _trim_builder_list_like(payload: JSONObject) -> None:
|
|
728
|
+
_trim_builder_envelope(payload)
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
def _register_policy(domains: tuple[str, ...], names: tuple[str, ...], transform: TransformFn) -> None:
|
|
732
|
+
for domain in domains:
|
|
733
|
+
for name in names:
|
|
734
|
+
SUCCESS_POLICY_BY_TOOL[tool_key(domain, name)] = transform
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
_register_policy((USER_DOMAIN, BUILDER_DOMAIN), ("auth_use_credential", "auth_whoami"), _trim_auth_payload)
|
|
738
|
+
_register_policy((USER_DOMAIN, BUILDER_DOMAIN), ("auth_logout",), _trim_auth_logout)
|
|
739
|
+
_register_policy((USER_DOMAIN, BUILDER_DOMAIN), ("workspace_list",), _trim_workspace_list)
|
|
740
|
+
_register_policy((USER_DOMAIN, BUILDER_DOMAIN), ("workspace_get", "workspace_select"), _trim_workspace_get)
|
|
741
|
+
_register_policy((USER_DOMAIN,), ("app_list", "app_search"), _trim_app_search_like)
|
|
742
|
+
_register_policy((USER_DOMAIN, BUILDER_DOMAIN), ("app_get",), _trim_app_get)
|
|
743
|
+
_register_policy((BUILDER_DOMAIN,), ("app_repair_code_blocks",), _trim_builder_list_like)
|
|
744
|
+
_register_policy((USER_DOMAIN, BUILDER_DOMAIN), ("portal_list", "portal_get", "view_get", "chart_get"), _trim_builder_list_like)
|
|
745
|
+
_register_policy((USER_DOMAIN,), ("file_get_upload_info",), _trim_file_upload_info)
|
|
746
|
+
_register_policy((USER_DOMAIN, BUILDER_DOMAIN), ("file_upload_local",), _trim_file_upload_local)
|
|
747
|
+
_register_policy(
|
|
748
|
+
(USER_DOMAIN,),
|
|
749
|
+
(
|
|
750
|
+
"record_import_schema_get",
|
|
751
|
+
"record_import_template_get",
|
|
752
|
+
"record_import_verify",
|
|
753
|
+
"record_import_repair_local",
|
|
754
|
+
"record_import_start",
|
|
755
|
+
"record_import_status_get",
|
|
756
|
+
),
|
|
757
|
+
_trim_import_schema,
|
|
758
|
+
)
|
|
759
|
+
_register_policy(
|
|
760
|
+
(USER_DOMAIN,),
|
|
761
|
+
(
|
|
762
|
+
"record_schema_get",
|
|
763
|
+
"record_insert_schema_get",
|
|
764
|
+
"record_browse_schema_get",
|
|
765
|
+
"record_update_schema_get",
|
|
766
|
+
"record_code_block_schema_get",
|
|
767
|
+
),
|
|
768
|
+
_trim_record_schema,
|
|
769
|
+
)
|
|
770
|
+
_register_policy((USER_DOMAIN,), ("record_insert", "record_update"), _trim_record_write)
|
|
771
|
+
_register_policy((USER_DOMAIN,), ("record_get",), _trim_record_get)
|
|
772
|
+
_register_policy((USER_DOMAIN,), ("record_list",), _trim_record_list)
|
|
773
|
+
_register_policy((USER_DOMAIN,), ("record_analyze",), _trim_record_analyze)
|
|
774
|
+
_register_policy((USER_DOMAIN,), ("record_code_block_run",), _trim_code_block_run)
|
|
775
|
+
_register_policy((USER_DOMAIN,), ("task_list",), _trim_task_list)
|
|
776
|
+
_register_policy((USER_DOMAIN,), ("task_get",), _trim_task_get)
|
|
777
|
+
_register_policy(
|
|
778
|
+
(USER_DOMAIN,),
|
|
779
|
+
(
|
|
780
|
+
"task_action_execute",
|
|
781
|
+
"task_associated_report_detail_get",
|
|
782
|
+
"task_workflow_log_get",
|
|
783
|
+
),
|
|
784
|
+
_trim_task_context_detail,
|
|
785
|
+
)
|
|
786
|
+
_register_policy(
|
|
787
|
+
(USER_DOMAIN,),
|
|
788
|
+
(
|
|
789
|
+
"directory_search",
|
|
790
|
+
"directory_list_internal_users",
|
|
791
|
+
"directory_list_all_internal_users",
|
|
792
|
+
"directory_list_internal_departments",
|
|
793
|
+
"directory_list_all_departments",
|
|
794
|
+
"directory_list_sub_departments",
|
|
795
|
+
"directory_list_external_members",
|
|
796
|
+
),
|
|
797
|
+
_trim_directory,
|
|
798
|
+
)
|
|
799
|
+
_register_policy((USER_DOMAIN, BUILDER_DOMAIN), ("feedback_submit",), _trim_feedback)
|
|
800
|
+
_register_policy(
|
|
801
|
+
(USER_DOMAIN,),
|
|
802
|
+
(
|
|
803
|
+
"record_member_candidates",
|
|
804
|
+
"record_department_candidates",
|
|
805
|
+
),
|
|
806
|
+
_trim_builder_list_like,
|
|
807
|
+
)
|
|
808
|
+
_register_policy((USER_DOMAIN,), ("record_delete",), _trim_record_delete)
|
|
809
|
+
_register_policy(
|
|
810
|
+
(BUILDER_DOMAIN,),
|
|
811
|
+
(
|
|
812
|
+
"builder_tool_contract",
|
|
813
|
+
"package_get",
|
|
814
|
+
"package_apply",
|
|
815
|
+
"solution_install",
|
|
816
|
+
"member_search",
|
|
817
|
+
"role_search",
|
|
818
|
+
"role_create",
|
|
819
|
+
"app_release_edit_lock_if_mine",
|
|
820
|
+
"app_resolve",
|
|
821
|
+
"app_custom_button_list",
|
|
822
|
+
"app_custom_button_get",
|
|
823
|
+
"app_custom_button_create",
|
|
824
|
+
"app_custom_button_update",
|
|
825
|
+
"app_custom_button_delete",
|
|
826
|
+
"app_get_fields",
|
|
827
|
+
"app_repair_code_blocks",
|
|
828
|
+
"app_get_layout",
|
|
829
|
+
"app_get_views",
|
|
830
|
+
"app_get_flow",
|
|
831
|
+
"app_get_charts",
|
|
832
|
+
"app_schema_apply",
|
|
833
|
+
"app_layout_apply",
|
|
834
|
+
"app_flow_apply",
|
|
835
|
+
"app_views_apply",
|
|
836
|
+
"app_charts_apply",
|
|
837
|
+
"portal_apply",
|
|
838
|
+
"app_publish_verify",
|
|
839
|
+
),
|
|
840
|
+
_trim_builder_list_like,
|
|
841
|
+
)
|