diff --git a/src/activities/tasks/createStandup.ts b/src/activities/tasks/createStandup.ts new file mode 100644 index 0000000..838fdb2 --- /dev/null +++ b/src/activities/tasks/createStandup.ts @@ -0,0 +1,112 @@ +import { PrismaClient } from "@prisma/client"; +import Container from "typedi"; +import { Context } from "../../context"; +import { + SlackEventWithProjects, + SlackMentorInfo, + SlackStudentInfo, + getSlackClientForEvent, + slackEventInfoSelect, +} from "../../slack"; +import { + EventWithStandupAndProsper, + getClientForEvent, +} from "../../standupAndProsper/StandupAndProsper"; +import { makeDebug } from "../../utils"; + +const DEBUG = makeDebug("activities:tasks:createStandup"); +const STANDUP_USER = "U026ZCTG0CB"; + +const DEFAULT_STANDUP = { + admins: ["U024H3101", "U07ACCWHDSA"], + days: ["Monday", "Wednesday", "Friday"], + time: "20:00:00", + reminders: [{ time: "10:00:00" }, { time: "18:00:00" }], + timezone: "America/Los_Angeles", + schedule: { type: "WEEKLY" }, + questions: [ + { text: "What did you do since last standup?" }, + { text: "What will you do until next standup?" }, + { text: "Is anything blocking you?" }, + ], + groupBy: "USER_SINGLE_MESSAGE", + reportSortOrder: "DISPLAY_NAME", + allowEditsAfterCompletion: "EXTENDED", + asThread: false, + syncWithChannel: false, + hideAnnouncements: true, +}; + +export default async function createStandup({ auth }: Context): Promise { + const prisma = Container.get(PrismaClient); + + const event = (await prisma.event.findFirst({ + rejectOnNotFound: true, + where: { + id: auth.eventId, + slackWorkspaceAccessToken: { not: null }, + slackWorkspaceId: { not: null }, + standupAndProsperToken: { not: null }, + }, + select: { + ...slackEventInfoSelect, + projects: { + ...slackEventInfoSelect.projects, + where: { + ...slackEventInfoSelect.projects.where, + standupId: null, + slackChannelId: { not: null }, + students: { + some: { + slackId: { not: null }, + }, + }, + }, + }, + standupAndProsperToken: true, + }, + })) as SlackEventWithProjects & + EventWithStandupAndProsper; + + const client = getClientForEvent(event); + const slack = getSlackClientForEvent(event); + + for (const project of event.projects) { + try { + await slack.conversations.invite({ + channel: project.slackChannelId!, + users: STANDUP_USER, + }); + } catch (ex) {} + + DEBUG(project.students); + const users = project.students + .filter((s) => s.slackId) + .map((s) => ({ userId: s.slackId! })); + + if (users.length === 0) { + DEBUG(`Skipping project ${project.id} — no eligible student Slack IDs`); + continue; + } + + try { + const result = await client.createStandup({ + ...DEFAULT_STANDUP, + channel: project.slackChannelId, + channelId: project.slackChannelId, + users, + }); + if (result.standupId) { + await prisma.project.update({ + where: { id: project.id }, + data: { standupId: result.standupId }, + }); + } + DEBUG( + `Created standup for project ${project.id} in channel ${project.slackChannelId}`, + ); + } catch (ex) { + DEBUG(ex); + } + } +} diff --git a/src/standupAndProsper/StandupAndProsper.ts b/src/standupAndProsper/StandupAndProsper.ts index 4418402..88d05c1 100644 --- a/src/standupAndProsper/StandupAndProsper.ts +++ b/src/standupAndProsper/StandupAndProsper.ts @@ -69,6 +69,26 @@ export class StandupAndPropser { if (!Array.isArray(result.threads)) throw new Error(`Expected array, got ${JSON.stringify(result)}`); return result.threads; } + + async post(path: string, body: object): Promise { + const result = await fetch( + `https://api.standup-and-prosper.com/v1/teams/${this.teamId}${path}`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${this.token}`, + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify(body), + }, + ); + return result.json(); + } + + async createStandup(options: object): Promise { + return this.post('/standups', options); + } } export function getClientForEvent(