From 1a1b041c35df94d5164b7b5446b9be079a7ffb98 Mon Sep 17 00:00:00 2001 From: Zach R Date: Mon, 9 Sep 2024 11:01:12 -0700 Subject: [PATCH] fix: improve messages and midnight task scheduling --- eslint.config.js | 4 +-- src/lib/sockets.ts | 7 ---- src/slack/blocks/responses.ts | 2 +- src/tasks/index.ts | 19 ++++++++--- src/tasks/midnight.ts | 63 +++++++++++++++++------------------ 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index dd0e989..fbaee2e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -20,8 +20,8 @@ export default tseslint.config( { argsIgnorePattern: '^_', varsIgnorePattern: '^_', - caughtErrorsIgnorePattern: '^_', - }, + caughtErrorsIgnorePattern: '^_' + } ], 'prefer-const': 'warn', '@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': 'allow-with-description' }] diff --git a/src/lib/sockets.ts b/src/lib/sockets.ts index 6795e6b..a56a898 100644 --- a/src/lib/sockets.ts +++ b/src/lib/sockets.ts @@ -13,13 +13,6 @@ export function startWS(server: HttpServer) { path: '/ws' }) logger.info('Websocket server started') - - io.on('connection', (socket) => { - socket.emit('hello', 'world') - socket.on('hello', (data) => { - socket.broadcast.emit('hello', data) - }) - }) } export function emitCluckChange(data: WSCluckChange) { diff --git a/src/slack/blocks/responses.ts b/src/slack/blocks/responses.ts index bcb0575..2da78e4 100644 --- a/src/slack/blocks/responses.ts +++ b/src/slack/blocks/responses.ts @@ -63,7 +63,7 @@ export default { autoSignoutDM(v: { slack_id: string; time_in: Date }) { return Message() .text( - `Hey <@${v.slack_id}>! You signed into the lab today at ${v.time_in.toLocaleTimeString()} but forgot to sign out, so we didn't log your hours for today :( Make sure you always sign out before you leave. Hope you had fun and excited to see you in the lab again!` + `Hey <@${v.slack_id}>! You signed into the lab today at ${v.time_in.toLocaleTimeString('en-us', { hour: 'numeric', hour12: true, minute: '2-digit' })} but forgot to sign out, so we didn't log your hours for today :( Make sure you always sign out before you leave. Hope you had fun and excited to see you in the lab again!` ) .buildToObject() } diff --git a/src/tasks/index.ts b/src/tasks/index.ts index c2ba69b..d9b1bff 100644 --- a/src/tasks/index.ts +++ b/src/tasks/index.ts @@ -4,16 +4,17 @@ import { syncSlackMembers } from '~tasks/slack' import { announceNewCerts, updateProfileCerts } from '~tasks/certs' import { updateSheet } from '~spreadsheet' import { syncFallbackPhotos } from './photos' -import { setupAutoLogout } from './midnight' +import schedule from 'node-schedule' +import { logoutAll } from './midnight' -type TaskFunc = (reason: string) => Promise +type TaskFunc = ((reason: string) => Promise) & { label: string } type Func = (() => void) | (() => Promise) const tasks: Record = {} function createTaskFunc(task: Func): TaskFunc { const label = 'task/' + task.name - return async (reason: string) => { + const func = async (reason: string) => { try { await task() } catch (e) { @@ -23,6 +24,8 @@ function createTaskFunc(task: Func): TaskFunc { logger.info({ name: label }, 'Task ran successfully') return } + func.label = label + return func } function scheduleTask(task: Func, interval_seconds: number, runOnInit: boolean, offset_seconds: number): TaskFunc { const cb = createTaskFunc(task) @@ -39,6 +42,11 @@ function scheduleTask(task: Func, interval_seconds: number, runOnInit: boolean, return cb } +function scheduleCronTask(task: TaskFunc, cron_exp: string) { + schedule.scheduleJob(task.label, cron_exp, (date) => task('scheduled run')) + return task +} + export function scheduleTasks() { // Offset is to combat Slack's rate limits const isProd = process.env.NODE_ENV === 'prod' @@ -46,11 +54,12 @@ export function scheduleTasks() { tasks['Sync Sheet'] = scheduleTask(updateSheet, 60 * 5, isProd, 0) tasks['Announce Certs'] = scheduleTask(announceNewCerts, 60 * 60, isProd, 60) // Just in case the cert announcement isn't automatically run on changes tasks['Sync Usergroups'] = scheduleTask(updateSlackUsergroups, 60 * 60, isProd, 2 * 60) - tasks['Update Profile Certs'] = scheduleTask(updateProfileCerts, 60 * 60 * 24, isProd, 5 * 60) tasks['Link Fallback Photos'] = createTaskFunc(syncFallbackPhotos) - setupAutoLogout() + tasks['Logout All'] = scheduleCronTask(createTaskFunc(logoutAll), '0 0 * * *') + // Slack is silly and can only handle 5 items in the overflow menu scheduleTask(syncSlackMembers, 60 * 60, isProd, 0) // can be run from the admin members page + scheduleTask(updateProfileCerts, 60 * 60 * 24, isProd, 5 * 60) } export async function runTask(key: string) { diff --git a/src/tasks/midnight.ts b/src/tasks/midnight.ts index 81b888c..bc85eec 100644 --- a/src/tasks/midnight.ts +++ b/src/tasks/midnight.ts @@ -1,42 +1,41 @@ import { Prisma } from '@prisma/client' -import schedule from 'node-schedule' import logger from '~lib/logger' import prisma from '~lib/prisma' +import { emitCluckChange } from '~lib/sockets' import { slack_client } from '~slack' import responses from '~slack/blocks/responses' -export function setupAutoLogout() { - schedule.scheduleJob('Midnight Logout', '0 0 * * *', async (date) => { - const loggedIn = await prisma.hourLog.findMany({ - where: { - state: 'pending', - type: 'lab' - }, - select: { time_in: true, Member: { select: { slack_id: true } } } - }) - for (const log of loggedIn) { - try { - const slack_id = log.Member.slack_id - if (slack_id) { - await slack_client.chat.postMessage({ - ...responses.autoSignoutDM({ slack_id, time_in: log.time_in }), - channel: log.Member.slack_id - }) - } - } catch (e) { - logger.warn(e) +export async function logoutAll() { + const loggedIn = await prisma.hourLog.findMany({ + where: { + state: 'pending', + type: 'lab' + }, + select: { time_in: true, Member: { select: { slack_id: true, email: true } } } + }) + for (const log of loggedIn) { + try { + const slack_id = log.Member.slack_id + emitCluckChange({ email: log.Member.email, logging_in: false }) + if (slack_id) { + await slack_client.chat.postMessage({ + ...responses.autoSignoutDM({ slack_id, time_in: log.time_in }), + channel: slack_id + }) } + } catch (e) { + logger.warn(e) + } + } + await prisma.hourLog.updateMany({ + where: { + state: 'pending', + type: 'lab' + }, + data: { + state: 'cancelled', + time_out: new Date(), + duration: new Prisma.Decimal(0) } - await prisma.hourLog.updateMany({ - where: { - state: 'pending', - type: 'lab' - }, - data: { - state: 'cancelled', - time_out: new Date(), - duration: new Prisma.Decimal(0) - } - }) }) }