mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-29 09:02:02 +03:00
fix(doctor): migrate Slack/Discord dm.policy keys to aliases
This commit is contained in:
@@ -111,4 +111,44 @@ describe("normalizeLegacyConfigValues", () => {
|
|||||||
fs.rmSync(customDir, { recursive: true, force: true });
|
fs.rmSync(customDir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("migrates Slack dm.policy/dm.allowFrom to dmPolicy/allowFrom aliases", () => {
|
||||||
|
const res = normalizeLegacyConfigValues({
|
||||||
|
channels: {
|
||||||
|
slack: {
|
||||||
|
dm: { enabled: true, policy: "open", allowFrom: ["*"] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.config.channels?.slack?.dmPolicy).toBe("open");
|
||||||
|
expect(res.config.channels?.slack?.allowFrom).toEqual(["*"]);
|
||||||
|
expect(res.config.channels?.slack?.dm).toEqual({ enabled: true });
|
||||||
|
expect(res.changes).toEqual([
|
||||||
|
"Moved channels.slack.dm.policy → channels.slack.dmPolicy.",
|
||||||
|
"Moved channels.slack.dm.allowFrom → channels.slack.allowFrom.",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("migrates Discord account dm.policy/dm.allowFrom to dmPolicy/allowFrom aliases", () => {
|
||||||
|
const res = normalizeLegacyConfigValues({
|
||||||
|
channels: {
|
||||||
|
discord: {
|
||||||
|
accounts: {
|
||||||
|
work: {
|
||||||
|
dm: { policy: "allowlist", allowFrom: ["123"], groupEnabled: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.config.channels?.discord?.accounts?.work?.dmPolicy).toBe("allowlist");
|
||||||
|
expect(res.config.channels?.discord?.accounts?.work?.allowFrom).toEqual(["123"]);
|
||||||
|
expect(res.config.channels?.discord?.accounts?.work?.dm).toEqual({ groupEnabled: true });
|
||||||
|
expect(res.changes).toEqual([
|
||||||
|
"Moved channels.discord.accounts.work.dm.policy → channels.discord.accounts.work.dmPolicy.",
|
||||||
|
"Moved channels.discord.accounts.work.dm.allowFrom → channels.discord.accounts.work.allowFrom.",
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,6 +6,151 @@ export function normalizeLegacyConfigValues(cfg: OpenClawConfig): {
|
|||||||
const changes: string[] = [];
|
const changes: string[] = [];
|
||||||
let next: OpenClawConfig = cfg;
|
let next: OpenClawConfig = cfg;
|
||||||
|
|
||||||
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||||
|
Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
||||||
|
|
||||||
|
const normalizeDmAliases = (params: {
|
||||||
|
provider: "slack" | "discord";
|
||||||
|
entry: Record<string, unknown>;
|
||||||
|
pathPrefix: string;
|
||||||
|
}): { entry: Record<string, unknown>; changed: boolean } => {
|
||||||
|
let changed = false;
|
||||||
|
let updated: Record<string, unknown> = params.entry;
|
||||||
|
const rawDm = updated.dm;
|
||||||
|
const dm = isRecord(rawDm) ? structuredClone(rawDm) : null;
|
||||||
|
let dmChanged = false;
|
||||||
|
|
||||||
|
const allowFromEqual = (a: unknown, b: unknown): boolean => {
|
||||||
|
if (!Array.isArray(a) || !Array.isArray(b)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const na = a.map((v) => String(v).trim()).filter(Boolean);
|
||||||
|
const nb = b.map((v) => String(v).trim()).filter(Boolean);
|
||||||
|
if (na.length !== nb.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return na.every((v, i) => v === nb[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const topDmPolicy = updated.dmPolicy;
|
||||||
|
const legacyDmPolicy = dm?.policy;
|
||||||
|
if (topDmPolicy === undefined && legacyDmPolicy !== undefined) {
|
||||||
|
updated = { ...updated, dmPolicy: legacyDmPolicy };
|
||||||
|
changed = true;
|
||||||
|
if (dm) {
|
||||||
|
delete dm.policy;
|
||||||
|
dmChanged = true;
|
||||||
|
}
|
||||||
|
changes.push(`Moved ${params.pathPrefix}.dm.policy → ${params.pathPrefix}.dmPolicy.`);
|
||||||
|
} else if (topDmPolicy !== undefined && legacyDmPolicy !== undefined) {
|
||||||
|
if (topDmPolicy === legacyDmPolicy) {
|
||||||
|
if (dm) {
|
||||||
|
delete dm.policy;
|
||||||
|
dmChanged = true;
|
||||||
|
changes.push(`Removed ${params.pathPrefix}.dm.policy (dmPolicy already set).`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
changes.push(
|
||||||
|
`Kept ${params.pathPrefix}.dm.policy (conflicts with ${params.pathPrefix}.dmPolicy).`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const topAllowFrom = updated.allowFrom;
|
||||||
|
const legacyAllowFrom = dm?.allowFrom;
|
||||||
|
if (topAllowFrom === undefined && legacyAllowFrom !== undefined) {
|
||||||
|
updated = { ...updated, allowFrom: legacyAllowFrom };
|
||||||
|
changed = true;
|
||||||
|
if (dm) {
|
||||||
|
delete dm.allowFrom;
|
||||||
|
dmChanged = true;
|
||||||
|
}
|
||||||
|
changes.push(`Moved ${params.pathPrefix}.dm.allowFrom → ${params.pathPrefix}.allowFrom.`);
|
||||||
|
} else if (topAllowFrom !== undefined && legacyAllowFrom !== undefined) {
|
||||||
|
if (allowFromEqual(topAllowFrom, legacyAllowFrom)) {
|
||||||
|
if (dm) {
|
||||||
|
delete dm.allowFrom;
|
||||||
|
dmChanged = true;
|
||||||
|
changes.push(`Removed ${params.pathPrefix}.dm.allowFrom (allowFrom already set).`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
changes.push(
|
||||||
|
`Kept ${params.pathPrefix}.dm.allowFrom (conflicts with ${params.pathPrefix}.allowFrom).`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dm && isRecord(rawDm) && dmChanged) {
|
||||||
|
const keys = Object.keys(dm);
|
||||||
|
if (keys.length === 0) {
|
||||||
|
if (updated.dm !== undefined) {
|
||||||
|
const { dm: _ignored, ...rest } = updated;
|
||||||
|
updated = rest;
|
||||||
|
changed = true;
|
||||||
|
changes.push(`Removed empty ${params.pathPrefix}.dm after migration.`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updated = { ...updated, dm };
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { entry: updated, changed };
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeProvider = (provider: "slack" | "discord") => {
|
||||||
|
const channels = next.channels as Record<string, unknown> | undefined;
|
||||||
|
const rawEntry = channels?.[provider];
|
||||||
|
if (!isRecord(rawEntry)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const base = normalizeDmAliases({
|
||||||
|
provider,
|
||||||
|
entry: rawEntry,
|
||||||
|
pathPrefix: `channels.${provider}`,
|
||||||
|
});
|
||||||
|
let updated = base.entry;
|
||||||
|
let changed = base.changed;
|
||||||
|
|
||||||
|
const rawAccounts = updated.accounts;
|
||||||
|
if (isRecord(rawAccounts)) {
|
||||||
|
let accountsChanged = false;
|
||||||
|
const accounts = { ...rawAccounts };
|
||||||
|
for (const [accountId, rawAccount] of Object.entries(rawAccounts)) {
|
||||||
|
if (!isRecord(rawAccount)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const res = normalizeDmAliases({
|
||||||
|
provider,
|
||||||
|
entry: rawAccount,
|
||||||
|
pathPrefix: `channels.${provider}.accounts.${accountId}`,
|
||||||
|
});
|
||||||
|
if (res.changed) {
|
||||||
|
accounts[accountId] = res.entry;
|
||||||
|
accountsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (accountsChanged) {
|
||||||
|
updated = { ...updated, accounts };
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
next = {
|
||||||
|
...next,
|
||||||
|
channels: {
|
||||||
|
...next.channels,
|
||||||
|
[provider]: updated as unknown,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
normalizeProvider("slack");
|
||||||
|
normalizeProvider("discord");
|
||||||
|
|
||||||
const legacyAckReaction = cfg.messages?.ackReaction?.trim();
|
const legacyAckReaction = cfg.messages?.ackReaction?.trim();
|
||||||
const hasWhatsAppConfig = cfg.channels?.whatsapp !== undefined;
|
const hasWhatsAppConfig = cfg.channels?.whatsapp !== undefined;
|
||||||
if (legacyAckReaction && hasWhatsAppConfig) {
|
if (legacyAckReaction && hasWhatsAppConfig) {
|
||||||
|
|||||||
Reference in New Issue
Block a user