subscribe update
This commit is contained in:
@@ -28,6 +28,27 @@ const commands = [
|
|||||||
option.setName('game')
|
option.setName('game')
|
||||||
.setDescription('Filter by game')
|
.setDescription('Filter by game')
|
||||||
.setRequired(false)),
|
.setRequired(false)),
|
||||||
|
new SlashCommandBuilder()
|
||||||
|
.setName('subscribe')
|
||||||
|
.setDescription('Subscribe to notifications for a game')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('game')
|
||||||
|
.setDescription('The game to subscribe to')
|
||||||
|
.setRequired(true))
|
||||||
|
.addChannelOption(option =>
|
||||||
|
option.setName('channel')
|
||||||
|
.setDescription('The channel to receive notifications (default: current channel)')
|
||||||
|
.setRequired(false)),
|
||||||
|
new SlashCommandBuilder()
|
||||||
|
.setName('unsubscribe')
|
||||||
|
.setDescription('Unsubscribe from notifications for a game')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('game')
|
||||||
|
.setDescription('The game to unsubscribe from')
|
||||||
|
.setRequired(true)),
|
||||||
|
new SlashCommandBuilder()
|
||||||
|
.setName('listsubscriptions')
|
||||||
|
.setDescription('List all active subscriptions for this server'),
|
||||||
];
|
];
|
||||||
|
|
||||||
const rest = new REST({ version: '10' }).setToken(process.env.BOT_TOKEN);
|
const rest = new REST({ version: '10' }).setToken(process.env.BOT_TOKEN);
|
||||||
|
|||||||
102
node_modules/.package-lock.json
generated
vendored
102
node_modules/.package-lock.json
generated
vendored
@@ -170,6 +170,80 @@
|
|||||||
"npm": ">=7.0.0"
|
"npm": ">=7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@supabase/auth-js": {
|
||||||
|
"version": "2.65.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.65.1.tgz",
|
||||||
|
"integrity": "sha512-IA7i2Xq2SWNCNMKxwmPlHafBQda0qtnFr8QnyyBr+KaSxoXXqEzFCnQ1dGTy6bsZjVBgXu++o3qrDypTspaAPw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/node-fetch": "^2.6.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/functions-js": {
|
||||||
|
"version": "2.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.4.3.tgz",
|
||||||
|
"integrity": "sha512-sOLXy+mWRyu4LLv1onYydq+10mNRQ4rzqQxNhbrKLTLTcdcmS9hbWif0bGz/NavmiQfPs4ZcmQJp4WqOXlR4AQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/node-fetch": "^2.6.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/node-fetch": {
|
||||||
|
"version": "2.6.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz",
|
||||||
|
"integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-url": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "4.x || >=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/postgrest-js": {
|
||||||
|
"version": "1.16.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.16.3.tgz",
|
||||||
|
"integrity": "sha512-HI6dsbW68AKlOPofUjDTaosiDBCtW4XAm0D18pPwxoW3zKOE2Ru13Z69Wuys9fd6iTpfDViNco5sgrtnP0666A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/node-fetch": "^2.6.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/realtime-js": {
|
||||||
|
"version": "2.10.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.10.7.tgz",
|
||||||
|
"integrity": "sha512-OLI0hiSAqQSqRpGMTUwoIWo51eUivSYlaNBgxsXZE7PSoWh12wPRdVt0psUMaUzEonSB85K21wGc7W5jHnT6uA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/node-fetch": "^2.6.14",
|
||||||
|
"@types/phoenix": "^1.5.4",
|
||||||
|
"@types/ws": "^8.5.10",
|
||||||
|
"ws": "^8.14.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/storage-js": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/node-fetch": "^2.6.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/supabase-js": {
|
||||||
|
"version": "2.46.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.46.1.tgz",
|
||||||
|
"integrity": "sha512-HiBpd8stf7M6+tlr+/82L8b2QmCjAD8ex9YdSAKU+whB/SHXXJdus1dGlqiH9Umy9ePUuxaYmVkGd9BcvBnNvg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/auth-js": "2.65.1",
|
||||||
|
"@supabase/functions-js": "2.4.3",
|
||||||
|
"@supabase/node-fetch": "2.6.15",
|
||||||
|
"@supabase/postgrest-js": "1.16.3",
|
||||||
|
"@supabase/realtime-js": "2.10.7",
|
||||||
|
"@supabase/storage-js": "2.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.5.5",
|
"version": "22.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
|
||||||
@@ -179,6 +253,12 @@
|
|||||||
"undici-types": "~6.19.2"
|
"undici-types": "~6.19.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/phoenix": {
|
||||||
|
"version": "1.6.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.5.tgz",
|
||||||
|
"integrity": "sha512-xegpDuR+z0UqG9fwHqNoy3rI7JDlvaPh2TY47Fl80oq6g+hXT+c/LEuE43X48clZ6lOfANl5WrPur9fYO1RJ/w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/ws": {
|
"node_modules/@types/ws": {
|
||||||
"version": "8.5.12",
|
"version": "8.5.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz",
|
||||||
@@ -1061,6 +1141,12 @@
|
|||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tr46": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ts-mixer": {
|
"node_modules/ts-mixer": {
|
||||||
"version": "6.0.4",
|
"version": "6.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz",
|
||||||
@@ -1128,6 +1214,22 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webidl-conversions": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-url": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "~0.0.3",
|
||||||
|
"webidl-conversions": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.18.0",
|
"version": "8.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
||||||
|
|||||||
103
package-lock.json
generated
103
package-lock.json
generated
@@ -9,6 +9,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@supabase/supabase-js": "^2.46.1",
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
"discord.js": "^14.16.2",
|
"discord.js": "^14.16.2",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
@@ -182,6 +183,80 @@
|
|||||||
"npm": ">=7.0.0"
|
"npm": ">=7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@supabase/auth-js": {
|
||||||
|
"version": "2.65.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.65.1.tgz",
|
||||||
|
"integrity": "sha512-IA7i2Xq2SWNCNMKxwmPlHafBQda0qtnFr8QnyyBr+KaSxoXXqEzFCnQ1dGTy6bsZjVBgXu++o3qrDypTspaAPw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/node-fetch": "^2.6.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/functions-js": {
|
||||||
|
"version": "2.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.4.3.tgz",
|
||||||
|
"integrity": "sha512-sOLXy+mWRyu4LLv1onYydq+10mNRQ4rzqQxNhbrKLTLTcdcmS9hbWif0bGz/NavmiQfPs4ZcmQJp4WqOXlR4AQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/node-fetch": "^2.6.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/node-fetch": {
|
||||||
|
"version": "2.6.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz",
|
||||||
|
"integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-url": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "4.x || >=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/postgrest-js": {
|
||||||
|
"version": "1.16.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.16.3.tgz",
|
||||||
|
"integrity": "sha512-HI6dsbW68AKlOPofUjDTaosiDBCtW4XAm0D18pPwxoW3zKOE2Ru13Z69Wuys9fd6iTpfDViNco5sgrtnP0666A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/node-fetch": "^2.6.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/realtime-js": {
|
||||||
|
"version": "2.10.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.10.7.tgz",
|
||||||
|
"integrity": "sha512-OLI0hiSAqQSqRpGMTUwoIWo51eUivSYlaNBgxsXZE7PSoWh12wPRdVt0psUMaUzEonSB85K21wGc7W5jHnT6uA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/node-fetch": "^2.6.14",
|
||||||
|
"@types/phoenix": "^1.5.4",
|
||||||
|
"@types/ws": "^8.5.10",
|
||||||
|
"ws": "^8.14.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/storage-js": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/node-fetch": "^2.6.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@supabase/supabase-js": {
|
||||||
|
"version": "2.46.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.46.1.tgz",
|
||||||
|
"integrity": "sha512-HiBpd8stf7M6+tlr+/82L8b2QmCjAD8ex9YdSAKU+whB/SHXXJdus1dGlqiH9Umy9ePUuxaYmVkGd9BcvBnNvg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@supabase/auth-js": "2.65.1",
|
||||||
|
"@supabase/functions-js": "2.4.3",
|
||||||
|
"@supabase/node-fetch": "2.6.15",
|
||||||
|
"@supabase/postgrest-js": "1.16.3",
|
||||||
|
"@supabase/realtime-js": "2.10.7",
|
||||||
|
"@supabase/storage-js": "2.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.5.5",
|
"version": "22.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
|
||||||
@@ -191,6 +266,12 @@
|
|||||||
"undici-types": "~6.19.2"
|
"undici-types": "~6.19.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/phoenix": {
|
||||||
|
"version": "1.6.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.5.tgz",
|
||||||
|
"integrity": "sha512-xegpDuR+z0UqG9fwHqNoy3rI7JDlvaPh2TY47Fl80oq6g+hXT+c/LEuE43X48clZ6lOfANl5WrPur9fYO1RJ/w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/ws": {
|
"node_modules/@types/ws": {
|
||||||
"version": "8.5.12",
|
"version": "8.5.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz",
|
||||||
@@ -1073,6 +1154,12 @@
|
|||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tr46": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ts-mixer": {
|
"node_modules/ts-mixer": {
|
||||||
"version": "6.0.4",
|
"version": "6.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz",
|
||||||
@@ -1140,6 +1227,22 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webidl-conversions": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-url": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "~0.0.3",
|
||||||
|
"webidl-conversions": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.18.0",
|
"version": "8.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
||||||
|
|||||||
@@ -4,16 +4,14 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
|
||||||
"test:webhook": "NODE_ENV=test node src/test/testWebhook.js"
|
"test:webhook": "NODE_ENV=test node src/test/testWebhook.js"
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@supabase/supabase-js": "^2.46.1",
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
"discord.js": "^14.16.2",
|
"discord.js": "^14.16.2",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
|
|||||||
121
src/Bot.js
121
src/Bot.js
@@ -1,8 +1,10 @@
|
|||||||
const { Client, GatewayIntentBits } = require('discord.js');
|
const { Client, GatewayIntentBits } = require("discord.js");
|
||||||
const CommandHandler = require('./commands/CommandHandler.js');
|
const CommandHandler = require("./commands/CommandHandler.js");
|
||||||
const PlayerService = require('./services/PlayerService.js');
|
const PlayerService = require("./services/PlayerService.js");
|
||||||
const NotificationService = require('./services/NotificationService.js');
|
const NotificationService = require("./services/NotificationService.js");
|
||||||
const MatchCommands = require('./commands/MatchCommands.js');
|
const MatchCommands = require("./commands/MatchCommands.js");
|
||||||
|
const SupabaseService = require("./services/SupabaseService.js");
|
||||||
|
const SubscriptionCommands = require("./commands/SubscriptionCommands.js");
|
||||||
|
|
||||||
class Bot {
|
class Bot {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -13,12 +15,20 @@ class Bot {
|
|||||||
GatewayIntentBits.MessageContent,
|
GatewayIntentBits.MessageContent,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.playerService = new PlayerService();
|
this.playerService = new PlayerService();
|
||||||
this.commandHandler = new CommandHandler(this.playerService);
|
this.commandHandler = new CommandHandler(this.playerService);
|
||||||
this.matchCommands = new MatchCommands(this.playerService);
|
this.matchCommands = new MatchCommands(this.playerService);
|
||||||
this.notificationService = new NotificationService(this);
|
this.notificationService = new NotificationService(this);
|
||||||
|
|
||||||
|
this.supabaseService = new SupabaseService();
|
||||||
|
if (this.supabaseService.supabase) {
|
||||||
|
this.subscriptionCommands = new SubscriptionCommands(this.supabaseService);
|
||||||
|
} else {
|
||||||
|
console.warn('SupabaseService not initialized. Subscription commands will be unavailable.');
|
||||||
|
this.subscriptionCommands = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.setupEventHandlers();
|
this.setupEventHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,35 +39,35 @@ class Bot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start(token) {
|
async start(token) {
|
||||||
console.log('Starting bot...');
|
console.log("Starting bot...");
|
||||||
try {
|
try {
|
||||||
await this.client.login(token);
|
await this.client.login(token);
|
||||||
console.log('Login successful');
|
console.log("Login successful");
|
||||||
|
|
||||||
// Start notification service after bot is logged in
|
// Start notification service after bot is logged in
|
||||||
const port = process.env.NOTIFICATION_PORT || 3000;
|
const port = process.env.NOTIFICATION_PORT || 3000;
|
||||||
await this.notificationService.start(port);
|
await this.notificationService.start(port);
|
||||||
console.log(`Notification service started on port ${port}`);
|
console.log(`Notification service started on port ${port}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Startup failed:', error);
|
console.error("Startup failed:", error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async stop() {
|
async stop() {
|
||||||
console.log('Stopping bot...');
|
console.log("Stopping bot...");
|
||||||
try {
|
try {
|
||||||
await this.notificationService.stop();
|
await this.notificationService.stop();
|
||||||
await this.client.destroy();
|
await this.client.destroy();
|
||||||
console.log('Bot stopped successfully');
|
console.log("Bot stopped successfully");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error stopping bot:', error);
|
console.error("Error stopping bot:", error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleError(error) {
|
handleError(error) {
|
||||||
console.error('Discord client error:', error);
|
console.error("Discord client error:", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReady() {
|
handleReady() {
|
||||||
@@ -72,94 +82,115 @@ class Bot {
|
|||||||
await this.handleButton(interaction);
|
await this.handleButton(interaction);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error handling interaction:', error);
|
console.error("Error handling interaction:", error);
|
||||||
this.handleInteractionError(interaction, error);
|
await this.handleInteractionError(interaction, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleCommand(interaction) {
|
async handleCommand(interaction) {
|
||||||
try {
|
try {
|
||||||
|
// Defer the reply immediately for all commands
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
|
||||||
switch (interaction.commandName) {
|
switch (interaction.commandName) {
|
||||||
case 'ping':
|
case "ping":
|
||||||
await this.commandHandler.handlePing(interaction);
|
await this.commandHandler.handlePing(interaction);
|
||||||
break;
|
break;
|
||||||
case 'finduser':
|
case "finduser":
|
||||||
await this.commandHandler.handleFindUser(interaction);
|
await this.commandHandler.handleFindUser(interaction);
|
||||||
break;
|
break;
|
||||||
case 'matchhistory':
|
case "matchhistory":
|
||||||
await this.commandHandler.handleMatchHistory(interaction);
|
await this.commandHandler.handleMatchHistory(interaction);
|
||||||
break;
|
break;
|
||||||
|
case "subscribe":
|
||||||
|
if (this.subscriptionCommands) {
|
||||||
|
await this.subscriptionCommands.handleSubscribe(interaction);
|
||||||
|
} else {
|
||||||
|
await interaction.editReply("Subscription commands are not available.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "unsubscribe":
|
||||||
|
if (this.subscriptionCommands) {
|
||||||
|
await this.subscriptionCommands.handleUnsubscribe(interaction);
|
||||||
|
} else {
|
||||||
|
await interaction.editReply("Subscription commands are not available.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "listsubscriptions":
|
||||||
|
if (this.subscriptionCommands) {
|
||||||
|
await this.subscriptionCommands.handleListSubscriptions(interaction);
|
||||||
|
} else {
|
||||||
|
await interaction.editReply("Subscription commands are not available.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
await interaction.reply({
|
await interaction.editReply("Unknown command");
|
||||||
content: 'Unknown command',
|
|
||||||
ephemeral: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error('Command error:', error);
|
||||||
await this.handleCommandError(interaction, error);
|
await this.handleCommandError(interaction, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleButton(interaction) {
|
async handleButton(interaction) {
|
||||||
const [action, matchId] = interaction.customId.split('_match_');
|
const [action, matchId] = interaction.customId.split("_match_");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'accept':
|
case "accept":
|
||||||
await this.matchCommands.handleMatchAccept(interaction, matchId);
|
await this.matchCommands.handleMatchAccept(interaction, matchId);
|
||||||
break;
|
break;
|
||||||
case 'view':
|
case "view":
|
||||||
await this.matchCommands.handleViewDetails(interaction, matchId);
|
await this.matchCommands.handleViewDetails(interaction, matchId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
content: 'Unknown button action',
|
content: "Unknown button action",
|
||||||
ephemeral: true
|
ephemeral: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error handling button:', error);
|
console.error("Error handling button:", error);
|
||||||
await this.handleInteractionError(interaction, error);
|
await this.handleInteractionError(interaction, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleCommandError(interaction, error) {
|
async handleCommandError(interaction, error) {
|
||||||
console.error('Command error:', error);
|
console.error("Command error:", error);
|
||||||
|
|
||||||
if (error.code === 10062) {
|
if (error.code === 10062) {
|
||||||
console.log('Interaction expired');
|
console.log("Interaction expired");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const message = 'An error occurred while processing your command.';
|
const message = "An error occurred while processing your command.";
|
||||||
if (interaction.deferred) {
|
if (interaction.deferred) {
|
||||||
await interaction.editReply({ content: message, ephemeral: true });
|
await interaction.editReply({ content: message });
|
||||||
} else if (!interaction.replied) {
|
} else if (!interaction.replied) {
|
||||||
await interaction.reply({ content: message, ephemeral: true });
|
await interaction.reply({ content: message, ephemeral: true });
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error while sending error message:', e);
|
console.error("Error while sending error message:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleInteractionError(interaction, error) {
|
async handleInteractionError(interaction, error) {
|
||||||
console.error('Interaction error:', error);
|
console.error("Interaction error:", error);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!interaction.replied && !interaction.deferred) {
|
if (!interaction.replied && !interaction.deferred) {
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
content: 'An error occurred while processing your request.',
|
content: "An error occurred while processing your request.",
|
||||||
ephemeral: true
|
ephemeral: true,
|
||||||
});
|
});
|
||||||
} else if (interaction.deferred) {
|
} else if (interaction.deferred) {
|
||||||
await interaction.editReply({
|
await interaction.editReply({
|
||||||
content: 'An error occurred while processing your request.',
|
content: "An error occurred while processing your request.",
|
||||||
ephemeral: true
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error while sending error message:', e);
|
console.error("Error while sending error message:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
62
src/commands/SubscriptionCommands.js
Normal file
62
src/commands/SubscriptionCommands.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
class SubscriptionCommands {
|
||||||
|
constructor(supabaseService) {
|
||||||
|
this.supabaseService = supabaseService;
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleSubscribe(interaction) {
|
||||||
|
const gameName = interaction.options.getString('game');
|
||||||
|
const channel = interaction.options.getChannel('channel') || interaction.channel;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Defer the reply immediately
|
||||||
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
|
||||||
|
// Perform the subscription operation
|
||||||
|
await this.supabaseService.addSubscription(interaction.guildId, gameName, channel.id);
|
||||||
|
|
||||||
|
// Edit the deferred reply with the success message
|
||||||
|
await interaction.editReply(`Successfully subscribed to ${gameName} notifications in ${channel}.`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error subscribing:', error);
|
||||||
|
|
||||||
|
// If we failed to defer earlier, try to reply now
|
||||||
|
if (!interaction.deferred && !interaction.replied) {
|
||||||
|
await interaction.reply({ content: 'An error occurred while subscribing. Please try again.', ephemeral: true }).catch(console.error);
|
||||||
|
} else {
|
||||||
|
// If we successfully deferred earlier, edit the reply
|
||||||
|
await interaction.editReply('An error occurred while subscribing. Please try again.').catch(console.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleUnsubscribe(interaction) {
|
||||||
|
const gameName = interaction.options.getString('game');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.supabaseService.removeSubscription(interaction.guildId, gameName);
|
||||||
|
await interaction.reply(`Successfully unsubscribed from ${gameName} notifications.`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error unsubscribing:', error);
|
||||||
|
await interaction.reply('An error occurred while unsubscribing. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleListSubscriptions(interaction) {
|
||||||
|
try {
|
||||||
|
const subscriptions = await this.supabaseService.getSubscriptions(interaction.guildId);
|
||||||
|
if (subscriptions.length === 0) {
|
||||||
|
await interaction.reply('This server has no active subscriptions.');
|
||||||
|
} else {
|
||||||
|
const subscriptionList = subscriptions.map(sub =>
|
||||||
|
`${sub.game_name} in <#${sub.channel_id}>`
|
||||||
|
).join('\n');
|
||||||
|
await interaction.reply(`Active subscriptions:\n${subscriptionList}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error listing subscriptions:', error);
|
||||||
|
await interaction.reply('An error occurred while fetching subscriptions. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SubscriptionCommands;
|
||||||
@@ -5,12 +5,13 @@ const { createMatchRequestEmbed } = require('../utils/embedBuilders');
|
|||||||
const { createMatchActionRow } = require('../utils/componentBuilders');
|
const { createMatchActionRow } = require('../utils/componentBuilders');
|
||||||
|
|
||||||
class NotificationService {
|
class NotificationService {
|
||||||
constructor(bot) {
|
constructor(bot, supabaseService) {
|
||||||
this.bot = bot;
|
this.bot = bot;
|
||||||
this.app = express();
|
this.supabaseService = supabaseService;
|
||||||
this.app.use(express.json());
|
this.app = express();
|
||||||
this.setupRoutes();
|
this.app.use(express.json());
|
||||||
}
|
this.setupRoutes();
|
||||||
|
}
|
||||||
|
|
||||||
setupRoutes() {
|
setupRoutes() {
|
||||||
this.app.post('/api/match-notification', this.handleMatchNotification.bind(this));
|
this.app.post('/api/match-notification', this.handleMatchNotification.bind(this));
|
||||||
@@ -49,26 +50,25 @@ class NotificationService {
|
|||||||
return res.status(400).json({ error: 'Invalid match data' });
|
return res.status(400).json({ error: 'Invalid match data' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const notificationChannelId = process.env.NOTIFICATION_CHANNEL_ID;
|
const subscriptions = await this.supabaseService.getSubscriptions();
|
||||||
if (!notificationChannelId) {
|
const relevantSubscriptions = subscriptions.filter(sub => sub.game_name === matchData.game_name);
|
||||||
throw new Error('Notification channel ID not configured');
|
|
||||||
|
for (const subscription of relevantSubscriptions) {
|
||||||
|
try {
|
||||||
|
const channel = await this.bot.client.channels.fetch(subscription.channel_id);
|
||||||
|
const embed = createMatchRequestEmbed(matchData);
|
||||||
|
const actionRow = createMatchActionRow(matchData.game_id);
|
||||||
|
|
||||||
|
await channel.send({
|
||||||
|
embeds: [embed],
|
||||||
|
components: [actionRow]
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error sending notification to channel ${subscription.channel_id}:`, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
res.json({ success: true });
|
||||||
const channel = await this.bot.client.channels.fetch(notificationChannelId);
|
|
||||||
const embed = createMatchRequestEmbed(matchData);
|
|
||||||
const actionRow = createMatchActionRow(matchData.game_id);
|
|
||||||
|
|
||||||
await channel.send({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [actionRow]
|
|
||||||
});
|
|
||||||
|
|
||||||
res.json({ success: true });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching or sending to notification channel:', error);
|
|
||||||
throw new Error('Failed to send match notification');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error handling match notification:', error);
|
console.error('Error handling match notification:', error);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
|||||||
58
src/services/SupabaseService.js
Normal file
58
src/services/SupabaseService.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
const { createClient } = require('@supabase/supabase-js');
|
||||||
|
|
||||||
|
class SupabaseService {
|
||||||
|
constructor() {
|
||||||
|
const supabaseUrl = process.env.SUPABASE_URL;
|
||||||
|
const supabaseKey = process.env.SUPABASE_KEY;
|
||||||
|
|
||||||
|
if (!supabaseUrl || !supabaseKey) {
|
||||||
|
console.error('Supabase URL or key is missing. Please check your .env file.');
|
||||||
|
this.supabase = null;
|
||||||
|
} else {
|
||||||
|
this.supabase = createClient(supabaseUrl, supabaseKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSubscriptions(guildId) {
|
||||||
|
if (!this.supabase) {
|
||||||
|
console.error('Supabase client is not initialized.');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const { data, error } = await this.supabase
|
||||||
|
.from('subscriptions')
|
||||||
|
.select('*')
|
||||||
|
.eq('guild_id', guildId);
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addSubscription(guildId, gameName, channelId) {
|
||||||
|
if (!this.supabase) {
|
||||||
|
console.error('Supabase client is not initialized.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { data, error } = await this.supabase
|
||||||
|
.from('subscriptions')
|
||||||
|
.insert({ guild_id: guildId, game_name: gameName, channel_id: channelId });
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeSubscription(guildId, gameName) {
|
||||||
|
if (!this.supabase) {
|
||||||
|
console.error('Supabase client is not initialized.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { data, error } = await this.supabase
|
||||||
|
.from('subscriptions')
|
||||||
|
.delete()
|
||||||
|
.match({ guild_id: guildId, game_name: gameName });
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SupabaseService;
|
||||||
Reference in New Issue
Block a user