diff --git a/extensions/mattermost/src/channel-config-shared.ts b/extensions/mattermost/src/channel-config-shared.ts new file mode 100644 index 00000000000..8cdb49c5313 --- /dev/null +++ b/extensions/mattermost/src/channel-config-shared.ts @@ -0,0 +1,74 @@ +import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers"; +import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from"; +import { + adaptScopedAccountAccessor, + createScopedChannelConfigAdapter, +} from "openclaw/plugin-sdk/channel-config-helpers"; +import { + listMattermostAccountIds, + resolveDefaultMattermostAccountId, + resolveMattermostAccount, + type ResolvedMattermostAccount, +} from "./mattermost/accounts.js"; + +export const mattermostMeta = { + id: "mattermost", + label: "Mattermost", + selectionLabel: "Mattermost (plugin)", + detailLabel: "Mattermost Bot", + docsPath: "/channels/mattermost", + docsLabel: "mattermost", + blurb: "self-hosted Slack-style chat; install the plugin to enable.", + systemImage: "bubble.left.and.bubble.right", + order: 65, + quickstartAllowFrom: true, +} as const; + +export function normalizeMattermostAllowEntry(entry: string): string { + return entry + .trim() + .replace(/^(mattermost|user):/i, "") + .replace(/^@/, "") + .toLowerCase(); +} + +export function formatMattermostAllowEntry(entry: string): string { + const trimmed = entry.trim(); + if (!trimmed) { + return ""; + } + if (trimmed.startsWith("@")) { + const username = trimmed.slice(1).trim(); + return username ? `@${username.toLowerCase()}` : ""; + } + return trimmed.replace(/^(mattermost|user):/i, "").toLowerCase(); +} + +export const mattermostConfigAdapter = createScopedChannelConfigAdapter({ + sectionKey: "mattermost", + listAccountIds: listMattermostAccountIds, + resolveAccount: adaptScopedAccountAccessor(resolveMattermostAccount), + defaultAccountId: resolveDefaultMattermostAccountId, + clearBaseFields: ["botToken", "baseUrl", "name"], + resolveAllowFrom: (account) => account.config.allowFrom, + formatAllowFrom: (allowFrom) => + formatNormalizedAllowFromEntries({ + allowFrom, + normalizeEntry: formatMattermostAllowEntry, + }), +}); + +export function isMattermostConfigured(account: ResolvedMattermostAccount): boolean { + return Boolean(account.botToken && account.baseUrl); +} + +export function describeMattermostAccount(account: ResolvedMattermostAccount) { + return describeAccountSnapshot({ + account, + configured: isMattermostConfigured(account), + extra: { + botTokenSource: account.botTokenSource, + baseUrl: account.baseUrl, + }, + }); +} diff --git a/extensions/mattermost/src/channel.setup.ts b/extensions/mattermost/src/channel.setup.ts index a4543bf16d1..973c2456d7f 100644 --- a/extensions/mattermost/src/channel.setup.ts +++ b/extensions/mattermost/src/channel.setup.ts @@ -1,59 +1,15 @@ -import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers"; -import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from"; -import { - adaptScopedAccountAccessor, - createScopedChannelConfigAdapter, -} from "openclaw/plugin-sdk/channel-config-helpers"; import type { ChannelPlugin } from "./channel-api.js"; -import { MattermostChannelConfigSchema } from "./config-surface.js"; import { - listMattermostAccountIds, - resolveDefaultMattermostAccountId, - resolveMattermostAccount, - type ResolvedMattermostAccount, -} from "./mattermost/accounts.js"; + describeMattermostAccount, + isMattermostConfigured, + mattermostConfigAdapter, + mattermostMeta, +} from "./channel-config-shared.js"; +import { MattermostChannelConfigSchema } from "./config-surface.js"; +import { type ResolvedMattermostAccount } from "./mattermost/accounts.js"; import { mattermostSetupAdapter } from "./setup-core.js"; import { mattermostSetupWizard } from "./setup-surface.js"; -const mattermostMeta = { - id: "mattermost", - label: "Mattermost", - selectionLabel: "Mattermost (plugin)", - detailLabel: "Mattermost Bot", - docsPath: "/channels/mattermost", - docsLabel: "mattermost", - blurb: "self-hosted Slack-style chat; install the plugin to enable.", - systemImage: "bubble.left.and.bubble.right", - order: 65, - quickstartAllowFrom: true, -} as const; - -function formatAllowEntry(entry: string): string { - const trimmed = entry.trim(); - if (!trimmed) { - return ""; - } - if (trimmed.startsWith("@")) { - const username = trimmed.slice(1).trim(); - return username ? `@${username.toLowerCase()}` : ""; - } - return trimmed.replace(/^(mattermost|user):/i, "").toLowerCase(); -} - -const mattermostConfigAdapter = createScopedChannelConfigAdapter({ - sectionKey: "mattermost", - listAccountIds: listMattermostAccountIds, - resolveAccount: adaptScopedAccountAccessor(resolveMattermostAccount), - defaultAccountId: resolveDefaultMattermostAccountId, - clearBaseFields: ["botToken", "baseUrl", "name"], - resolveAllowFrom: (account) => account.config.allowFrom, - formatAllowFrom: (allowFrom) => - formatNormalizedAllowFromEntries({ - allowFrom, - normalizeEntry: formatAllowEntry, - }), -}); - export const mattermostSetupPlugin: ChannelPlugin = { id: "mattermost", meta: { @@ -70,16 +26,8 @@ export const mattermostSetupPlugin: ChannelPlugin = { configSchema: MattermostChannelConfigSchema, config: { ...mattermostConfigAdapter, - isConfigured: (account) => Boolean(account.botToken && account.baseUrl), - describeAccount: (account) => - describeAccountSnapshot({ - account, - configured: Boolean(account.botToken && account.baseUrl), - extra: { - botTokenSource: account.botTokenSource, - baseUrl: account.baseUrl, - }, - }), + isConfigured: isMattermostConfigured, + describeAccount: describeMattermostAccount, }, setup: mattermostSetupAdapter, setupWizard: mattermostSetupWizard, diff --git a/extensions/mattermost/src/channel.ts b/extensions/mattermost/src/channel.ts index 8a777ba51c5..111e25d6017 100644 --- a/extensions/mattermost/src/channel.ts +++ b/extensions/mattermost/src/channel.ts @@ -1,11 +1,5 @@ import { Type } from "@sinclair/typebox"; -import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers"; -import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from"; import { createMessageToolButtonsSchema } from "openclaw/plugin-sdk/channel-actions"; -import { - adaptScopedAccountAccessor, - createScopedChannelConfigAdapter, -} from "openclaw/plugin-sdk/channel-config-helpers"; import type { ChannelMessageActionAdapter, ChannelMessageActionName, @@ -29,6 +23,13 @@ import { DEFAULT_ACCOUNT_ID, type ChannelPlugin, } from "./channel-api.js"; +import { + describeMattermostAccount, + isMattermostConfigured, + mattermostConfigAdapter, + mattermostMeta as meta, + normalizeMattermostAllowEntry as normalizeAllowEntry, +} from "./channel-config-shared.js"; import { MattermostChannelConfigSchema } from "./config-surface.js"; import { mattermostDoctor } from "./doctor.js"; import { resolveMattermostGroupRequireMention } from "./group-mentions.js"; @@ -241,19 +242,6 @@ const mattermostMessageActions: ChannelMessageActionAdapter = { }, }; -const meta = { - id: "mattermost", - label: "Mattermost", - selectionLabel: "Mattermost (plugin)", - detailLabel: "Mattermost Bot", - docsPath: "/channels/mattermost", - docsLabel: "mattermost", - blurb: "self-hosted Slack-style chat; install the plugin to enable.", - systemImage: "bubble.left.and.bubble.right", - order: 65, - quickstartAllowFrom: true, -} as const; - function readTrimmedString(value: unknown): string | undefined { if (typeof value !== "string") { return undefined; @@ -288,40 +276,6 @@ function readMattermostReplyToId(params: Record): string | unde return readTrimmedString(params.replyToId) ?? readTrimmedString(params.replyTo); } -function normalizeAllowEntry(entry: string): string { - return entry - .trim() - .replace(/^(mattermost|user):/i, "") - .replace(/^@/, "") - .toLowerCase(); -} - -function formatAllowEntry(entry: string): string { - const trimmed = entry.trim(); - if (!trimmed) { - return ""; - } - if (trimmed.startsWith("@")) { - const username = trimmed.slice(1).trim(); - return username ? `@${username.toLowerCase()}` : ""; - } - return trimmed.replace(/^(mattermost|user):/i, "").toLowerCase(); -} - -const mattermostConfigAdapter = createScopedChannelConfigAdapter({ - sectionKey: "mattermost", - listAccountIds: listMattermostAccountIds, - resolveAccount: adaptScopedAccountAccessor(resolveMattermostAccount), - defaultAccountId: resolveDefaultMattermostAccountId, - clearBaseFields: ["botToken", "baseUrl", "name"], - resolveAllowFrom: (account: ResolvedMattermostAccount) => account.config.allowFrom, - formatAllowFrom: (allowFrom) => - formatNormalizedAllowFromEntries({ - allowFrom, - normalizeEntry: formatAllowEntry, - }), -}); - export const mattermostPlugin: ChannelPlugin = createChatChannelPlugin({ base: { id: "mattermost", @@ -344,16 +298,8 @@ export const mattermostPlugin: ChannelPlugin = create configSchema: MattermostChannelConfigSchema, config: { ...mattermostConfigAdapter, - isConfigured: (account) => Boolean(account.botToken && account.baseUrl), - describeAccount: (account) => - describeAccountSnapshot({ - account, - configured: Boolean(account.botToken && account.baseUrl), - extra: { - botTokenSource: account.botTokenSource, - baseUrl: account.baseUrl, - }, - }), + isConfigured: isMattermostConfigured, + describeAccount: describeMattermostAccount, }, auth: mattermostApprovalAuth, doctor: mattermostDoctor,