mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 07:17:26 +00:00
refactor(mattermost): dedupe reaction flow and test fixtures
This commit is contained in:
@@ -1,7 +1,13 @@
|
|||||||
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
||||||
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
|
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
|
||||||
import { describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it } from "vitest";
|
||||||
import { mattermostPlugin } from "./channel.js";
|
import { mattermostPlugin } from "./channel.js";
|
||||||
|
import { resetMattermostReactionBotUserCacheForTests } from "./mattermost/reactions.js";
|
||||||
|
import {
|
||||||
|
createMattermostReactionFetchMock,
|
||||||
|
createMattermostTestConfig,
|
||||||
|
withMockedGlobalFetch,
|
||||||
|
} from "./mattermost/reactions.test-helpers.js";
|
||||||
|
|
||||||
describe("mattermostPlugin", () => {
|
describe("mattermostPlugin", () => {
|
||||||
describe("messaging", () => {
|
describe("messaging", () => {
|
||||||
@@ -44,6 +50,10 @@ describe("mattermostPlugin", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("messageActions", () => {
|
describe("messageActions", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
resetMattermostReactionBotUserCacheForTests();
|
||||||
|
});
|
||||||
|
|
||||||
it("exposes react when mattermost is configured", () => {
|
it("exposes react when mattermost is configured", () => {
|
||||||
const cfg: OpenClawConfig = {
|
const cfg: OpenClawConfig = {
|
||||||
channels: {
|
channels: {
|
||||||
@@ -142,41 +152,14 @@ describe("mattermostPlugin", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("handles react by calling Mattermost reactions API", async () => {
|
it("handles react by calling Mattermost reactions API", async () => {
|
||||||
const cfg: OpenClawConfig = {
|
const cfg = createMattermostTestConfig();
|
||||||
channels: {
|
const fetchImpl = createMattermostReactionFetchMock({
|
||||||
mattermost: {
|
mode: "add",
|
||||||
enabled: true,
|
postId: "POST1",
|
||||||
botToken: "test-token",
|
emojiName: "thumbsup",
|
||||||
baseUrl: "https://chat.example.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchImpl = vi.fn(async (url: any, init?: any) => {
|
|
||||||
if (String(url).endsWith("/api/v4/users/me")) {
|
|
||||||
return new Response(JSON.stringify({ id: "BOT123" }), {
|
|
||||||
status: 200,
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (String(url).endsWith("/api/v4/reactions")) {
|
|
||||||
expect(init?.method).toBe("POST");
|
|
||||||
expect(JSON.parse(init?.body)).toEqual({
|
|
||||||
user_id: "BOT123",
|
|
||||||
post_id: "POST1",
|
|
||||||
emoji_name: "thumbsup",
|
|
||||||
});
|
|
||||||
return new Response(JSON.stringify({ ok: true }), {
|
|
||||||
status: 201,
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
throw new Error(`unexpected url: ${url}`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const prevFetch = globalThis.fetch;
|
const result = await withMockedGlobalFetch(fetchImpl as unknown as typeof fetch, async () => {
|
||||||
(globalThis as any).fetch = fetchImpl;
|
|
||||||
try {
|
|
||||||
const result = await mattermostPlugin.actions?.handleAction?.({
|
const result = await mattermostPlugin.actions?.handleAction?.({
|
||||||
channel: "mattermost",
|
channel: "mattermost",
|
||||||
action: "react",
|
action: "react",
|
||||||
@@ -185,51 +168,22 @@ describe("mattermostPlugin", () => {
|
|||||||
accountId: "default",
|
accountId: "default",
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
expect(result?.content).toEqual([
|
return result;
|
||||||
{ type: "text", text: "Reacted with :thumbsup: on POST1" },
|
});
|
||||||
]);
|
|
||||||
expect(result?.details).toEqual({});
|
expect(result?.content).toEqual([{ type: "text", text: "Reacted with :thumbsup: on POST1" }]);
|
||||||
} finally {
|
expect(result?.details).toEqual({});
|
||||||
(globalThis as any).fetch = prevFetch;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("only treats boolean remove flag as removal", async () => {
|
it("only treats boolean remove flag as removal", async () => {
|
||||||
const cfg: OpenClawConfig = {
|
const cfg = createMattermostTestConfig();
|
||||||
channels: {
|
const fetchImpl = createMattermostReactionFetchMock({
|
||||||
mattermost: {
|
mode: "add",
|
||||||
enabled: true,
|
postId: "POST1",
|
||||||
botToken: "test-token",
|
emojiName: "thumbsup",
|
||||||
baseUrl: "https://chat.example.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchImpl = vi.fn(async (url: any, init?: any) => {
|
|
||||||
if (String(url).endsWith("/api/v4/users/me")) {
|
|
||||||
return new Response(JSON.stringify({ id: "BOT123" }), {
|
|
||||||
status: 200,
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (String(url).endsWith("/api/v4/reactions")) {
|
|
||||||
expect(init?.method).toBe("POST");
|
|
||||||
expect(JSON.parse(init?.body)).toEqual({
|
|
||||||
user_id: "BOT123",
|
|
||||||
post_id: "POST1",
|
|
||||||
emoji_name: "thumbsup",
|
|
||||||
});
|
|
||||||
return new Response(JSON.stringify({ ok: true }), {
|
|
||||||
status: 201,
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
throw new Error(`unexpected url: ${url}`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const prevFetch = globalThis.fetch;
|
const result = await withMockedGlobalFetch(fetchImpl as unknown as typeof fetch, async () => {
|
||||||
(globalThis as any).fetch = fetchImpl;
|
|
||||||
try {
|
|
||||||
const result = await mattermostPlugin.actions?.handleAction?.({
|
const result = await mattermostPlugin.actions?.handleAction?.({
|
||||||
channel: "mattermost",
|
channel: "mattermost",
|
||||||
action: "react",
|
action: "react",
|
||||||
@@ -238,12 +192,10 @@ describe("mattermostPlugin", () => {
|
|||||||
accountId: "default",
|
accountId: "default",
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
expect(result?.content).toEqual([
|
return result;
|
||||||
{ type: "text", text: "Reacted with :thumbsup: on POST1" },
|
});
|
||||||
]);
|
|
||||||
} finally {
|
expect(result?.content).toEqual([{ type: "text", text: "Reacted with :thumbsup: on POST1" }]);
|
||||||
(globalThis as any).fetch = prevFetch;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
||||||
|
import { expect, vi } from "vitest";
|
||||||
|
|
||||||
|
export function createMattermostTestConfig(): OpenClawConfig {
|
||||||
|
return {
|
||||||
|
channels: {
|
||||||
|
mattermost: {
|
||||||
|
enabled: true,
|
||||||
|
botToken: "test-token",
|
||||||
|
baseUrl: "https://chat.example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createMattermostReactionFetchMock(params: {
|
||||||
|
postId: string;
|
||||||
|
emojiName: string;
|
||||||
|
mode: "add" | "remove" | "both";
|
||||||
|
userId?: string;
|
||||||
|
status?: number;
|
||||||
|
body?: unknown;
|
||||||
|
}) {
|
||||||
|
const userId = params.userId ?? "BOT123";
|
||||||
|
const mode = params.mode;
|
||||||
|
const allowAdd = mode === "add" || mode === "both";
|
||||||
|
const allowRemove = mode === "remove" || mode === "both";
|
||||||
|
const addStatus = params.status ?? 201;
|
||||||
|
const removeStatus = params.status ?? 204;
|
||||||
|
const removePath = `/api/v4/users/${userId}/posts/${params.postId}/reactions/${encodeURIComponent(params.emojiName)}`;
|
||||||
|
|
||||||
|
return vi.fn(async (url: any, init?: any) => {
|
||||||
|
if (String(url).endsWith("/api/v4/users/me")) {
|
||||||
|
return new Response(JSON.stringify({ id: userId }), {
|
||||||
|
status: 200,
|
||||||
|
headers: { "content-type": "application/json" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowAdd && String(url).endsWith("/api/v4/reactions")) {
|
||||||
|
expect(init?.method).toBe("POST");
|
||||||
|
expect(JSON.parse(init?.body)).toEqual({
|
||||||
|
user_id: userId,
|
||||||
|
post_id: params.postId,
|
||||||
|
emoji_name: params.emojiName,
|
||||||
|
});
|
||||||
|
|
||||||
|
const responseBody = params.body === undefined ? { ok: true } : params.body;
|
||||||
|
return new Response(
|
||||||
|
responseBody === null ? null : JSON.stringify(responseBody),
|
||||||
|
responseBody === null
|
||||||
|
? { status: addStatus, headers: { "content-type": "text/plain" } }
|
||||||
|
: { status: addStatus, headers: { "content-type": "application/json" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowRemove && String(url).endsWith(removePath)) {
|
||||||
|
expect(init?.method).toBe("DELETE");
|
||||||
|
const responseBody = params.body === undefined ? null : params.body;
|
||||||
|
return new Response(
|
||||||
|
responseBody === null ? null : JSON.stringify(responseBody),
|
||||||
|
responseBody === null
|
||||||
|
? { status: removeStatus, headers: { "content-type": "text/plain" } }
|
||||||
|
: { status: removeStatus, headers: { "content-type": "application/json" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`unexpected url: ${url}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function withMockedGlobalFetch<T>(
|
||||||
|
fetchImpl: typeof fetch,
|
||||||
|
run: () => Promise<T>,
|
||||||
|
): Promise<T> {
|
||||||
|
const prevFetch = globalThis.fetch;
|
||||||
|
(globalThis as any).fetch = fetchImpl;
|
||||||
|
try {
|
||||||
|
return await run();
|
||||||
|
} finally {
|
||||||
|
(globalThis as any).fetch = prevFetch;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +1,28 @@
|
|||||||
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
import { beforeEach, describe, expect, it } from "vitest";
|
||||||
import { describe, expect, it, vi } from "vitest";
|
import {
|
||||||
import { addMattermostReaction, removeMattermostReaction } from "./reactions.js";
|
addMattermostReaction,
|
||||||
|
removeMattermostReaction,
|
||||||
function createCfg(): OpenClawConfig {
|
resetMattermostReactionBotUserCacheForTests,
|
||||||
return {
|
} from "./reactions.js";
|
||||||
channels: {
|
import {
|
||||||
mattermost: {
|
createMattermostReactionFetchMock,
|
||||||
enabled: true,
|
createMattermostTestConfig,
|
||||||
botToken: "test-token",
|
} from "./reactions.test-helpers.js";
|
||||||
baseUrl: "https://chat.example.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("mattermost reactions", () => {
|
describe("mattermost reactions", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
resetMattermostReactionBotUserCacheForTests();
|
||||||
|
});
|
||||||
|
|
||||||
it("adds reactions by calling /users/me then POST /reactions", async () => {
|
it("adds reactions by calling /users/me then POST /reactions", async () => {
|
||||||
const fetchMock = vi.fn(async (url: any, init?: any) => {
|
const fetchMock = createMattermostReactionFetchMock({
|
||||||
if (String(url).endsWith("/api/v4/users/me")) {
|
mode: "add",
|
||||||
return new Response(JSON.stringify({ id: "BOT123" }), {
|
postId: "POST1",
|
||||||
status: 200,
|
emojiName: "thumbsup",
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (String(url).endsWith("/api/v4/reactions")) {
|
|
||||||
expect(init?.method).toBe("POST");
|
|
||||||
expect(JSON.parse(init?.body)).toEqual({
|
|
||||||
user_id: "BOT123",
|
|
||||||
post_id: "POST1",
|
|
||||||
emoji_name: "thumbsup",
|
|
||||||
});
|
|
||||||
return new Response(JSON.stringify({ ok: true }), {
|
|
||||||
status: 201,
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
throw new Error(`unexpected url: ${url}`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await addMattermostReaction({
|
const result = await addMattermostReaction({
|
||||||
cfg: createCfg(),
|
cfg: createMattermostTestConfig(),
|
||||||
postId: "POST1",
|
postId: "POST1",
|
||||||
emojiName: "thumbsup",
|
emojiName: "thumbsup",
|
||||||
fetchImpl: fetchMock as unknown as typeof fetch,
|
fetchImpl: fetchMock as unknown as typeof fetch,
|
||||||
@@ -50,24 +33,16 @@ describe("mattermost reactions", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("returns a Result error when add reaction API call fails", async () => {
|
it("returns a Result error when add reaction API call fails", async () => {
|
||||||
const fetchMock = vi.fn(async (url: any) => {
|
const fetchMock = createMattermostReactionFetchMock({
|
||||||
if (String(url).endsWith("/api/v4/users/me")) {
|
mode: "add",
|
||||||
return new Response(JSON.stringify({ id: "BOT123" }), {
|
postId: "POST1",
|
||||||
status: 200,
|
emojiName: "thumbsup",
|
||||||
headers: { "content-type": "application/json" },
|
status: 500,
|
||||||
});
|
body: { id: "err", message: "boom" },
|
||||||
}
|
|
||||||
if (String(url).endsWith("/api/v4/reactions")) {
|
|
||||||
return new Response(JSON.stringify({ id: "err", message: "boom" }), {
|
|
||||||
status: 500,
|
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
throw new Error(`unexpected url: ${url}`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await addMattermostReaction({
|
const result = await addMattermostReaction({
|
||||||
cfg: createCfg(),
|
cfg: createMattermostTestConfig(),
|
||||||
postId: "POST1",
|
postId: "POST1",
|
||||||
emojiName: "thumbsup",
|
emojiName: "thumbsup",
|
||||||
fetchImpl: fetchMock as unknown as typeof fetch,
|
fetchImpl: fetchMock as unknown as typeof fetch,
|
||||||
@@ -80,25 +55,14 @@ describe("mattermost reactions", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("removes reactions by calling /users/me then DELETE /users/:id/posts/:postId/reactions/:emoji", async () => {
|
it("removes reactions by calling /users/me then DELETE /users/:id/posts/:postId/reactions/:emoji", async () => {
|
||||||
const fetchMock = vi.fn(async (url: any, init?: any) => {
|
const fetchMock = createMattermostReactionFetchMock({
|
||||||
if (String(url).endsWith("/api/v4/users/me")) {
|
mode: "remove",
|
||||||
return new Response(JSON.stringify({ id: "BOT123" }), {
|
postId: "POST1",
|
||||||
status: 200,
|
emojiName: "thumbsup",
|
||||||
headers: { "content-type": "application/json" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (String(url).endsWith("/api/v4/users/BOT123/posts/POST1/reactions/thumbsup")) {
|
|
||||||
expect(init?.method).toBe("DELETE");
|
|
||||||
return new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
headers: { "content-type": "text/plain" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
throw new Error(`unexpected url: ${url}`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await removeMattermostReaction({
|
const result = await removeMattermostReaction({
|
||||||
cfg: createCfg(),
|
cfg: createMattermostTestConfig(),
|
||||||
postId: "POST1",
|
postId: "POST1",
|
||||||
emojiName: "thumbsup",
|
emojiName: "thumbsup",
|
||||||
fetchImpl: fetchMock as unknown as typeof fetch,
|
fetchImpl: fetchMock as unknown as typeof fetch,
|
||||||
@@ -107,4 +71,33 @@ describe("mattermost reactions", () => {
|
|||||||
expect(result).toEqual({ ok: true });
|
expect(result).toEqual({ ok: true });
|
||||||
expect(fetchMock).toHaveBeenCalled();
|
expect(fetchMock).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("caches the bot user id across reaction mutations", async () => {
|
||||||
|
const fetchMock = createMattermostReactionFetchMock({
|
||||||
|
mode: "both",
|
||||||
|
postId: "POST1",
|
||||||
|
emojiName: "thumbsup",
|
||||||
|
});
|
||||||
|
|
||||||
|
const cfg = createMattermostTestConfig();
|
||||||
|
const addResult = await addMattermostReaction({
|
||||||
|
cfg,
|
||||||
|
postId: "POST1",
|
||||||
|
emojiName: "thumbsup",
|
||||||
|
fetchImpl: fetchMock as unknown as typeof fetch,
|
||||||
|
});
|
||||||
|
const removeResult = await removeMattermostReaction({
|
||||||
|
cfg,
|
||||||
|
postId: "POST1",
|
||||||
|
emojiName: "thumbsup",
|
||||||
|
fetchImpl: fetchMock as unknown as typeof fetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
const usersMeCalls = fetchMock.mock.calls.filter((call) =>
|
||||||
|
String(call[0]).endsWith("/api/v4/users/me"),
|
||||||
|
);
|
||||||
|
expect(addResult).toEqual({ ok: true });
|
||||||
|
expect(removeResult).toEqual({ ok: true });
|
||||||
|
expect(usersMeCalls).toHaveLength(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,15 @@ import { resolveMattermostAccount } from "./accounts.js";
|
|||||||
import { createMattermostClient, fetchMattermostMe, type MattermostClient } from "./client.js";
|
import { createMattermostClient, fetchMattermostMe, type MattermostClient } from "./client.js";
|
||||||
|
|
||||||
type Result = { ok: true } | { ok: false; error: string };
|
type Result = { ok: true } | { ok: false; error: string };
|
||||||
|
type ReactionParams = {
|
||||||
|
cfg: OpenClawConfig;
|
||||||
|
postId: string;
|
||||||
|
emojiName: string;
|
||||||
|
accountId?: string | null;
|
||||||
|
fetchImpl?: typeof fetch;
|
||||||
|
};
|
||||||
|
type ReactionMutation = (client: MattermostClient, params: MutationPayload) => Promise<void>;
|
||||||
|
type MutationPayload = { userId: string; postId: string; emojiName: string };
|
||||||
|
|
||||||
const BOT_USER_CACHE_TTL_MS = 10 * 60_000;
|
const BOT_USER_CACHE_TTL_MS = 10 * 60_000;
|
||||||
const botUserIdCache = new Map<string, { userId: string; expiresAt: number }>();
|
const botUserIdCache = new Map<string, { userId: string; expiresAt: number }>();
|
||||||
@@ -31,36 +40,10 @@ export async function addMattermostReaction(params: {
|
|||||||
accountId?: string | null;
|
accountId?: string | null;
|
||||||
fetchImpl?: typeof fetch;
|
fetchImpl?: typeof fetch;
|
||||||
}): Promise<Result> {
|
}): Promise<Result> {
|
||||||
const resolved = resolveMattermostAccount({ cfg: params.cfg, accountId: params.accountId });
|
return runMattermostReaction(params, {
|
||||||
const baseUrl = resolved.baseUrl?.trim();
|
action: "add",
|
||||||
const botToken = resolved.botToken?.trim();
|
mutation: createReaction,
|
||||||
if (!baseUrl || !botToken) {
|
|
||||||
return { ok: false, error: "Mattermost botToken/baseUrl missing." };
|
|
||||||
}
|
|
||||||
|
|
||||||
const client = createMattermostClient({
|
|
||||||
baseUrl,
|
|
||||||
botToken,
|
|
||||||
fetchImpl: params.fetchImpl,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const cacheKey = `${baseUrl}:${botToken}`;
|
|
||||||
const userId = await resolveBotUserId(client, cacheKey);
|
|
||||||
if (!userId) {
|
|
||||||
return { ok: false, error: "Mattermost reactions failed: could not resolve bot user id." };
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await createReaction(client, {
|
|
||||||
userId,
|
|
||||||
postId: params.postId,
|
|
||||||
emojiName: params.emojiName,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
return { ok: false, error: `Mattermost add reaction failed: ${String(err)}` };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ok: true };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removeMattermostReaction(params: {
|
export async function removeMattermostReaction(params: {
|
||||||
@@ -70,6 +53,23 @@ export async function removeMattermostReaction(params: {
|
|||||||
accountId?: string | null;
|
accountId?: string | null;
|
||||||
fetchImpl?: typeof fetch;
|
fetchImpl?: typeof fetch;
|
||||||
}): Promise<Result> {
|
}): Promise<Result> {
|
||||||
|
return runMattermostReaction(params, {
|
||||||
|
action: "remove",
|
||||||
|
mutation: deleteReaction,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetMattermostReactionBotUserCacheForTests(): void {
|
||||||
|
botUserIdCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runMattermostReaction(
|
||||||
|
params: ReactionParams,
|
||||||
|
options: {
|
||||||
|
action: "add" | "remove";
|
||||||
|
mutation: ReactionMutation;
|
||||||
|
},
|
||||||
|
): Promise<Result> {
|
||||||
const resolved = resolveMattermostAccount({ cfg: params.cfg, accountId: params.accountId });
|
const resolved = resolveMattermostAccount({ cfg: params.cfg, accountId: params.accountId });
|
||||||
const baseUrl = resolved.baseUrl?.trim();
|
const baseUrl = resolved.baseUrl?.trim();
|
||||||
const botToken = resolved.botToken?.trim();
|
const botToken = resolved.botToken?.trim();
|
||||||
@@ -90,22 +90,19 @@ export async function removeMattermostReaction(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await deleteReaction(client, {
|
await options.mutation(client, {
|
||||||
userId,
|
userId,
|
||||||
postId: params.postId,
|
postId: params.postId,
|
||||||
emojiName: params.emojiName,
|
emojiName: params.emojiName,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return { ok: false, error: `Mattermost remove reaction failed: ${String(err)}` };
|
return { ok: false, error: `Mattermost ${options.action} reaction failed: ${String(err)}` };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createReaction(
|
async function createReaction(client: MattermostClient, params: MutationPayload): Promise<void> {
|
||||||
client: MattermostClient,
|
|
||||||
params: { userId: string; postId: string; emojiName: string },
|
|
||||||
): Promise<void> {
|
|
||||||
await client.request<Record<string, unknown>>("/reactions", {
|
await client.request<Record<string, unknown>>("/reactions", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -116,10 +113,7 @@ async function createReaction(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteReaction(
|
async function deleteReaction(client: MattermostClient, params: MutationPayload): Promise<void> {
|
||||||
client: MattermostClient,
|
|
||||||
params: { userId: string; postId: string; emojiName: string },
|
|
||||||
): Promise<void> {
|
|
||||||
const emoji = encodeURIComponent(params.emojiName);
|
const emoji = encodeURIComponent(params.emojiName);
|
||||||
await client.request<unknown>(
|
await client.request<unknown>(
|
||||||
`/users/${params.userId}/posts/${params.postId}/reactions/${emoji}`,
|
`/users/${params.userId}/posts/${params.postId}/reactions/${emoji}`,
|
||||||
|
|||||||
Reference in New Issue
Block a user