a fun bot for the hc slack
at v0.0.3 5.7 kB view raw
1import { slackApp } from "../../../index"; 2import TakesConfig from "../../../libs/config"; 3import { db } from "../../../libs/db"; 4import { takes as takesTable } from "../../../libs/schema"; 5import { eq } from "drizzle-orm"; 6import { 7 calculateElapsedTime, 8 getPausedDuration, 9 getRemainingTime, 10} from "../../../libs/time-periods"; 11import { prettyPrintTime } from "../../../libs/time"; 12 13// Check for paused sessions that have exceeded the max pause duration 14export async function expirePausedSessions() { 15 const now = new Date(); 16 const pausedTakes = await db 17 .select() 18 .from(takesTable) 19 .where(eq(takesTable.status, "paused")); 20 21 for (const take of pausedTakes) { 22 const pausedDuration = getPausedDuration(take.periods) / 60000; // Convert to minutes 23 24 // Send warning notification when getting close to expiration 25 if ( 26 pausedDuration > 27 TakesConfig.MAX_PAUSE_DURATION - 28 TakesConfig.NOTIFICATIONS.PAUSE_EXPIRATION_WARNING && 29 !take.notifiedPauseExpiration 30 ) { 31 // Update notification flag 32 await db 33 .update(takesTable) 34 .set({ 35 notifiedPauseExpiration: true, 36 }) 37 .where(eq(takesTable.id, take.id)); 38 39 // Send warning message 40 try { 41 const timeRemaining = Math.round( 42 TakesConfig.MAX_PAUSE_DURATION - pausedDuration, 43 ); 44 await slackApp.client.chat.postMessage({ 45 channel: take.userId, 46 text: `⚠️ Reminder: Your paused takes session will automatically complete in about ${timeRemaining} minutes if not resumed.`, 47 }); 48 } catch (error) { 49 console.error( 50 "Failed to send pause expiration warning:", 51 error, 52 ); 53 } 54 } 55 56 // Calculate elapsed time 57 const elapsedTime = calculateElapsedTime(JSON.parse(take.periods)); 58 59 // Auto-expire paused sessions that exceed the max pause duration 60 if (pausedDuration > TakesConfig.MAX_PAUSE_DURATION) { 61 let ts: string | undefined; 62 // Notify user that their session was auto-completed 63 try { 64 const res = await slackApp.client.chat.postMessage({ 65 channel: take.userId, 66 text: `⏰ Your paused takes session has been automatically completed because it was paused for more than ${TakesConfig.MAX_PAUSE_DURATION} minutes.\n\nPlease upload your takes video in this thread within the next 24 hours!`, 67 blocks: [ 68 { 69 type: "section", 70 text: { 71 type: "mrkdwn", 72 text: `⏰ Your paused takes session has been automatically completed because it was paused for more than ${TakesConfig.MAX_PAUSE_DURATION} minutes.\n\nPlease upload your takes video in this thread within the next 24 hours!`, 73 }, 74 }, 75 { 76 type: "divider", 77 }, 78 { 79 type: "context", 80 elements: [ 81 { 82 type: "mrkdwn", 83 text: `\`${prettyPrintTime(elapsedTime)}\`${take.description ? ` working on: *${take.description}*` : ""}`, 84 }, 85 ], 86 }, 87 ], 88 }); 89 ts = res.ts; 90 } catch (error) { 91 console.error( 92 "Failed to notify user of auto-completed session:", 93 error, 94 ); 95 } 96 97 await db 98 .update(takesTable) 99 .set({ 100 status: "waitingUpload", 101 completedAt: now, 102 elapsedTimeMs: elapsedTime, 103 ts, 104 notes: take.notes 105 ? `${take.notes} (Automatically completed due to pause timeout)` 106 : "Automatically completed due to pause timeout", 107 }) 108 .where(eq(takesTable.id, take.id)); 109 } 110 } 111} 112 113// Check for active sessions that are almost done 114export async function checkActiveSessions() { 115 const now = new Date(); 116 const activeTakes = await db 117 .select() 118 .from(takesTable) 119 .where(eq(takesTable.status, "active")); 120 121 for (const take of activeTakes) { 122 const endTime = getRemainingTime(take.targetDurationMs, take.periods); 123 124 const remainingMinutes = endTime.remaining / 60000; 125 126 if ( 127 remainingMinutes <= TakesConfig.NOTIFICATIONS.LOW_TIME_WARNING && 128 remainingMinutes > 0 && 129 !take.notifiedLowTime 130 ) { 131 await db 132 .update(takesTable) 133 .set({ notifiedLowTime: true }) 134 .where(eq(takesTable.id, take.id)); 135 136 try { 137 await slackApp.client.chat.postMessage({ 138 channel: take.userId, 139 text: `⏱️ Your takes session has less than ${TakesConfig.NOTIFICATIONS.LOW_TIME_WARNING} minutes remaining.`, 140 }); 141 } catch (error) { 142 console.error("Failed to send low time warning:", error); 143 } 144 } 145 146 const elapsedTime = calculateElapsedTime(JSON.parse(take.periods)); 147 148 if (endTime.remaining <= 0) { 149 let ts: string | undefined; 150 try { 151 const res = await slackApp.client.chat.postMessage({ 152 channel: take.userId, 153 text: "⏰ Your takes session has automatically completed because the time is up. Please upload your takes video in this thread within the next 24 hours!", 154 blocks: [ 155 { 156 type: "section", 157 text: { 158 type: "mrkdwn", 159 text: "⏰ Your takes session has automatically completed because the time is up. Please upload your takes video in this thread within the next 24 hours!", 160 }, 161 }, 162 { 163 type: "divider", 164 }, 165 { 166 type: "context", 167 elements: [ 168 { 169 type: "mrkdwn", 170 text: `\`${prettyPrintTime(elapsedTime)}\`${take.description ? ` working on: *${take.description}*` : ""}`, 171 }, 172 ], 173 }, 174 ], 175 }); 176 177 ts = res.ts; 178 } catch (error) { 179 console.error( 180 "Failed to notify user of completed session:", 181 error, 182 ); 183 } 184 185 await db 186 .update(takesTable) 187 .set({ 188 status: "waitingUpload", 189 completedAt: now, 190 elapsedTimeMs: elapsedTime, 191 ts, 192 notes: take.notes 193 ? `${take.notes} (Automatically completed - time expired)` 194 : "Automatically completed - time expired", 195 }) 196 .where(eq(takesTable.id, take.id)); 197 } 198 } 199}