1+ import { App } from "@slack/bolt" ;
2+ import { store } from "./storage/fileStore" ;
3+ import { logger } from "./logger" ;
4+ import { StatementResultingChanges } from "node:sqlite" ;
5+
6+ function nowIso ( ) { return new Date ( ) . toISOString ( ) ; }
7+
8+ function ensureUserInState ( userId : string ) {
9+ const s = store . get ( ) ;
10+ if ( ! s . users [ userId ] ) {
11+ s . users [ userId ] = {
12+ id : userId ,
13+ play : false ,
14+ see : false ,
15+ createdAt : nowIso ( ) ,
16+ updatedAt : nowIso ( ) ,
17+ stats : { currentStreak : 0 , longestStreak : 0 } ,
18+ } ;
19+ }
20+ if ( ! s . balances [ userId ] ) {
21+ s . balances [ userId ] = { userId, amount : 0 , updatedAt : nowIso ( ) } ;
22+ }
23+ }
24+
25+ async function setPlay ( userId : string , on : boolean ) {
26+ await store . update ( ( s ) => {
27+ ensureUserInState ( userId ) ;
28+ s . users [ userId ] . play = on ;
29+ s . users [ userId ] . updatedAt = nowIso ( ) ;
30+ } ) ;
31+ }
32+
33+ async function setSee ( userId : string , on : boolean ) {
34+ await store . update ( ( s ) => {
35+ ensureUserInState ( userId ) ;
36+ s . users [ userId ] . see = on ;
37+ s . users [ userId ] . updatedAt = nowIso ( ) ;
38+ } ) ;
39+ }
40+
41+ export function buildSlackApp ( ) {
42+ const app = new App ( {
43+ token : process . env . SLACK_BOT_TOKEN ,
44+ socketMode : true ,
45+ appToken : process . env . SLACK_APP_TOKEN ,
46+ signingSecret : process . env . SLACK_SIGNING_SECRET ,
47+ } ) ;
48+
49+ //add special emoji reaction
50+ app . event ( "reaction_added" , async ( { event, client, logger : boltLogger } ) => {
51+ const ev : any = event ;
52+ try {
53+ if ( ev . reaction !== "siege-coin" ) return ; //change based on reaction name i forgor name
54+ const userId : string = ev . user ;
55+ if ( ! userId || userId === "USLACKBOT" ) return ;
56+
57+ await setPlay ( userId , true ) ;
58+ logger . info ( "Opt-in (PLAY) via :ssiege-coin: reaction" , { userId } ) ;
59+
60+ const channelId : string | undefined = ev . itemn ?. channel ;
61+ if ( channelId ) {
62+ await client . chat . postEphemeral ( {
63+ channel : channelId ,
64+ user : userId ,
65+ text : "Welcome to the gamblers. You can now use commands! Toggle the activity feed with `/see on` or `/see off`. Opt out anytime with `/stopgambeling`." ,
66+ } ) ;
67+ }
68+ } catch ( e : any ) {
69+ boltLogger . error ( e ) ;
70+ }
71+ } ) ;
72+
73+ app . command ( "/see" , async ( { ack, respond, command } ) => {
74+ await ack ( ) ;
75+ const userId = command . user_id ;
76+ const arg = ( command . text || "" ) . trim ( ) . toLowerCase ( ) ;
77+
78+ if ( arg !== "on" && arg !== "off" ) {
79+ await respond ( {
80+ response_type : "ephemeral" ,
81+ text : "Usage: `/see on` or `/see off` "
82+ } ) ;
83+ return ;
84+ }
85+
86+ const on = arg === "on" ;
87+ await setSee ( userId , on ) ;
88+
89+ await respond ( {
90+ response_type : "ephemeral" ,
91+ text : on
92+ ? "👀 Activity feed is now **ON**. You’ll see public game posts."
93+ : "🙈 Activity feed is now **OFF**. You won’t see public game posts."
94+ } ) ;
95+ } ) ;
96+
97+ app . command ( "/stopgambling" , async ( { ack, respond, command } ) => {
98+ await ack ( ) ;
99+ const userId = command . user_id ;
100+ await store . update ( ( s ) => {
101+ ensureUserInState ( userId ) ;
102+ s . users [ userId ] . play = false ;
103+ s . users [ userId ] . see = false ;
104+ s . users [ userId ] . updatedAt = nowIso ( ) ;
105+ } ) ;
106+
107+ await respond ( {
108+ response_type : "ephemeral" ,
109+ text : "🛑 You’re opted out. The bot won’t react to you or show you game activity. Re-opt-in by reacting with :siege-coin: on the intro post."
110+ } ) ;
111+ } ) ;
112+
113+ //because socket is being stupid
114+ app . event ( "app_mention" , async ( { event, say, client} ) => {
115+ const ev = event as any ;
116+ const text = String ( ( event as any ) . text || "" ) . toLowerCase ( ) ;
117+
118+ if ( text . includes ( "hello" ) ) {
119+ await client . chat . postMessage ( {
120+ channel : ev . channel ,
121+ text : `hello <@${ ev . user } >, start gambling RIGHT NOW!` ,
122+ } ) ;
123+ return ;
124+ }
125+
126+ if ( text . includes ( "help" ) ) {
127+ await client . chat . postMessage ( {
128+ channel : ev . channel ,
129+ text : "Hi ! Opt in by reacting with :siege-coin:. Toggle feed with `/see on|off`. Opt out with `/stopgambling`." ,
130+ thread_ts : ev . thread_ts || ev . ts ,
131+ } ) ;
132+ }
133+ } ) ;
134+ return app ;
135+ }
136+
137+ export async function startSlackApp ( app : ReturnType < typeof buildSlackApp > ) {
138+ const port = Number ( process . env . PORT ) || 3000 ;
139+ await app . start ( { port } ) ;
140+ logger . info ( "Slack app runnin (SOCKET)" , { port } ) ;
141+ }
0 commit comments