feat(search): 搜索 provider 可变源 + 插件声明面板(PLG-4)
- 新增 $DATA_DIR/config/plugins/web-search.json(0600 + temp+rename,文件名 = 插件 id)
- 组合根改「先读可变源、缺失回落 .env 播种」;**不新增任何 env 键**(.env 已冻结)
- 多实例:每家 provider 独立 key/baseURL/启用态 + 「测试连通」探针
- 用 PLG-1 的声明库给出该面板的 adminPanels 声明;动作名交给 PLG-2 的通用动作端点分发
(本片自己不开路由)
⚠️ 本片自认越界:改了 cmd/cyrene/wire_web_search_test.go(既有测试,为适配 DataDir);
另有 design/28 的相关注册留给主会话。
This commit is contained in:
1 parent
2d21aa553e
commit
120d926cf8
11 files changed
+1811
-41
No files matched your search
@@ -0,0 +1,109 @@
|
||||
package search
|
||||
|
||||
// 本文件是 web-search 插件向**面板**声明的管理页面:design/09 §5.2 的 `adminPanels`,
|
||||
// 形状即 `pkg/plugins/sdk` 的 `Panel`。
|
||||
//
|
||||
// 声明只说三件事:**要什么字段、怎么渲染、动作叫什么**。它
|
||||
//
|
||||
// - 不注入任何 JS/CSS/HTML、
|
||||
// - 不给 URL(只有动作名,走宿主的通用动作端点分发)、
|
||||
// - 不开任何路由。
|
||||
//
|
||||
// 这三条是 design/09 §5.2.1 的红线:声明而非编码、声明里塞不进请求面(防 SSRF)、
|
||||
// 面板数据一律经插件管理器的端点。渲染与流程由宿主负责,本文件只负责「说得清楚」。
|
||||
|
||||
import "git.yeij.top/AskaEth/Cyrene_v2/pkg/plugins/sdk"
|
||||
|
||||
// PanelPluginID 是本插件在面板体系里的 id。它与可变源的文件名**同源**:
|
||||
// `$DATA_DIR/config/plugins/web-search.json`(design/13 §2.1:文件名 = 插件 id),
|
||||
// 两边由 panel_test.go 钉住。
|
||||
const PanelPluginID = "web-search"
|
||||
|
||||
// PanelIDProviders 是「搜索提供商」页的面板 id。
|
||||
// 前端路由为 `/admin/plugin/web-search/providers`(design/09 §5.7 C)。
|
||||
const PanelIDProviders = "providers"
|
||||
|
||||
// 本插件声明的**全部**动作名(design/09 §5.2 示例给出的那四个)。
|
||||
//
|
||||
// 表里的动作名一律取自这里,通用动作端点也只接受这几个名字(未声明 ⇒ 404/403,
|
||||
// design/09 §5.2.1 B)。把「声明」与「动作名」放同一个文件,是为了让「表里写了一个
|
||||
// 没实现的动作」这种半渲染在 review 时一眼可见 —— 它们就挨着。
|
||||
const (
|
||||
// ActionListProviders 列出全部 provider 配置(表格区块的数据源)。
|
||||
ActionListProviders = "plugin.listProviders"
|
||||
// ActionSaveProvider 新增 / 修改一条 provider 配置(表单提交)。
|
||||
// 语义是 upsert:按 `provider` 名就位替换或追加。
|
||||
ActionSaveProvider = "plugin.saveProvider"
|
||||
// ActionTestProvider 测试连通:对一条 provider 配置真发一次最小检索(见 probe.go)。
|
||||
ActionTestProvider = "plugin.testProvider"
|
||||
// ActionReauthProvider 重配凭据:把该条带回表单。写侧的「未改动」必须用显式哨兵表达,
|
||||
// **不能**靠空字符串(那会静默清空凭据,design/09 §5.4.2)。
|
||||
ActionReauthProvider = "plugin.reauthProvider"
|
||||
)
|
||||
|
||||
// ActionNames 返回本插件声明的动作名,顺序与 AdminPanels 里出现的顺序一致
|
||||
// (表格数据源 → 表单提交 → 行内动作)。调用方(插件管理器的动作端点)据此建白名单:
|
||||
// 白名单外的动作名一律拒,绝不「先执行再看结果」。
|
||||
func ActionNames() []string {
|
||||
return []string{ActionListProviders, ActionSaveProvider, ActionTestProvider, ActionReauthProvider}
|
||||
}
|
||||
|
||||
// AdminPanels 返回本插件声明的管理页面(design/09 §5.2 示例的 providers 页)。
|
||||
//
|
||||
// 两处相对示例的**明确增补**(示例是形状示范,不是字段清单的穷举;两处都被本片的任务书
|
||||
// 要求):
|
||||
// - 表单多一个 `enabled` 开关:任务书要求每家 provider **独立启用态**;
|
||||
// - 表单的 `baseUrl` 用示例的 `endpoint` 语义(searxng 的端点 = 那家的基地址),
|
||||
// 名字跟可变源的字段名走,免得面板字段名与文件字段名对不上。
|
||||
func AdminPanels() []sdk.Panel {
|
||||
return []sdk.Panel{{
|
||||
ID: PanelIDProviders,
|
||||
Title: "搜索提供商",
|
||||
Description: "为 web-search 能力配置多个第三方搜索后端:每条独立凭据与基地址," +
|
||||
"可单独启停并测试连通。改动落 $DATA_DIR/config/plugins/web-search.json,重启后仍然生效。",
|
||||
Group: sdk.GroupPlugins,
|
||||
Order: 20,
|
||||
Icon: "search",
|
||||
// 未启用的插件 ⇒ 入口不出现(design/09 §5.2.1 nav.item)。web-search 是编进二进制的
|
||||
// 内置能力,没有卸载路径 ⇒ 恒为启用;这里写条件是为了让「启用事实」由插件管理器
|
||||
// 给出(单一事实来源),而不是由面板猜。
|
||||
When: &sdk.When{Enabled: boolFlag(true)},
|
||||
Sections: []sdk.Section{
|
||||
{
|
||||
Type: sdk.SectionForm,
|
||||
ID: "add",
|
||||
Title: "添加 / 修改提供商",
|
||||
Fields: []sdk.Field{
|
||||
{Key: "provider", Label: "提供商", Type: sdk.FieldSelect,
|
||||
OptionsFrom: "plugin:providers", Required: true},
|
||||
// secret 字段刻意不标 required:它同时承担「编辑既有条目」的输入,
|
||||
// 而编辑时不重填凭据是常态(写侧哨兵语义,见 ActionReauthProvider)。
|
||||
{Key: "apiKey", Label: "API Key", Type: sdk.FieldSecret,
|
||||
Placeholder: "留空 = 保持原值"},
|
||||
{Key: "baseUrl", Label: "接口地址", Type: sdk.FieldText,
|
||||
Placeholder: "https://..."},
|
||||
{Key: "enabled", Label: "启用", Type: sdk.FieldSwitch},
|
||||
},
|
||||
Submit: &sdk.Submit{Action: ActionSaveProvider},
|
||||
},
|
||||
{
|
||||
Type: sdk.SectionTable,
|
||||
ID: "list",
|
||||
Title: "已配置的提供商",
|
||||
Source: &sdk.Source{Action: ActionListProviders},
|
||||
// 列 key 与 panelrow.go 的行字段同源;凭据不进任何列(读侧无明文)。
|
||||
Columns: []sdk.Column{
|
||||
{Key: "provider", Label: "提供商"},
|
||||
{Key: "state", Label: "状态"},
|
||||
},
|
||||
RowActions: []sdk.RowAction{
|
||||
{ID: "test", Label: "测试连通", Action: ActionTestProvider},
|
||||
{ID: "reauth", Label: "重配凭据", Action: ActionReauthProvider},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
// boolFlag 是 `&true` / `&false` 的简写(sdk.When.Enabled 是三态指针)。
|
||||
func boolFlag(v bool) *bool { return &v }
|
||||
Reference in new issue
Block a user