diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 0b35b25..634cd6b 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -2,7 +2,7 @@ name: PR checks on: pull_request: - types: [opened, synchronize] + types: [opened, synchronize, reopened] branches: [main] jobs: diff --git a/package.json b/package.json index edc4d87..59955d7 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "mockdate": "^3.0.5", "pg": "^8.11.3", "prettier": "^3.0.3", - "tsx": "^3.14.0", + "tsx": "^4.6.2", "typescript": "^5.2.2", "vite": "^4.5.0", "vitest": "^0.34.6" diff --git a/packages/core/db/queries/deleteBirthdayInputs.ts b/packages/core/db/queries/deleteBirthdayInputs.ts index 8c9bcb4..d7e2b14 100644 --- a/packages/core/db/queries/deleteBirthdayInputs.ts +++ b/packages/core/db/queries/deleteBirthdayInputs.ts @@ -4,6 +4,8 @@ import { db } from "@/db/index"; import { iceBreakerThreads, presentIdeas, squadJoins } from "@/db/schema"; export const deleteBirthdayInputs = async (teamId: string, userId: string) => { + console.log("Deleting birthday inputs", teamId, userId); + await db.transaction(async (tx) => { await tx .delete(iceBreakerThreads) @@ -32,4 +34,6 @@ export const deleteBirthdayInputs = async (teamId: string, userId: string) => { ), ); }); + + console.log("Birthday inputs deleted", teamId, userId); }; diff --git a/packages/core/db/queries/deleteUser.ts b/packages/core/db/queries/deleteUser.ts index 9b03eef..5c075eb 100644 --- a/packages/core/db/queries/deleteUser.ts +++ b/packages/core/db/queries/deleteUser.ts @@ -4,7 +4,11 @@ import { db } from "@/db/index"; import { users } from "@/db/schema"; export const deleteUser = async (userId: string, teamId: string) => { + console.log("Deleting user", userId, teamId); + await db .delete(users) .where(and(eq(users.id, userId), eq(users.teamId, teamId))); + + console.log("User deleted", userId, teamId); }; diff --git a/packages/core/db/queries/saveBirthday.ts b/packages/core/db/queries/saveBirthday.ts index 475a4b2..8092cd2 100644 --- a/packages/core/db/queries/saveBirthday.ts +++ b/packages/core/db/queries/saveBirthday.ts @@ -13,6 +13,8 @@ type Arguments = { }; export const saveBirthday = async ({ birthday, teamId, user }: Arguments) => { + console.log("Saving birthday", user, birthday, teamId); + const birthdayDate = birthday ? dayjs.utc(birthday).toDate() : null; await db @@ -28,4 +30,6 @@ export const saveBirthday = async ({ birthday, teamId, user }: Arguments) => { birthday: birthdayDate, }, }); + + console.log("Birthday saved", user, birthday, teamId); }; diff --git a/packages/core/db/queries/savePresentIdea.ts b/packages/core/db/queries/savePresentIdea.ts index d5de623..9a4e107 100644 --- a/packages/core/db/queries/savePresentIdea.ts +++ b/packages/core/db/queries/savePresentIdea.ts @@ -3,5 +3,9 @@ import type { PresentIdea } from "@/db/schema"; import { presentIdeas } from "@/db/schema"; export const savePresentIdea = async (presentIdea: PresentIdea) => { + console.log("Saving present idea", presentIdea); + await db.insert(presentIdeas).values(presentIdea); + + console.log("Present idea saved", presentIdea); }; diff --git a/packages/core/db/queries/saveSquadJoin.ts b/packages/core/db/queries/saveSquadJoin.ts index 5c60454..52cec99 100644 --- a/packages/core/db/queries/saveSquadJoin.ts +++ b/packages/core/db/queries/saveSquadJoin.ts @@ -3,5 +3,9 @@ import type { SquadJoin } from "@/db/schema"; import { squadJoins } from "@/db/schema"; export const saveSquadJoin = async (squadJoin: SquadJoin) => { + console.log("Saving squad join", squadJoin); + await db.insert(squadJoins).values(squadJoin); + + console.log("Squad join saved", squadJoin); }; diff --git a/packages/core/types/events/index.ts b/packages/core/types/events/index.ts index 4c13b89..da045fe 100644 --- a/packages/core/types/events/index.ts +++ b/packages/core/types/events/index.ts @@ -76,3 +76,8 @@ export type Events = z.infer; export type EventType = keyof Events; export const eventTypes = Object.keys(Events.shape) as EventType[]; + +export type EventPayload = { + type: T; + payload: Events[T]; +}; diff --git a/packages/functions/lambdas/slack-interaction.ts b/packages/functions/lambdas/slack-interaction.ts index 8df94ac..3a634c5 100644 --- a/packages/functions/lambdas/slack-interaction.ts +++ b/packages/functions/lambdas/slack-interaction.ts @@ -1,7 +1,9 @@ import type { APIGatewayProxyHandlerV2 } from "aws-lambda"; +import type { EventPayload, EventType } from "@/events"; import { constructLoadingMessage } from "@/services/slack/constructLoadingMessage"; import { sendResponse } from "@/services/slack/sendResponse"; +import type { SlackInteractionRequest } from "@/types/SlackInteractionRequest"; import { additionalPresentIdeasInputActionId, additionalPresentIdeasInputBlockId, @@ -20,86 +22,122 @@ import { publishEvent } from "@/utils/eventBridge/publishEvent"; import { parseRequest } from "@/utils/lambda/parseRequest"; import { errorResult, okResult } from "@/utils/lambda/result"; -export const handler: APIGatewayProxyHandlerV2 = async (request) => { - try { - const payload = parseRequest(request); +const getEventPayload = ( + request: SlackInteractionRequest, +): EventPayload | EventPayload[] | null => { + switch (request.actions[0].action_id) { + case pickBirthdayActionId: + return { + type: "birthdayFilled", + payload: { + birthday: request.actions[0].selected_date, + responseUrl: request.response_url, + }, + }; + case birthdayConfirmActionId: + return { + type: "birthdayConfirmed", + payload: { + user: request.user.id, + team: request.user.team_id, + birthday: request.actions[0].value, + responseUrl: request.response_url, + }, + }; + case birthdayIncorrectActionId: + return { + type: "askBirthday", + payload: { + user: request.user.id, + responseUrl: request.response_url, + }, + }; + case presentIdeasSaveButtonActionId: { + const presentIdea = + request.state?.values?.[presentIdeasInputBlockId]?.[ + presentIdeasInputActionId + ]?.value; - const parsedData = SlackInteractionRequestSchema.parse(payload); + if (!presentIdea) { + throw new Error("Present idea is empty"); + } - switch (parsedData.actions[0].action_id) { - case pickBirthdayActionId: - await publishEvent("birthdayFilled", { - birthday: parsedData.actions[0].selected_date, - responseUrl: parsedData.response_url, - }); - break; - case birthdayConfirmActionId: - await publishEvent("birthdayConfirmed", { - user: parsedData.user.id, - team: parsedData.user.team_id, - birthday: parsedData.actions[0].value, - responseUrl: parsedData.response_url, - }); - break; - case birthdayIncorrectActionId: - await publishEvent("askBirthday", { - user: parsedData.user.id, - responseUrl: parsedData.response_url, - }); - break; - case presentIdeasSaveButtonActionId: { - const presentIdea = - parsedData.state?.values?.[presentIdeasInputBlockId]?.[ - presentIdeasInputActionId - ]?.value; - - if (!presentIdea) { - throw new Error("Present idea is empty"); - } - await publishEvent("savePresentIdea", { - birthdayPerson: parsedData.actions[0].value, - user: parsedData.user.id, - team: parsedData.user.team_id, + return { + type: "savePresentIdea", + payload: { + birthdayPerson: request.actions[0].value, + user: request.user.id, + team: request.user.team_id, presentIdea, - responseUrl: parsedData.response_url, - }); - break; + responseUrl: request.response_url, + }, + }; + } + case additionalPresentIdeasSaveButtonActionId: { + const presentIdea = + request.state?.values?.[additionalPresentIdeasInputBlockId]?.[ + additionalPresentIdeasInputActionId + ]?.value; + const squadJoin = + !!request.state?.values?.[squadJoinCheckboxBlockId]?.[ + squadJoinCheckboxActionId + ]?.selected_options?.length; + + if (!presentIdea) { + throw new Error("Additional Present idea is empty"); } - case additionalPresentIdeasSaveButtonActionId: { - const presentIdea = - parsedData.state?.values?.[additionalPresentIdeasInputBlockId]?.[ - additionalPresentIdeasInputActionId - ]?.value; - const squadJoin = - !!parsedData.state?.values?.[squadJoinCheckboxBlockId]?.[ - squadJoinCheckboxActionId - ]?.selected_options?.length; - - if (!presentIdea) { - throw new Error("Additional Present idea is empty"); - } - if (squadJoin) { - await publishEvent("saveSquadJoin", { - birthdayPerson: parsedData.actions[0].value, - user: parsedData.user.id, - team: parsedData.user.team_id, - }); - } - await publishEvent("savePresentIdea", { - birthdayPerson: parsedData.actions[0].value, - user: parsedData.user.id, - team: parsedData.user.team_id, - presentIdea, - responseUrl: parsedData.response_url, + + const events: EventPayload[] = [ + { + type: "savePresentIdea", + payload: { + birthdayPerson: request.actions[0].value, + user: request.user.id, + team: request.user.team_id, + presentIdea, + responseUrl: request.response_url, + }, + }, + ]; + + if (squadJoin) { + events.push({ + type: "saveSquadJoin", + payload: { + birthdayPerson: request.actions[0].value, + user: request.user.id, + team: request.user.team_id, + }, }); - break; } - default: - return okResult(); + + return events; + } + default: + return null; + } +}; + +export const handler: APIGatewayProxyHandlerV2 = async (request) => { + try { + const payload = parseRequest(request); + + const parsedData = SlackInteractionRequestSchema.parse(payload); + + const event = getEventPayload(parsedData); + + if (!event) { + return okResult(); } await sendResponse(parsedData.response_url, constructLoadingMessage()); + if (Array.isArray(event)) { + await Promise.all(event.map((e) => publishEvent(e.type, e.payload))); + } else { + await publishEvent(event.type, event.payload); + } + return okResult(); } catch (error) { console.error(`Error handling slack interaction: ${error}`); diff --git a/packages/functions/utils/eventBridge/publishEvent.ts b/packages/functions/utils/eventBridge/publishEvent.ts index 57629e7..2679886 100644 --- a/packages/functions/utils/eventBridge/publishEvent.ts +++ b/packages/functions/utils/eventBridge/publishEvent.ts @@ -12,6 +12,8 @@ export const publishEvent = async ( payload: Events[T], ) => { try { + console.log("Publishing event", event, payload); + await client.send( new PutEventsCommand({ Entries: [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01135ae..0b8864e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -88,8 +88,8 @@ importers: specifier: ^3.0.3 version: 3.0.3 tsx: - specifier: ^3.14.0 - version: 3.14.0 + specifier: ^4.6.2 + version: 4.6.2 typescript: specifier: ^5.2.2 version: 5.2.2 @@ -8367,13 +8367,13 @@ packages: resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} engines: {node: '>=0.6.x'} - /tsx@3.14.0: - resolution: {integrity: sha512-xHtFaKtHxM9LOklMmJdI3BEnQq/D5F73Of2E1GDrITi9sgoVkvIsrQUTY1G8FlmGtA+awCI4EBlTRRYxkL2sRg==} + /tsx@4.6.2: + resolution: {integrity: sha512-QPpBdJo+ZDtqZgAnq86iY/PD2KYCUPSUGIunHdGwyII99GKH+f3z3FZ8XNFLSGQIA4I365ui8wnQpl8OKLqcsg==} + engines: {node: '>=18.0.0'} hasBin: true dependencies: esbuild: 0.18.20 get-tsconfig: 4.7.2 - source-map-support: 0.5.21 optionalDependencies: fsevents: 2.3.3 dev: true