11import { App } from "@slack/bolt" ;
2+ import moment from "moment-timezone" ;
23import {
34 processCoffeeChatChannel ,
45 registerCoffeeChatChannel ,
@@ -10,11 +11,40 @@ import {
1011 CoffeeChatUserPreferenceModel ,
1112} from "./coffeeChatModels" ;
1213
14+ /**
15+ * Checks if a user is a workspace admin or owner
16+ */
17+ const isUserAdmin = async (
18+ slackbot : App ,
19+ userId : string ,
20+ ) : Promise < boolean > => {
21+ try {
22+ const userInfo = await slackbot . client . users . info ( { user : userId } ) ;
23+ return (
24+ userInfo . user ?. is_admin ||
25+ userInfo . user ?. is_owner ||
26+ userInfo . user ?. is_primary_owner ||
27+ false
28+ ) ;
29+ } catch {
30+ return false ;
31+ }
32+ } ;
33+
1334export function registerCoffeeChatCommands ( slackbot : App ) {
1435 // Command to register a channel for coffee chats
1536 slackbot . command ( "/register-coffee-chats" , async ( { command, ack, say } ) => {
1637 await ack ( ) ;
1738
39+ // Check if user is admin
40+ const isAdmin = await isUserAdmin ( slackbot , command . user_id ) ;
41+ if ( ! isAdmin ) {
42+ await say (
43+ `❌ Only workspace admins can register channels for coffee chats.` ,
44+ ) ;
45+ return ;
46+ }
47+
1848 try {
1949 const channelId = command . channel_id ;
2050 const channelInfo = await slackbot . client . conversations . info ( {
@@ -37,6 +67,15 @@ export function registerCoffeeChatCommands(slackbot: App) {
3767 slackbot . command ( "/trigger-coffee-chats" , async ( { command, ack, say } ) => {
3868 await ack ( ) ;
3969
70+ // Check if user is admin
71+ const isAdmin = await isUserAdmin ( slackbot , command . user_id ) ;
72+ if ( ! isAdmin ) {
73+ await say (
74+ `❌ Only workspace admins can manually trigger coffee chats.` ,
75+ ) ;
76+ return ;
77+ }
78+
4079 try {
4180 const channelId = command . channel_id ;
4281 const config = await CoffeeChatConfigModel . findOne ( { channelId } ) ;
@@ -58,6 +97,13 @@ export function registerCoffeeChatCommands(slackbot: App) {
5897 slackbot . command ( "/disable-coffee-chats" , async ( { command, ack, say } ) => {
5998 await ack ( ) ;
6099
100+ // Check if user is admin
101+ const isAdmin = await isUserAdmin ( slackbot , command . user_id ) ;
102+ if ( ! isAdmin ) {
103+ await say ( `❌ Only workspace admins can disable coffee chats.` ) ;
104+ return ;
105+ }
106+
61107 try {
62108 const channelId = command . channel_id ;
63109 const result = await CoffeeChatConfigModel . updateOne (
@@ -161,6 +207,13 @@ export function registerCoffeeChatCommands(slackbot: App) {
161207 slackbot . command ( "/reset-coffee-chats" , async ( { command, ack, say } ) => {
162208 await ack ( ) ;
163209
210+ // Check if user is admin
211+ const isAdmin = await isUserAdmin ( slackbot , command . user_id ) ;
212+ if ( ! isAdmin ) {
213+ await say ( `❌ Only workspace admins can reset coffee chats.` ) ;
214+ return ;
215+ }
216+
164217 try {
165218 const channelId = command . channel_id ;
166219
@@ -205,4 +258,102 @@ export function registerCoffeeChatCommands(slackbot: App) {
205258 await say ( `❌ Error resetting coffee chats: ${ error } ` ) ;
206259 }
207260 } ) ;
261+
262+ // Command to view pairing history
263+ slackbot . command ( "/my-coffee-chats" , async ( { command, ack, say } ) => {
264+ await ack ( ) ;
265+
266+ try {
267+ const userId = command . user_id ;
268+ const channelId = command . channel_id ;
269+
270+ // Check if channel is registered for coffee chats
271+ const config = await CoffeeChatConfigModel . findOne ( { channelId } ) ;
272+ if ( ! config ) {
273+ await say ( {
274+ text : `❌ This channel is not registered for coffee chats.` ,
275+ } ) ;
276+ return ;
277+ }
278+
279+ // Find all pairings that include this user in this channel
280+ const pairings = await CoffeeChatPairingModel . find ( {
281+ channelId,
282+ userIds : userId ,
283+ } ) . sort ( { createdAt : - 1 } ) ;
284+
285+ if ( pairings . length === 0 ) {
286+ await say ( {
287+ text : `You haven't been paired with anyone yet in this channel.` ,
288+ blocks : [
289+ {
290+ type : "section" ,
291+ text : {
292+ type : "mrkdwn" ,
293+ text : `☕ You haven't been paired with anyone yet in this channel. Stay tuned for your first coffee chat!` ,
294+ } ,
295+ } ,
296+ ] ,
297+ } ) ;
298+ return ;
299+ }
300+
301+ // Build the history message
302+ const historyLines : string [ ] = [ ] ;
303+
304+ for ( const pairing of pairings ) {
305+ const partners = pairing . userIds
306+ . filter ( ( id ) => id !== userId )
307+ . map ( ( id ) => `<@${ id } >` )
308+ . join ( ", " ) ;
309+
310+ const date = moment ( pairing . createdAt )
311+ . tz ( "America/New_York" )
312+ . format ( "MMM D, YYYY" ) ;
313+
314+ let status = "" ;
315+ if ( pairing . isActive ) {
316+ status = "🟢 Active" ;
317+ } else if ( pairing . meetupConfirmed ) {
318+ status = "✅ Met" ;
319+ } else {
320+ status = "❌ Did not meet" ;
321+ }
322+
323+ historyLines . push ( `• ${ date } - ${ partners } ${ status } ` ) ;
324+ }
325+
326+ await say ( {
327+ text : `Your coffee chat history` ,
328+ blocks : [
329+ {
330+ type : "header" ,
331+ text : {
332+ type : "plain_text" ,
333+ text : "☕ Your Coffee Chat History" ,
334+ emoji : true ,
335+ } ,
336+ } ,
337+ {
338+ type : "section" ,
339+ text : {
340+ type : "mrkdwn" ,
341+ text : `You've been paired *${ pairings . length } time${ pairings . length !== 1 ? "s" : "" } * in this channel:\n\n${ historyLines . join ( "\n" ) } ` ,
342+ } ,
343+ } ,
344+ {
345+ type : "context" ,
346+ elements : [
347+ {
348+ type : "mrkdwn" ,
349+ text : "🟢 Active pairing • ✅ Met • ❌ Did not meet" ,
350+ } ,
351+ ] ,
352+ } ,
353+ ] ,
354+ } ) ;
355+ } catch ( error ) {
356+ await say ( `❌ Error retrieving pairing history: ${ error } ` ) ;
357+ }
358+ } ) ;
208359}
0 commit comments