Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse slack errors semi-properly #187

Merged
merged 1 commit into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions app/(authenticated)/calendar/[eventID]/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import slackApiConnection, {
} from "@/lib/slack/slackApiConnection";
import { wrapServerAction } from "@/lib/actions";
import { env } from "@/lib/env";
import { parseAndThrowOrIgnoreSlackError } from "@/lib/slack/errors";

export const editEvent = wrapServerAction(
"editEvent",
Expand Down Expand Up @@ -98,18 +99,32 @@ export const updateAttendeeStatus = wrapServerAction(
if (slackUser && evt.slack_channel_id) {
const slackApp = await slackApiConnection();

try {
await slackApp.client.conversations.invite({
channel: evt.slack_channel_id,
users: slackUser.provider_key,
});
} catch (e) {}

await slackApp.client.chat.postEphemeral({
const channel_info = await slackApp.client.conversations.info({
channel: evt.slack_channel_id,
user: slackUser.provider_key,
text: `You have been added to this channel as you expressed your interest in attending '${evt.name}'.`,
});

if (channel_info.ok) {
if (!channel_info.channel?.is_member) {
await slackApp.client.conversations.join({
channel: evt.slack_channel_id,
});
}

try {
await slackApp.client.conversations.invite({
channel: evt.slack_channel_id,
users: slackUser.provider_key,
});
} catch (e) {
parseAndThrowOrIgnoreSlackError(e, "already_in_channel");
}

await slackApp.client.chat.postEphemeral({
channel: evt.slack_channel_id,
user: slackUser.provider_key,
text: `You have been added to this channel as you expressed your interest in attending '${evt.name}'.`,
});
}
}
}
}
Expand Down
20 changes: 14 additions & 6 deletions app/(authenticated)/calendar/[eventID]/signUpSheetActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import slackApiConnection, {
isSlackEnabled,
} from "@/lib/slack/slackApiConnection";
import { wrapServerAction } from "@/lib/actions";
import { CodedError, isCodedError } from "@slack/bolt";
import { parseAndThrowOrIgnoreSlackError } from "@/lib/slack/errors";

export const createSignUpSheet = wrapServerAction(
"createSignUpSheet",
Expand Down Expand Up @@ -190,6 +190,18 @@ export const signUpToRole = wrapServerAction(
if (slackUser && sheet.events.slack_channel_id) {
const slackApp = await slackApiConnection();

const channel_info = await slackApp.client.conversations.info({
channel: sheet.events.slack_channel_id,
});

if (channel_info.ok) {
if (!channel_info.channel?.is_member) {
await slackApp.client.conversations.join({
channel: sheet.events.slack_channel_id,
});
}
}

// Boltjs works weirdly.
// This code will ignore the error thrown if the user is already in the
// channel but throw any others.
Expand All @@ -214,11 +226,7 @@ export const signUpToRole = wrapServerAction(
});
}
} catch (e) {
if (!isCodedError(e)) throw e;

const error = e as CodedError;

if (error.code !== "already_in_channel") throw e;
parseAndThrowOrIgnoreSlackError(e, "already_in_channel");
}
}
}
Expand Down
9 changes: 3 additions & 6 deletions app/(authenticated)/calendar/new/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import * as Calendar from "@/features/calendar";
import { revalidatePath } from "next/cache";
import { env } from "process";
import { schema } from "./schema";
import { App, CodedError, isCodedError } from "@slack/bolt";
import { App } from "@slack/bolt";
import { parseAndThrowOrIgnoreSlackError } from "@/lib/slack/errors";

export const createEvent = wrapServerAction(
"createEvent",
Expand Down Expand Up @@ -106,11 +107,7 @@ export const createEvent = wrapServerAction(
users: slackUser.provider_key,
});
} catch (e) {
if (!isCodedError(e)) throw e;

const error = e as CodedError;

if (error.code !== "already_in_channel") throw error;
parseAndThrowOrIgnoreSlackError(e, "already_in_channel");
}
}
}
Expand Down
50 changes: 50 additions & 0 deletions lib/slack/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { isCodedError } from "@slack/bolt";
import { z } from "zod";

const errorModel = z.object({
code: z.string(),
data: z.object({
ok: z.boolean(),
error: z.string(),
response_metadata: z
.object({
scopes: z.array(z.string()),
})
.optional(),
acceptedScopes: z.array(z.string()).optional(),
}),
});

/**
* If passed a coded slack error, will parse and return it
* @param e Possible slack error
* @returns parsed slack error
*/
export function parseOrThrowSlackError(e: unknown) {
if (!isCodedError(e)) throw e;

const errorParsed = errorModel.safeParse(e);

if (!errorParsed.success) {
throw e;
}

return errorParsed.data;
}

/**
* When passed a coded slack error and an error message to ignore, will parse the error and ignore or throw it depending on the message
* @param e possible slack error
* @param error_to_ignore the error message to ignore from slack
* @returns parsed error that was ignored
*/
export function parseAndThrowOrIgnoreSlackError(
e: unknown,
error_to_ignore: string,
) {
const errorParse = parseOrThrowSlackError(e);

if (errorParse.data.error !== error_to_ignore) throw e;

return errorParse;
}
Loading