From 6237660a9b28d355bccbf4512cc6f4e28e8ce76f Mon Sep 17 00:00:00 2001 From: mi-mott <98304083+mi-mott@users.noreply.github.com> Date: Tue, 7 Feb 2023 19:07:31 +1100 Subject: [PATCH 01/19] update: checking if perms work --- config/database.yml | 10 +++++----- data/createvc.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/database.yml b/config/database.yml index 1fa06e4f..f4ffa9e4 100644 --- a/config/database.yml +++ b/config/database.yml @@ -2,8 +2,8 @@ # Database Settings # #################################################################### -user: user -dbname: bot -password: pass -host: 0.0.0.0 -port: 40041 +user: postgres +dbname: Fuelbot +password: abc +host: localhost +port: 5432 diff --git a/data/createvc.json b/data/createvc.json index 1b3f33f3..b8daef27 100644 --- a/data/createvc.json +++ b/data/createvc.json @@ -1,4 +1,4 @@ { "users": [], "channels": [] -} +} \ No newline at end of file From d6628a38a16547a79a9f372649fac390916f3910 Mon Sep 17 00:00:00 2001 From: mi-mott <98304083+mi-mott@users.noreply.github.com> Date: Tue, 7 Feb 2023 20:52:53 +1100 Subject: [PATCH 02/19] Chron job set for every minute, basic embed added and structure for the locations and sub locations created --- data/lunch_buddy_locations.js | 109 +++++++++ events/lunch_buddy.js | 28 +++ package-lock.json | 448 ++++++++++++++++++++++++++++++++-- package.json | 7 +- 4 files changed, 568 insertions(+), 24 deletions(-) create mode 100644 data/lunch_buddy_locations.js create mode 100644 events/lunch_buddy.js diff --git a/data/lunch_buddy_locations.js b/data/lunch_buddy_locations.js new file mode 100644 index 00000000..9cf5a6e3 --- /dev/null +++ b/data/lunch_buddy_locations.js @@ -0,0 +1,109 @@ +const locations = [ + { + 'value': 'Upper Campus Food Court', + 'sub': [ + { + 'name': 'Tropical Green Pho' + }, + { + 'name': 'Pho House' + }, + { + 'name': 'Classic Kebab' + }, + { + 'name': 'Chinese Takeaway' + }, + { + 'name': 'Tori Sushi' + }, + { + 'name': 'Gradu-eat' + }, + { + 'name': 'The Little Marionette Cafe' + }, + { + 'name': 'Lhaksa Delight' + }, + { + 'name': 'Bioscience building Cafe (XS Espresso)' + } + ] + }, + { + 'value': 'Subway Zone', + 'sub': [ + { + 'name': 'Subway' + }, + { + 'name': 'Boost' + }, + { + 'name': 'Southern Wok' + }, + { + 'name': 'Cafe Brioso' + }, + { + 'name': 'Penny Lane' + }, + ] + }, + { + 'value': 'Quad Food court (under renovation)', + 'sub': [ + { + 'name': 'Plume Cafe (Open)' + }, + ] + }, + { + 'value': 'Lower Campus', + 'sub': [ + { + 'name': 'Stellinis Pasta Bar' + }, + { + 'name': 'GYG' + }, + { + 'name': 'Mamak Village' + }, + { + 'name': 'Yallah Eats Kebab and Shawarma' + }, + { + 'name': 'Sharetea' + }, + { + 'name': 'Maze Coffee & Food' + }, + { + 'name': 'Campus Village Cafe' + }, + ] + }, + { + 'value': 'J17 Ainsworth', + 'sub': [ + { + 'name': 'Coffee on Campus cafe' + }, + ] + }, + { + 'value': 'Other Options (Still in UNSW)', + 'sub': [ + { + 'name': 'Sport' + }, + { + 'name': 'On campus study' + }, + ] + } +] + +exports.locations = locations; \ No newline at end of file diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js new file mode 100644 index 00000000..b7b3b939 --- /dev/null +++ b/events/lunch_buddy.js @@ -0,0 +1,28 @@ +const { MessageEmbed } = require('discord.js'); +const cron = require('node-cron'); +const lunchBuddyLocations = require('../data/lunch_buddy_locations'); + +const exampleEmbed = new MessageEmbed() + .setColor(0x0099FF) + .setDescription('Some description here') + +lunchBuddyLocations.locations[0].sub.forEach(e => { + exampleEmbed.addFields({ name: e.name, value: 'Some value here' },) +}); + + + +module.exports = { + name: "ready", + once: true, + execute(client) { + + cron.schedule('* * * * *', function() { + client.channels.fetch('946636861256904774') + .then(channel => { + channel.send({embeds: [exampleEmbed], ephemeral: true}); + }) + + }); + }, +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c738b18d..13a6bd14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,9 @@ "dotenv": "10.0.0", "js-yaml": "4.1.0", "mathjs": "^11.3.3", + "node-cron": "^3.0.2", "nodemailer": "6.7.5", + "nodemon": "^2.0.20", "pg": "8.7.3", "textversionjs": "1.1.3", "voucher-code-generator": "1.1.1", @@ -899,6 +901,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -995,6 +1009,14 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -1013,7 +1035,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -1152,6 +1173,43 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -1985,7 +2043,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2107,6 +2164,19 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -2351,6 +2421,11 @@ "node": ">= 4" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" + }, "node_modules/ignore-walk": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", @@ -2405,11 +2480,21 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2426,7 +2511,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -2438,7 +2522,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -2540,9 +2623,9 @@ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -2867,6 +2950,25 @@ "ms": "^2.1.1" } }, + "node_modules/node-cron": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz", + "integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==", + "dependencies": { + "uuid": "8.3.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/node-cron/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -3165,6 +3267,68 @@ "node": ">=6.0.0" } }, + "node_modules/nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -3179,6 +3343,14 @@ "node": ">=6" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-bundled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", @@ -3518,7 +3690,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -3633,6 +3804,11 @@ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -3706,6 +3882,17 @@ "node": ">= 6" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.10", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", @@ -3937,6 +4124,25 @@ "simple-concat": "^1.0.0" } }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4084,7 +4290,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -4092,6 +4297,31 @@ "node": ">=8.0" } }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -4171,6 +4401,11 @@ "node": ">= 14" } }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + }, "node_modules/update-browserslist-db": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", @@ -5010,6 +5245,15 @@ "color-convert": "^2.0.1" } }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -5096,6 +5340,11 @@ } } }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -5114,7 +5363,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -5199,6 +5447,31 @@ "domutils": "^3.0.1" } }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, "chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -5821,7 +6094,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -5900,6 +6172,12 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, "gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -6079,6 +6357,11 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" + }, "ignore-walk": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", @@ -6124,11 +6407,18 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -6139,7 +6429,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -6147,8 +6436,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-obj": { "version": "2.0.0", @@ -6235,9 +6523,9 @@ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "jsprim": { @@ -6482,6 +6770,21 @@ } } }, + "node-cron": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz", + "integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==", + "requires": { + "uuid": "8.3.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, "node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -6735,6 +7038,51 @@ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.5.tgz", "integrity": "sha512-6VtMpwhsrixq1HDYSBBHvW0GwiWawE75dS3oal48VqRhUvKJNnKnJo2RI/bCVQubj1vgrgscMNW4DHaD6xtMCg==" }, + "nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -6743,6 +7091,11 @@ "abbrev": "1" } }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, "npm-bundled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", @@ -7002,8 +7355,7 @@ "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "postgres-array": { "version": "2.0.0", @@ -7066,6 +7418,11 @@ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -7112,6 +7469,14 @@ "util-deprecate": "^1.0.1" } }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, "regenerator-runtime": { "version": "0.13.10", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", @@ -7265,6 +7630,21 @@ "simple-concat": "^1.0.0" } }, + "simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "requires": { + "semver": "~7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + } + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -7379,11 +7759,28 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "requires": { + "nopt": "~1.0.10" + }, + "dependencies": { + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "requires": { + "abbrev": "1" + } + } + } + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -7447,6 +7844,11 @@ "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.1.0.tgz", "integrity": "sha512-DGwUl6cioBW5gw2L+6SMupGwH/kZOqivy17E4nsh1JI9fKF87orMmlQx3KISQPmg3sfnOUGlwVkroosvgddrlg==" }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + }, "update-browserslist-db": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", diff --git a/package.json b/package.json index 55e35eeb..a065fbf4 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,10 @@ "format:check": "prettier --check './**/*.js'", "lint": "eslint . --ext .js", "lint:fix": "eslint --fix . --ext .js", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "de": "node deploy-commands.js", + "start": "node index.js", + "server": "nodemon index.js" }, "repository": { "type": "git", @@ -37,7 +40,9 @@ "dotenv": "10.0.0", "js-yaml": "4.1.0", "mathjs": "^11.3.3", + "node-cron": "^3.0.2", "nodemailer": "6.7.5", + "nodemon": "^2.0.20", "pg": "8.7.3", "textversionjs": "1.1.3", "voucher-code-generator": "1.1.1", From 37ac8d6290d59cc9357428ed9953223c559e8197 Mon Sep 17 00:00:00 2001 From: mi-mott <98304083+mi-mott@users.noreply.github.com> Date: Tue, 7 Feb 2023 20:56:55 +1100 Subject: [PATCH 03/19] Updated README --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c35c1a4e..36f29917 100644 --- a/README.md +++ b/README.md @@ -8,5 +8,10 @@ - `DISCORD_TOKEN` with the token of the bot - `APP_ID` with the ID of the bot application - Install dependencies with `npm install` -- Register slash commands with `node deploy-commands.js` +- Register slash commands with `node deploy-commands.js` or `npm run de` - Start the bot with `node index.js` + +## Running the bot with Nodemon + +- Nodemon has been installed, this addition allows for continuous integration with and hot reloads the bot upon saving. +- Run the bot with Nodemon using npm run server \ No newline at end of file From 888fbb783b341fc69c6d27149c47f1787b1e7011 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Sun, 12 Feb 2023 16:05:29 +1100 Subject: [PATCH 04/19] Implemented area voting system --- data/lunch_buddy_locations.js | 10 +-- events/lunch_buddy.js | 115 ++++++++++++++++++++++++++++++---- 2 files changed, 108 insertions(+), 17 deletions(-) diff --git a/data/lunch_buddy_locations.js b/data/lunch_buddy_locations.js index 9cf5a6e3..2319274d 100644 --- a/data/lunch_buddy_locations.js +++ b/data/lunch_buddy_locations.js @@ -52,7 +52,7 @@ const locations = [ ] }, { - 'value': 'Quad Food court (under renovation)', + 'value': 'Quadrangle Food Court (under renovation)', 'sub': [ { 'name': 'Plume Cafe (Open)' @@ -66,7 +66,7 @@ const locations = [ 'name': 'Stellinis Pasta Bar' }, { - 'name': 'GYG' + 'name': 'Guzman Y Gomez' }, { 'name': 'Mamak Village' @@ -89,18 +89,18 @@ const locations = [ 'value': 'J17 Ainsworth', 'sub': [ { - 'name': 'Coffee on Campus cafe' + 'name': 'Coffee on Campus Cafe' }, ] }, { - 'value': 'Other Options (Still in UNSW)', + 'value': 'Other Options', 'sub': [ { 'name': 'Sport' }, { - 'name': 'On campus study' + 'name': 'On Campus Study' }, ] } diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index b7b3b939..7ac80e34 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -1,28 +1,119 @@ -const { MessageEmbed } = require('discord.js'); +const { MessageEmbed, MessageButton, MessageActionRow } = require('discord.js'); const cron = require('node-cron'); const lunchBuddyLocations = require('../data/lunch_buddy_locations'); -const exampleEmbed = new MessageEmbed() - .setColor(0x0099FF) - .setDescription('Some description here') +const maxRowButtons = 5; +const areaButtonCustomId = 'AreaButton'; +const interactionTimeout = 30000; //30mins = 1800000 -lunchBuddyLocations.locations[0].sub.forEach(e => { - exampleEmbed.addFields({ name: e.name, value: 'Some value here' },) -}); +const generateAreasEmbed = (areaVotes = undefined) => { + const areas = lunchBuddyLocations.locations.map(element => (`${element.value}: ${areaVotes ? areaVotes[element.value].length : 0}`)); + return new MessageEmbed() + .setTitle('Meetup Area Selection') + .setColor(0x0099FF) + .setDescription('Please select an option below to vote for that area!') + .setFields({ + name: 'Options', + value: areas.join('\n') + }); +}; +const generateLocationsEmbed = (area, votes = undefined) => { + const locations = lunchBuddyLocations.locations[area].sub.map(element => (`${element.value}: ${votes ? votes[element.value].length : 0}`)); + return new MessageEmbed() + .setTitle(`Meetup Location Selection - ${area}`) + .setColor(0x0099FF) + .setDescription('Please select an option below to vote for that location!') + .setFields({ + name: 'Options', + value: locations.join('\n') + }); +} +const areasList = lunchBuddyLocations.locations.map(element => element.value); +const areasButtons = lunchBuddyLocations.locations.map(element => new MessageButton({ + style: "PRIMARY", + label: element.value, + customId: `${element.value}${areaButtonCustomId}` +})); +areasButtons.push(new MessageButton({ + style: 'DANGER', + label: 'Remove Vote', + customId: `Remove${areaButtonCustomId}` +})); +const areasButtonsIds = lunchBuddyLocations.locations.map(element => `${element.value}${areaButtonCustomId}`); +areasButtonsIds.push(`Remove${areaButtonCustomId}`) +const areasActionRows = []; +for (let i = 0; i < areasButtons.length; i += maxRowButtons) { + areasActionRows.push(new MessageActionRow({ components: areasButtons.slice(i, i + maxRowButtons) })); +} +const areasButtonsFilter = (resInteraction) => { + return areasButtonsIds.includes(resInteraction.customId); +}; +const getVoteOption = (userId, votes) => { + for (const option of Object.keys(votes)) { + if (votes[option].includes(userId)) { + return option; + } + } + return undefined; +} module.exports = { - name: "ready", + name: 'ready', once: true, execute(client) { - cron.schedule('* * * * *', function() { + const areaVotes = []; + areasList.forEach((area) => areaVotes[area] = []); + client.channels.fetch('946636861256904774') - .then(channel => { - channel.send({embeds: [exampleEmbed], ephemeral: true}); - }) + .then(async (channel) => { + const message = await channel.send({embeds: [generateAreasEmbed()], components: areasActionRows}); + + const collector = message.createMessageComponentCollector({ + filter: areasButtonsFilter, + time: interactionTimeout, + idle: interactionTimeout, + }); + + collector.on('collect', async(interaction) => { + const interactorId = String(interaction.user.id) + const priorVoteOption = getVoteOption(interactorId, areaVotes); + const newOption = interaction.customId.replace(areaButtonCustomId, ''); + let newVoteString = ` voted for ${newOption}!`; + let oldVoteString = ''; + + if (priorVoteOption) { + if (newOption === 'Remove') { + newVoteString = ' removed your vote.'; + const location = areaVotes[priorVoteOption].indexOf(interactorId); + areaVotes[priorVoteOption].splice(location, 1); + } else { + const location = areaVotes[priorVoteOption].indexOf(interactorId); + areaVotes[priorVoteOption].splice(location, 1); + + oldVoteString = ` removed your vote for ${priorVoteOption} and`; + } + } else if (newOption === 'Remove') { + newVoteString = ' no vote to remove.'; + } + + const voteString = `You have${oldVoteString}${newVoteString}`; + + if (newOption !== 'Remove') { + areaVotes[newOption].push(interactorId); + } + + interaction.reply({ content: voteString, ephemeral: true }); + interaction.message.edit({ embeds: [generateAreasEmbed(areaVotes)] }) + }); + + collector.on('end', () => { + message.delete(); + }); + }) }); }, }; \ No newline at end of file From e175de7be9bd2c0906f870b3699e7c3d52209390 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Sun, 12 Feb 2023 16:13:24 +1100 Subject: [PATCH 05/19] Ran linting and prettier for current changes --- data/lunch_buddy_locations.js | 106 +++++++++++++++--------------- events/lunch_buddy.js | 119 +++++++++++++++++++--------------- 2 files changed, 120 insertions(+), 105 deletions(-) diff --git a/data/lunch_buddy_locations.js b/data/lunch_buddy_locations.js index 2319274d..6aff5770 100644 --- a/data/lunch_buddy_locations.js +++ b/data/lunch_buddy_locations.js @@ -1,109 +1,109 @@ const locations = [ - { - 'value': 'Upper Campus Food Court', - 'sub': [ + { + value: "Upper Campus Food Court", + sub: [ { - 'name': 'Tropical Green Pho' + name: "Tropical Green Pho", }, { - 'name': 'Pho House' + name: "Pho House", }, { - 'name': 'Classic Kebab' + name: "Classic Kebab", }, { - 'name': 'Chinese Takeaway' + name: "Chinese Takeaway", }, { - 'name': 'Tori Sushi' + name: "Tori Sushi", }, { - 'name': 'Gradu-eat' + name: "Gradu-eat", }, { - 'name': 'The Little Marionette Cafe' + name: "The Little Marionette Cafe", }, { - 'name': 'Lhaksa Delight' + name: "Lhaksa Delight", }, { - 'name': 'Bioscience building Cafe (XS Espresso)' - } - ] + name: "Bioscience building Cafe (XS Espresso)", + }, + ], }, - { - 'value': 'Subway Zone', - 'sub': [ + { + value: "Subway Zone", + sub: [ { - 'name': 'Subway' + name: "Subway", }, { - 'name': 'Boost' + name: "Boost", }, { - 'name': 'Southern Wok' + name: "Southern Wok", }, { - 'name': 'Cafe Brioso' + name: "Cafe Brioso", }, { - 'name': 'Penny Lane' + name: "Penny Lane", }, - ] + ], }, - { - 'value': 'Quadrangle Food Court (under renovation)', - 'sub': [ + { + value: "Quadrangle Food Court (under renovation)", + sub: [ { - 'name': 'Plume Cafe (Open)' + name: "Plume Cafe (Open)", }, - ] + ], }, - { - 'value': 'Lower Campus', - 'sub': [ + { + value: "Lower Campus", + sub: [ { - 'name': 'Stellinis Pasta Bar' + name: "Stellinis Pasta Bar", }, { - 'name': 'Guzman Y Gomez' + name: "Guzman Y Gomez", }, { - 'name': 'Mamak Village' + name: "Mamak Village", }, { - 'name': 'Yallah Eats Kebab and Shawarma' + name: "Yallah Eats Kebab and Shawarma", }, { - 'name': 'Sharetea' + name: "Sharetea", }, { - 'name': 'Maze Coffee & Food' + name: "Maze Coffee & Food", }, { - 'name': 'Campus Village Cafe' + name: "Campus Village Cafe", }, - ] + ], }, - { - 'value': 'J17 Ainsworth', - 'sub': [ + { + value: "J17 Ainsworth", + sub: [ { - 'name': 'Coffee on Campus Cafe' + name: "Coffee on Campus Cafe", }, - ] + ], }, - { - 'value': 'Other Options', - 'sub': [ + { + value: "Other Options", + sub: [ { - 'name': 'Sport' + name: "Sport", }, { - 'name': 'On Campus Study' + name: "On Campus Study", }, - ] - } -] + ], + }, +]; -exports.locations = locations; \ No newline at end of file +exports.locations = locations; diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index 7ac80e34..32336e6a 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -1,49 +1,62 @@ -const { MessageEmbed, MessageButton, MessageActionRow } = require('discord.js'); -const cron = require('node-cron'); -const lunchBuddyLocations = require('../data/lunch_buddy_locations'); +const { MessageEmbed, MessageButton, MessageActionRow } = require("discord.js"); +const cron = require("node-cron"); +const lunchBuddyLocations = require("../data/lunch_buddy_locations"); const maxRowButtons = 5; -const areaButtonCustomId = 'AreaButton'; -const interactionTimeout = 30000; //30mins = 1800000 +const areaButtonCustomId = "AreaButton"; +const interactionTimeout = 30000; const generateAreasEmbed = (areaVotes = undefined) => { - const areas = lunchBuddyLocations.locations.map(element => (`${element.value}: ${areaVotes ? areaVotes[element.value].length : 0}`)); + const areas = lunchBuddyLocations.locations.map( + (element) => `${element.value}: ${areaVotes ? areaVotes[element.value].length : 0}`, + ); return new MessageEmbed() - .setTitle('Meetup Area Selection') - .setColor(0x0099FF) - .setDescription('Please select an option below to vote for that area!') + .setTitle("Meetup Area Selection") + .setColor(0x0099ff) + .setDescription("Please select an option below to vote for that area!") .setFields({ - name: 'Options', - value: areas.join('\n') + name: "Options", + value: areas.join("\n"), }); }; const generateLocationsEmbed = (area, votes = undefined) => { - const locations = lunchBuddyLocations.locations[area].sub.map(element => (`${element.value}: ${votes ? votes[element.value].length : 0}`)); + const locations = lunchBuddyLocations.locations[area].sub.map( + (element) => `${element.value}: ${votes ? votes[element.value].length : 0}`, + ); return new MessageEmbed() .setTitle(`Meetup Location Selection - ${area}`) - .setColor(0x0099FF) - .setDescription('Please select an option below to vote for that location!') + .setColor(0x0099ff) + .setDescription("Please select an option below to vote for that location!") .setFields({ - name: 'Options', - value: locations.join('\n') + name: "Options", + value: locations.join("\n"), }); -} -const areasList = lunchBuddyLocations.locations.map(element => element.value); -const areasButtons = lunchBuddyLocations.locations.map(element => new MessageButton({ - style: "PRIMARY", - label: element.value, - customId: `${element.value}${areaButtonCustomId}` -})); -areasButtons.push(new MessageButton({ - style: 'DANGER', - label: 'Remove Vote', - customId: `Remove${areaButtonCustomId}` -})); -const areasButtonsIds = lunchBuddyLocations.locations.map(element => `${element.value}${areaButtonCustomId}`); -areasButtonsIds.push(`Remove${areaButtonCustomId}`) +}; +const areasList = lunchBuddyLocations.locations.map((element) => element.value); +const areasButtons = lunchBuddyLocations.locations.map( + (element) => + new MessageButton({ + style: "PRIMARY", + label: element.value, + customId: `${element.value}${areaButtonCustomId}`, + }), +); +areasButtons.push( + new MessageButton({ + style: "DANGER", + label: "Remove Vote", + customId: `Remove${areaButtonCustomId}`, + }), +); +const areasButtonsIds = lunchBuddyLocations.locations.map( + (element) => `${element.value}${areaButtonCustomId}`, +); +areasButtonsIds.push(`Remove${areaButtonCustomId}`); const areasActionRows = []; for (let i = 0; i < areasButtons.length; i += maxRowButtons) { - areasActionRows.push(new MessageActionRow({ components: areasButtons.slice(i, i + maxRowButtons) })); + areasActionRows.push( + new MessageActionRow({ components: areasButtons.slice(i, i + maxRowButtons) }), + ); } const areasButtonsFilter = (resInteraction) => { @@ -57,19 +70,21 @@ const getVoteOption = (userId, votes) => { } } return undefined; -} +}; module.exports = { - name: 'ready', + name: "ready", once: true, execute(client) { - cron.schedule('* * * * *', function() { + cron.schedule("* * * * *", function () { const areaVotes = []; - areasList.forEach((area) => areaVotes[area] = []); + areasList.forEach((area) => (areaVotes[area] = [])); - client.channels.fetch('946636861256904774') - .then(async (channel) => { - const message = await channel.send({embeds: [generateAreasEmbed()], components: areasActionRows}); + client.channels.fetch("946636861256904774").then(async (channel) => { + const message = await channel.send({ + embeds: [generateAreasEmbed()], + components: areasActionRows, + }); const collector = message.createMessageComponentCollector({ filter: areasButtonsFilter, @@ -77,43 +92,43 @@ module.exports = { idle: interactionTimeout, }); - collector.on('collect', async(interaction) => { - const interactorId = String(interaction.user.id) + collector.on("collect", async (interaction) => { + const interactorId = String(interaction.user.id); const priorVoteOption = getVoteOption(interactorId, areaVotes); - const newOption = interaction.customId.replace(areaButtonCustomId, ''); + const newOption = interaction.customId.replace(areaButtonCustomId, ""); let newVoteString = ` voted for ${newOption}!`; - let oldVoteString = ''; + let oldVoteString = ""; if (priorVoteOption) { - if (newOption === 'Remove') { - newVoteString = ' removed your vote.'; + if (newOption === "Remove") { + newVoteString = " removed your vote."; const location = areaVotes[priorVoteOption].indexOf(interactorId); areaVotes[priorVoteOption].splice(location, 1); } else { const location = areaVotes[priorVoteOption].indexOf(interactorId); areaVotes[priorVoteOption].splice(location, 1); - + oldVoteString = ` removed your vote for ${priorVoteOption} and`; } - } else if (newOption === 'Remove') { - newVoteString = ' no vote to remove.'; + } else if (newOption === "Remove") { + newVoteString = " no vote to remove."; } const voteString = `You have${oldVoteString}${newVoteString}`; - if (newOption !== 'Remove') { + if (newOption !== "Remove") { areaVotes[newOption].push(interactorId); } interaction.reply({ content: voteString, ephemeral: true }); - interaction.message.edit({ embeds: [generateAreasEmbed(areaVotes)] }) + interaction.message.edit({ embeds: [generateAreasEmbed(areaVotes)] }); }); - collector.on('end', () => { + collector.on("end", () => { message.delete(); }); - }) + }); }); }, -}; \ No newline at end of file +}; From 65f5fb7c1c9243d00ffa09ddf9fb997e1a96f262 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Sat, 25 Feb 2023 16:44:54 +1100 Subject: [PATCH 06/19] Appending location poll for given area, and vote counting for both area and locations --- events/lunch_buddy.js | 196 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 181 insertions(+), 15 deletions(-) diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index 32336e6a..4cd8e310 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -4,7 +4,17 @@ const lunchBuddyLocations = require("../data/lunch_buddy_locations"); const maxRowButtons = 5; const areaButtonCustomId = "AreaButton"; -const interactionTimeout = 30000; +const locationButtonCustomId = "LocationButton"; +const interactionTimeout = 15000; + +const getLocations = (area) => { + for (const object of lunchBuddyLocations.locations) { + if (object.value === area) { + return object; + } + } + return undefined; +}; const generateAreasEmbed = (areaVotes = undefined) => { const areas = lunchBuddyLocations.locations.map( @@ -20,8 +30,9 @@ const generateAreasEmbed = (areaVotes = undefined) => { }); }; const generateLocationsEmbed = (area, votes = undefined) => { - const locations = lunchBuddyLocations.locations[area].sub.map( - (element) => `${element.value}: ${votes ? votes[element.value].length : 0}`, + const locationData = getLocations(area); + const locations = locationData.sub.map( + (element) => `${element.name}: ${votes ? votes[element.name].length : 0}`, ); return new MessageEmbed() .setTitle(`Meetup Location Selection - ${area}`) @@ -72,27 +83,46 @@ const getVoteOption = (userId, votes) => { return undefined; }; +const getMostVoted = (votes) => { + let maxValue = 0; + let results = []; + for (const option of Object.keys(votes)) { + const optionVotes = votes[option].length; + if (optionVotes > maxValue) { + maxValue = optionVotes; + results = [option]; + } else if (optionVotes === maxValue) { + results.push(option); + } + } + + return results; +}; + module.exports = { name: "ready", once: true, execute(client) { cron.schedule("* * * * *", function () { - const areaVotes = []; + // Setup for voting + const areaVotes = {}; areasList.forEach((area) => (areaVotes[area] = [])); + // Fetch channel object and send voting message client.channels.fetch("946636861256904774").then(async (channel) => { - const message = await channel.send({ + const areaMessage = await channel.send({ embeds: [generateAreasEmbed()], components: areasActionRows, }); - const collector = message.createMessageComponentCollector({ + // Setup receiving message interactions + const areaCollector = areaMessage.createMessageComponentCollector({ filter: areasButtonsFilter, time: interactionTimeout, idle: interactionTimeout, }); - collector.on("collect", async (interaction) => { + areaCollector.on("collect", async (interaction) => { const interactorId = String(interaction.user.id); const priorVoteOption = getVoteOption(interactorId, areaVotes); const newOption = interaction.customId.replace(areaButtonCustomId, ""); @@ -100,15 +130,15 @@ module.exports = { let newVoteString = ` voted for ${newOption}!`; let oldVoteString = ""; + // Checks whether voter has previously cast vote and edits accordingly if (priorVoteOption) { + // Removes previously cast vote + const location = areaVotes[priorVoteOption].indexOf(interactorId); + areaVotes[priorVoteOption].splice(location, 1); + if (newOption === "Remove") { newVoteString = " removed your vote."; - const location = areaVotes[priorVoteOption].indexOf(interactorId); - areaVotes[priorVoteOption].splice(location, 1); } else { - const location = areaVotes[priorVoteOption].indexOf(interactorId); - areaVotes[priorVoteOption].splice(location, 1); - oldVoteString = ` removed your vote for ${priorVoteOption} and`; } } else if (newOption === "Remove") { @@ -117,16 +147,152 @@ module.exports = { const voteString = `You have${oldVoteString}${newVoteString}`; + // Appends new vote if cast if (newOption !== "Remove") { areaVotes[newOption].push(interactorId); } interaction.reply({ content: voteString, ephemeral: true }); - interaction.message.edit({ embeds: [generateAreasEmbed(areaVotes)] }); + areaMessage.edit({ embeds: [generateAreasEmbed(areaVotes)] }); }); - collector.on("end", () => { - message.delete(); + areaCollector.on("end", async () => { + // Removes options to vote for area + await areaMessage.edit({ components: [] }); + + let areaInfo; + let selected; + + // Finds the highest voted option, and randomises for ties + const mostVoted = getMostVoted(areaVotes); + if (mostVoted.length !== 1) { + selected = mostVoted[Math.floor(Math.random() * mostVoted.length)]; + areaInfo = `Several options had the highest votes, and the area ${selected} was randomly selected from the tied options.`; + } else { + selected = mostVoted[0]; + areaInfo = `The area ${selected} had the highest votes.`; + } + + if (areaVotes[selected].length) { + await areaMessage.reply(areaInfo); + } else { + await areaMessage.reply("No votes were cast for the area."); + return; + } + + const locationData = getLocations(selected); + + const locationsList = locationData.sub.map((element) => element.name); + const locationsButtons = locationData.sub.map( + (element) => + new MessageButton({ + style: "PRIMARY", + label: element.name, + customId: `${element.name}${locationButtonCustomId}`, + }), + ); + locationsButtons.push( + new MessageButton({ + style: "DANGER", + label: "Remove Vote", + customId: `Remove${locationButtonCustomId}`, + }), + ); + const locationsButtonsIds = locationData.sub.map( + (element) => `${element.name}${locationButtonCustomId}`, + ); + locationsButtonsIds.push(`Remove${locationButtonCustomId}`); + const locationsActionRows = []; + for (let i = 0; i < locationsButtons.length; i += maxRowButtons) { + locationsActionRows.push( + new MessageActionRow({ + components: locationsButtons.slice(i, i + maxRowButtons), + }), + ); + } + + const locationVotes = {}; + locationsList.forEach((location) => (locationVotes[location] = [])); + + const locationMessage = await channel.send({ + embeds: [generateLocationsEmbed(selected)], + components: locationsActionRows, + }); + + const locationsButtonsFilter = (resInteraction) => { + return locationsButtonsIds.includes(resInteraction.customId); + }; + + // Setup receiving message interactions + const locationCollector = locationMessage.createMessageComponentCollector({ + filter: locationsButtonsFilter, + time: interactionTimeout, + idle: interactionTimeout, + }); + + locationCollector.on("collect", async (interaction) => { + const interactorId = String(interaction.user.id); + const priorVoteOption = getVoteOption(interactorId, locationVotes); + const newOption = interaction.customId.replace(locationButtonCustomId, ""); + + let newVoteString = ` voted for ${newOption}!`; + let oldVoteString = ""; + + // Checks whether voter has previously cast vote and edits accordingly + if (priorVoteOption) { + // Removes previously cast vote + const location = locationVotes[priorVoteOption].indexOf(interactorId); + locationVotes[priorVoteOption].splice(location, 1); + + if (newOption === "Remove") { + newVoteString = " removed your vote."; + } else { + oldVoteString = ` removed your vote for ${priorVoteOption} and`; + } + } else if (newOption === "Remove") { + newVoteString = " no vote to remove."; + } + + const voteString = `You have${oldVoteString}${newVoteString}`; + + // Appends new vote if cast + if (newOption !== "Remove") { + locationVotes[newOption].push(interactorId); + } + + interaction.reply({ content: voteString, ephemeral: true }); + locationMessage.edit({ + embeds: [generateLocationsEmbed(selected, locationVotes)], + }); + }); + + locationCollector.on("end", async () => { + // Removes options to vote for location + locationMessage.edit({ components: [] }); + + let locationInfo; + let selectedLocation; + + // Finds the highest voted option, and randomises for ties + const mostVotedLocation = getMostVoted(locationVotes); + if (mostVotedLocation.length !== 1) { + selectedLocation = + mostVotedLocation[ + Math.floor(Math.random() * mostVotedLocation.length) + ]; + locationInfo = `Several options had the highest votes, and the location ${selectedLocation} was randomly selected from the tied options.`; + } else { + selectedLocation = mostVotedLocation[0]; + locationInfo = `The location ${selectedLocation} had the highest votes.`; + } + + if (locationVotes[selectedLocation].length) { + await locationMessage.reply(locationInfo); + } else { + await locationMessage.reply("No votes were cast for the location."); + return; + } + }); }); }); }); From 492b13c90b5e8356470a61a277c0ec308b141b46 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Mon, 15 May 2023 22:34:41 +1000 Subject: [PATCH 07/19] Implemented functional voting system for area and location, creating thread upon completion of set --- events/lunch_buddy.js | 374 ++++++++++++++++++++++++------------------ 1 file changed, 217 insertions(+), 157 deletions(-) diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index 4cd8e310..c102c418 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -5,7 +5,9 @@ const lunchBuddyLocations = require("../data/lunch_buddy_locations"); const maxRowButtons = 5; const areaButtonCustomId = "AreaButton"; const locationButtonCustomId = "LocationButton"; -const interactionTimeout = 15000; +const interactionTimeout = 10000; +const voteOriginId = "946636861256904774"; +const threadDestinationId = "946636879426617354"; const getLocations = (area) => { for (const object of lunchBuddyLocations.locations) { @@ -103,198 +105,256 @@ module.exports = { name: "ready", once: true, execute(client) { - cron.schedule("* * * * *", function () { - // Setup for voting + cron.schedule("* * * * *", async function () { + let locationData; + let selectedArea; + let selectedLocation; const areaVotes = {}; - areasList.forEach((area) => (areaVotes[area] = [])); - // Fetch channel object and send voting message - client.channels.fetch("946636861256904774").then(async (channel) => { - const areaMessage = await channel.send({ - embeds: [generateAreasEmbed()], - components: areasActionRows, - }); - - // Setup receiving message interactions - const areaCollector = areaMessage.createMessageComponentCollector({ - filter: areasButtonsFilter, - time: interactionTimeout, - idle: interactionTimeout, - }); - - areaCollector.on("collect", async (interaction) => { - const interactorId = String(interaction.user.id); - const priorVoteOption = getVoteOption(interactorId, areaVotes); - const newOption = interaction.customId.replace(areaButtonCustomId, ""); + const conductAreaVote = () => { + return new Promise((resolve) => { + // Setup for voting + areasList.forEach((area) => (areaVotes[area] = [])); + // Fetch channel object and send voting message + client.channels.fetch(voteOriginId).then(async (voteChannel) => { + + const areaMessage = await voteChannel.send({ + embeds: [generateAreasEmbed()], + components: areasActionRows, + }); - let newVoteString = ` voted for ${newOption}!`; - let oldVoteString = ""; + // Setup receiving message interactions + const areaCollector = areaMessage.createMessageComponentCollector({ + filter: areasButtonsFilter, + time: interactionTimeout, + idle: interactionTimeout, + }); - // Checks whether voter has previously cast vote and edits accordingly - if (priorVoteOption) { - // Removes previously cast vote - const location = areaVotes[priorVoteOption].indexOf(interactorId); - areaVotes[priorVoteOption].splice(location, 1); + areaCollector.on("collect", async (interaction) => { + const interactorId = String(interaction.user.id); + const priorVoteOption = getVoteOption(interactorId, areaVotes); + const newOption = interaction.customId.replace(areaButtonCustomId, ""); + + let newVoteString = ` voted for ${newOption}!`; + let oldVoteString = ""; + + // Checks whether voter has previously cast vote and edits accordingly + if (priorVoteOption) { + if (priorVoteOption === newOption) { + interaction.reply({ + content: "You have already voted for this option.", + ephemeral: true, + }); + return; + } + // Removes previously cast vote + const location = areaVotes[priorVoteOption].indexOf(interactorId); + areaVotes[priorVoteOption].splice(location, 1); + + if (newOption === "Remove") { + newVoteString = " removed your vote."; + } else { + oldVoteString = ` removed your vote for ${priorVoteOption} and`; + } + } else if (newOption === "Remove") { + newVoteString = " no vote to remove."; + } - if (newOption === "Remove") { - newVoteString = " removed your vote."; - } else { - oldVoteString = ` removed your vote for ${priorVoteOption} and`; - } - } else if (newOption === "Remove") { - newVoteString = " no vote to remove."; - } + const voteString = `You have${oldVoteString}${newVoteString}`; - const voteString = `You have${oldVoteString}${newVoteString}`; + // Appends new vote if cast + if (newOption !== "Remove") { + areaVotes[newOption].push(interactorId); + } - // Appends new vote if cast - if (newOption !== "Remove") { - areaVotes[newOption].push(interactorId); - } + interaction.reply({ content: voteString, ephemeral: true }); + areaMessage.edit({ embeds: [generateAreasEmbed(areaVotes)] }); + }); - interaction.reply({ content: voteString, ephemeral: true }); - areaMessage.edit({ embeds: [generateAreasEmbed(areaVotes)] }); - }); + areaCollector.on("end", async () => { + // Removes options to vote for area + await areaMessage.edit({ components: [] }); - areaCollector.on("end", async () => { - // Removes options to vote for area - await areaMessage.edit({ components: [] }); + let areaInfo; - let areaInfo; - let selected; + // Finds the highest voted option, and randomises for ties + const mostVoted = getMostVoted(areaVotes); + if (mostVoted.length !== 1) { + selectedArea = mostVoted[Math.floor(Math.random() * mostVoted.length)]; + areaInfo = `Several options had the highest votes, and the area ${selectedArea} was randomly selected from the tied options.`; + } else { + selectedArea = mostVoted[0]; + areaInfo = `The area ${selectedArea} had the highest votes.`; + } - // Finds the highest voted option, and randomises for ties - const mostVoted = getMostVoted(areaVotes); - if (mostVoted.length !== 1) { - selected = mostVoted[Math.floor(Math.random() * mostVoted.length)]; - areaInfo = `Several options had the highest votes, and the area ${selected} was randomly selected from the tied options.`; - } else { - selected = mostVoted[0]; - areaInfo = `The area ${selected} had the highest votes.`; - } + if (areaVotes[selectedArea].length) { + await areaMessage.reply(areaInfo); + } else { + await areaMessage.reply("No votes were cast for the area."); + return; + } - if (areaVotes[selected].length) { - await areaMessage.reply(areaInfo); - } else { - await areaMessage.reply("No votes were cast for the area."); - return; - } + locationData = getLocations(selectedArea); - const locationData = getLocations(selected); + resolve(); + }); + }); + }); + }; + const conductLocationVote = () => { + return new Promise((resolve) => { const locationsList = locationData.sub.map((element) => element.name); - const locationsButtons = locationData.sub.map( - (element) => + + // Fetch channel and prepare voting message + client.channels.fetch(voteOriginId).then(async (voteChannel) => { + const locationsButtons = locationData.sub.map( + (element) => + new MessageButton({ + style: "PRIMARY", + label: element.name, + customId: `${element.name}${locationButtonCustomId}`, + }), + ); + locationsButtons.push( new MessageButton({ - style: "PRIMARY", - label: element.name, - customId: `${element.name}${locationButtonCustomId}`, - }), - ); - locationsButtons.push( - new MessageButton({ - style: "DANGER", - label: "Remove Vote", - customId: `Remove${locationButtonCustomId}`, - }), - ); - const locationsButtonsIds = locationData.sub.map( - (element) => `${element.name}${locationButtonCustomId}`, - ); - locationsButtonsIds.push(`Remove${locationButtonCustomId}`); - const locationsActionRows = []; - for (let i = 0; i < locationsButtons.length; i += maxRowButtons) { - locationsActionRows.push( - new MessageActionRow({ - components: locationsButtons.slice(i, i + maxRowButtons), + style: "DANGER", + label: "Remove Vote", + customId: `Remove${locationButtonCustomId}`, }), ); - } + const locationsButtonsIds = locationData.sub.map( + (element) => `${element.name}${locationButtonCustomId}`, + ); + locationsButtonsIds.push(`Remove${locationButtonCustomId}`); + const locationsActionRows = []; + for (let i = 0; i < locationsButtons.length; i += maxRowButtons) { + locationsActionRows.push( + new MessageActionRow({ + components: locationsButtons.slice(i, i + maxRowButtons), + }), + ); + } - const locationVotes = {}; - locationsList.forEach((location) => (locationVotes[location] = [])); + const locationVotes = {}; + locationsList.forEach((location) => (locationVotes[location] = [])); - const locationMessage = await channel.send({ - embeds: [generateLocationsEmbed(selected)], - components: locationsActionRows, - }); + const locationMessage = await voteChannel.send({ + embeds: [generateLocationsEmbed(selectedArea)], + components: locationsActionRows, + }); - const locationsButtonsFilter = (resInteraction) => { - return locationsButtonsIds.includes(resInteraction.customId); - }; + const locationsButtonsFilter = (resInteraction) => { + return locationsButtonsIds.includes(resInteraction.customId); + }; - // Setup receiving message interactions - const locationCollector = locationMessage.createMessageComponentCollector({ - filter: locationsButtonsFilter, - time: interactionTimeout, - idle: interactionTimeout, - }); + // Setup receiving message interactions + const locationCollector = locationMessage.createMessageComponentCollector({ + filter: locationsButtonsFilter, + time: interactionTimeout, + idle: interactionTimeout, + }); - locationCollector.on("collect", async (interaction) => { - const interactorId = String(interaction.user.id); - const priorVoteOption = getVoteOption(interactorId, locationVotes); - const newOption = interaction.customId.replace(locationButtonCustomId, ""); + locationCollector.on("collect", async (interaction) => { + const interactorId = String(interaction.user.id); + const priorVoteOption = getVoteOption(interactorId, locationVotes); + const newOption = interaction.customId.replace(locationButtonCustomId, ""); + + let newVoteString = ` voted for ${newOption}!`; + let oldVoteString = ""; + + // Checks whether voter has previously cast vote and edits accordingly + if (priorVoteOption) { + if (priorVoteOption === newOption) { + interaction.reply({ + content: "You have already voted for this option.", + ephemeral: true, + }); + return; + } + // Removes previously cast vote + const location = locationVotes[priorVoteOption].indexOf(interactorId); + locationVotes[priorVoteOption].splice(location, 1); + + if (newOption === "Remove") { + newVoteString = " removed your vote."; + } else { + oldVoteString = ` removed your vote for ${priorVoteOption} and`; + } + } else if (newOption === "Remove") { + newVoteString = " no vote to remove."; + } - let newVoteString = ` voted for ${newOption}!`; - let oldVoteString = ""; + const voteString = `You have${oldVoteString}${newVoteString}`; - // Checks whether voter has previously cast vote and edits accordingly - if (priorVoteOption) { - // Removes previously cast vote - const location = locationVotes[priorVoteOption].indexOf(interactorId); - locationVotes[priorVoteOption].splice(location, 1); + // Appends new vote if cast + if (newOption !== "Remove") { + locationVotes[newOption].push(interactorId); + } + + interaction.reply({ content: voteString, ephemeral: true }); + locationMessage.edit({ + embeds: [generateLocationsEmbed(selectedArea, locationVotes)], + }); + }); - if (newOption === "Remove") { - newVoteString = " removed your vote."; + locationCollector.on("end", async () => { + // Removes options to vote for location + locationMessage.edit({ components: [] }); + + let locationInfo; + + + // Finds the highest voted option, and randomises for ties + const mostVotedLocation = getMostVoted(locationVotes); + if (mostVotedLocation.length !== 1) { + selectedLocation = + mostVotedLocation[ + Math.floor(Math.random() * mostVotedLocation.length) + ]; + locationInfo = `Several options had the highest votes, and the location ${selectedLocation} was randomly selected from the tied options.`; } else { - oldVoteString = ` removed your vote for ${priorVoteOption} and`; + selectedLocation = mostVotedLocation[0]; + locationInfo = `The location ${selectedLocation} had the highest votes.`; } - } else if (newOption === "Remove") { - newVoteString = " no vote to remove."; - } - - const voteString = `You have${oldVoteString}${newVoteString}`; - // Appends new vote if cast - if (newOption !== "Remove") { - locationVotes[newOption].push(interactorId); - } + if (locationVotes[selectedLocation].length) { + await locationMessage.reply(locationInfo); + } else { + await locationMessage.reply("No votes were cast for the location."); + return; + } - interaction.reply({ content: voteString, ephemeral: true }); - locationMessage.edit({ - embeds: [generateLocationsEmbed(selected, locationVotes)], + resolve(); }); }); + }); + }; - locationCollector.on("end", async () => { - // Removes options to vote for location - locationMessage.edit({ components: [] }); - - let locationInfo; - let selectedLocation; - - // Finds the highest voted option, and randomises for ties - const mostVotedLocation = getMostVoted(locationVotes); - if (mostVotedLocation.length !== 1) { - selectedLocation = - mostVotedLocation[ - Math.floor(Math.random() * mostVotedLocation.length) - ]; - locationInfo = `Several options had the highest votes, and the location ${selectedLocation} was randomly selected from the tied options.`; - } else { - selectedLocation = mostVotedLocation[0]; - locationInfo = `The location ${selectedLocation} had the highest votes.`; - } + const createMeetupThread = () => { + const dateString = new Date().toLocaleDateString('en-AU') - if (locationVotes[selectedLocation].length) { - await locationMessage.reply(locationInfo); - } else { - await locationMessage.reply("No votes were cast for the location."); - return; - } + client.channels.fetch(threadDestinationId).then( async (channel) => { + // Creates thread which expires after 1 day + const thread = await channel.threads.create({ + name: `${dateString}-${selectedLocation}`, + autoArchiveDuration: 1440 + }); + + // Adds all area voters to thread + areaVotes[selectedArea].forEach(async (id) => { + await thread.members.add(id); + }); + + client.channels.fetch(voteOriginId).then(async (channel) => { + await channel.send(`Created a thread for today's lunch buddy meet: ${thread}`) }); }); - }); + }; + + await conductAreaVote(); + await conductLocationVote(); + createMeetupThread(); }); }, }; From faad7d3c75f23fb7423ed955ec55c26be228e3c8 Mon Sep 17 00:00:00 2001 From: mi-mott <98304083+mi-mott@users.noreply.github.com> Date: Sat, 27 May 2023 16:20:28 +1000 Subject: [PATCH 08/19] Used await and cleaned up a bit of code, thread now adds all voters not only the ones who voted for the winning area --- events/lunch_buddy.js | 371 +++++++++++++++++++------------------- events/tictactoeButton.js | 24 +-- 2 files changed, 201 insertions(+), 194 deletions(-) diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index c102c418..dab67504 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -2,12 +2,12 @@ const { MessageEmbed, MessageButton, MessageActionRow } = require("discord.js"); const cron = require("node-cron"); const lunchBuddyLocations = require("../data/lunch_buddy_locations"); -const maxRowButtons = 5; +const maxRowButtons = 4; const areaButtonCustomId = "AreaButton"; const locationButtonCustomId = "LocationButton"; const interactionTimeout = 10000; -const voteOriginId = "946636861256904774"; -const threadDestinationId = "946636879426617354"; +const voteOriginId = "959995388289495050"; +const threadDestinationId = "959995388289495050"; const getLocations = (area) => { for (const object of lunchBuddyLocations.locations) { @@ -31,6 +31,7 @@ const generateAreasEmbed = (areaVotes = undefined) => { value: areas.join("\n"), }); }; + const generateLocationsEmbed = (area, votes = undefined) => { const locationData = getLocations(area); const locations = locationData.sub.map( @@ -45,6 +46,7 @@ const generateLocationsEmbed = (area, votes = undefined) => { value: locations.join("\n"), }); }; + const areasList = lunchBuddyLocations.locations.map((element) => element.value); const areasButtons = lunchBuddyLocations.locations.map( (element) => @@ -112,221 +114,225 @@ module.exports = { const areaVotes = {}; const conductAreaVote = () => { - return new Promise((resolve) => { + return new Promise(async (resolve, reject) => { // Setup for voting areasList.forEach((area) => (areaVotes[area] = [])); // Fetch channel object and send voting message - client.channels.fetch(voteOriginId).then(async (voteChannel) => { - - const areaMessage = await voteChannel.send({ - embeds: [generateAreasEmbed()], - components: areasActionRows, - }); - // Setup receiving message interactions - const areaCollector = areaMessage.createMessageComponentCollector({ - filter: areasButtonsFilter, - time: interactionTimeout, - idle: interactionTimeout, - }); + const voteChannel = await client.channels.fetch(voteOriginId); - areaCollector.on("collect", async (interaction) => { - const interactorId = String(interaction.user.id); - const priorVoteOption = getVoteOption(interactorId, areaVotes); - const newOption = interaction.customId.replace(areaButtonCustomId, ""); - - let newVoteString = ` voted for ${newOption}!`; - let oldVoteString = ""; - - // Checks whether voter has previously cast vote and edits accordingly - if (priorVoteOption) { - if (priorVoteOption === newOption) { - interaction.reply({ - content: "You have already voted for this option.", - ephemeral: true, - }); - return; - } - // Removes previously cast vote - const location = areaVotes[priorVoteOption].indexOf(interactorId); - areaVotes[priorVoteOption].splice(location, 1); - - if (newOption === "Remove") { - newVoteString = " removed your vote."; - } else { - oldVoteString = ` removed your vote for ${priorVoteOption} and`; - } - } else if (newOption === "Remove") { - newVoteString = " no vote to remove."; - } + const areaMessage = await voteChannel.send({ + embeds: [generateAreasEmbed()], + components: areasActionRows, + }); - const voteString = `You have${oldVoteString}${newVoteString}`; + // Setup receiving message interactions + const areaCollector = areaMessage.createMessageComponentCollector({ + filter: areasButtonsFilter, + time: interactionTimeout, + idle: interactionTimeout, + }); - // Appends new vote if cast - if (newOption !== "Remove") { - areaVotes[newOption].push(interactorId); + areaCollector.on("collect", async (interaction) => { + const interactorId = String(interaction.user.id); + const priorVoteOption = getVoteOption(interactorId, areaVotes); + const newOption = interaction.customId.replace(areaButtonCustomId, ""); + + let newVoteString = ` voted for ${newOption}!`; + let oldVoteString = ""; + + // Checks whether voter has previously cast vote and edits accordingly + if (priorVoteOption) { + if (priorVoteOption === newOption) { + interaction.reply({ + content: "You have already voted for this option.", + ephemeral: true, + }); + return; } + // Removes previously cast vote + const location = areaVotes[priorVoteOption].indexOf(interactorId); + areaVotes[priorVoteOption].splice(location, 1); - interaction.reply({ content: voteString, ephemeral: true }); - areaMessage.edit({ embeds: [generateAreasEmbed(areaVotes)] }); - }); + if (newOption === "Remove") { + newVoteString = " removed your vote."; + } else { + oldVoteString = ` removed your vote for ${priorVoteOption} and`; + } - areaCollector.on("end", async () => { - // Removes options to vote for area - await areaMessage.edit({ components: [] }); + } else if (newOption === "Remove") { + newVoteString = " no vote to remove."; + } - let areaInfo; + const voteString = `You have${oldVoteString}${newVoteString}`; - // Finds the highest voted option, and randomises for ties - const mostVoted = getMostVoted(areaVotes); - if (mostVoted.length !== 1) { - selectedArea = mostVoted[Math.floor(Math.random() * mostVoted.length)]; - areaInfo = `Several options had the highest votes, and the area ${selectedArea} was randomly selected from the tied options.`; - } else { - selectedArea = mostVoted[0]; - areaInfo = `The area ${selectedArea} had the highest votes.`; - } + // Appends new vote if cast + if (newOption !== "Remove") { + areaVotes[newOption].push(interactorId); + } - if (areaVotes[selectedArea].length) { - await areaMessage.reply(areaInfo); - } else { - await areaMessage.reply("No votes were cast for the area."); - return; - } + interaction.reply({ content: voteString, ephemeral: true }); + areaMessage.edit({ embeds: [generateAreasEmbed(areaVotes)] }); + }); - locationData = getLocations(selectedArea); + areaCollector.on("end", async () => { + // Removes options to vote for area + await areaMessage.edit({ components: [] }); - resolve(); - }); + let areaInfo; + + // Finds the highest voted option, and randomises for ties + const mostVoted = getMostVoted(areaVotes); + + if (mostVoted.length !== 1) { + selectedArea = mostVoted[Math.floor(Math.random() * mostVoted.length)]; + areaInfo = `Several options had the highest votes, and the area ${selectedArea} was randomly selected from the tied options.`; + } else { + selectedArea = mostVoted[0]; + areaInfo = `The area ${selectedArea} had the highest votes.`; + } + + if (areaVotes[selectedArea].length) { + await areaMessage.reply(areaInfo); + } else { + await areaMessage.reply("No votes were cast for the area."); + return; + } + + locationData = getLocations(selectedArea); + + resolve(); }); }); }; const conductLocationVote = () => { - return new Promise((resolve) => { + return new Promise(async (resolve) => { const locationsList = locationData.sub.map((element) => element.name); // Fetch channel and prepare voting message - client.channels.fetch(voteOriginId).then(async (voteChannel) => { - const locationsButtons = locationData.sub.map( - (element) => - new MessageButton({ - style: "PRIMARY", - label: element.name, - customId: `${element.name}${locationButtonCustomId}`, - }), - ); - locationsButtons.push( + + const voteChannel = await client.channels.fetch(voteOriginId); + + // client.channels.fetch(voteOriginId).then(async (voteChannel) => { + const locationsButtons = locationData.sub.map( + (element) => new MessageButton({ - style: "DANGER", - label: "Remove Vote", - customId: `Remove${locationButtonCustomId}`, + style: "PRIMARY", + label: element.name, + customId: `${element.name}${locationButtonCustomId}`, + }), + ); + locationsButtons.push( + new MessageButton({ + style: "DANGER", + label: "Remove Vote", + customId: `Remove${locationButtonCustomId}`, + }), + ); + const locationsButtonsIds = locationData.sub.map( + (element) => `${element.name}${locationButtonCustomId}`, + ); + locationsButtonsIds.push(`Remove${locationButtonCustomId}`); + const locationsActionRows = []; + for (let i = 0; i < locationsButtons.length; i += maxRowButtons) { + locationsActionRows.push( + new MessageActionRow({ + components: locationsButtons.slice(i, i + maxRowButtons), }), ); - const locationsButtonsIds = locationData.sub.map( - (element) => `${element.name}${locationButtonCustomId}`, - ); - locationsButtonsIds.push(`Remove${locationButtonCustomId}`); - const locationsActionRows = []; - for (let i = 0; i < locationsButtons.length; i += maxRowButtons) { - locationsActionRows.push( - new MessageActionRow({ - components: locationsButtons.slice(i, i + maxRowButtons), - }), - ); - } + } - const locationVotes = {}; - locationsList.forEach((location) => (locationVotes[location] = [])); + const locationVotes = {}; + locationsList.forEach((location) => (locationVotes[location] = [])); - const locationMessage = await voteChannel.send({ - embeds: [generateLocationsEmbed(selectedArea)], - components: locationsActionRows, - }); + const locationMessage = await voteChannel.send({ + embeds: [generateLocationsEmbed(selectedArea)], + components: locationsActionRows, + }); - const locationsButtonsFilter = (resInteraction) => { - return locationsButtonsIds.includes(resInteraction.customId); - }; + const locationsButtonsFilter = (resInteraction) => { + return locationsButtonsIds.includes(resInteraction.customId); + }; - // Setup receiving message interactions - const locationCollector = locationMessage.createMessageComponentCollector({ - filter: locationsButtonsFilter, - time: interactionTimeout, - idle: interactionTimeout, - }); + // Setup receiving message interactions + const locationCollector = locationMessage.createMessageComponentCollector({ + filter: locationsButtonsFilter, + time: interactionTimeout, + idle: interactionTimeout, + }); - locationCollector.on("collect", async (interaction) => { - const interactorId = String(interaction.user.id); - const priorVoteOption = getVoteOption(interactorId, locationVotes); - const newOption = interaction.customId.replace(locationButtonCustomId, ""); - - let newVoteString = ` voted for ${newOption}!`; - let oldVoteString = ""; - - // Checks whether voter has previously cast vote and edits accordingly - if (priorVoteOption) { - if (priorVoteOption === newOption) { - interaction.reply({ - content: "You have already voted for this option.", - ephemeral: true, - }); - return; - } - // Removes previously cast vote - const location = locationVotes[priorVoteOption].indexOf(interactorId); - locationVotes[priorVoteOption].splice(location, 1); - - if (newOption === "Remove") { - newVoteString = " removed your vote."; - } else { - oldVoteString = ` removed your vote for ${priorVoteOption} and`; - } - } else if (newOption === "Remove") { - newVoteString = " no vote to remove."; + locationCollector.on("collect", async (interaction) => { + const interactorId = String(interaction.user.id); + const priorVoteOption = getVoteOption(interactorId, locationVotes); + const newOption = interaction.customId.replace(locationButtonCustomId, ""); + + let newVoteString = ` voted for ${newOption}!`; + let oldVoteString = ""; + + // Checks whether voter has previously cast vote and edits accordingly + if (priorVoteOption) { + if (priorVoteOption === newOption) { + interaction.reply({ + content: "You have already voted for this option.", + ephemeral: true, + }); + return; } + // Removes previously cast vote + const location = locationVotes[priorVoteOption].indexOf(interactorId); + locationVotes[priorVoteOption].splice(location, 1); - const voteString = `You have${oldVoteString}${newVoteString}`; - - // Appends new vote if cast - if (newOption !== "Remove") { - locationVotes[newOption].push(interactorId); + if (newOption === "Remove") { + newVoteString = " removed your vote."; + } else { + oldVoteString = ` removed your vote for ${priorVoteOption} and`; } + } else if (newOption === "Remove") { + newVoteString = " no vote to remove."; + } + + const voteString = `You have${oldVoteString}${newVoteString}`; - interaction.reply({ content: voteString, ephemeral: true }); - locationMessage.edit({ - embeds: [generateLocationsEmbed(selectedArea, locationVotes)], - }); + // Appends new vote if cast + if (newOption !== "Remove") { + locationVotes[newOption].push(interactorId); + } + + interaction.reply({ content: voteString, ephemeral: true }); + locationMessage.edit({ + embeds: [generateLocationsEmbed(selectedArea, locationVotes)], }); + }); - locationCollector.on("end", async () => { - // Removes options to vote for location - locationMessage.edit({ components: [] }); - - let locationInfo; - - - // Finds the highest voted option, and randomises for ties - const mostVotedLocation = getMostVoted(locationVotes); - if (mostVotedLocation.length !== 1) { - selectedLocation = - mostVotedLocation[ - Math.floor(Math.random() * mostVotedLocation.length) - ]; - locationInfo = `Several options had the highest votes, and the location ${selectedLocation} was randomly selected from the tied options.`; - } else { - selectedLocation = mostVotedLocation[0]; - locationInfo = `The location ${selectedLocation} had the highest votes.`; - } + locationCollector.on("end", async () => { + // Removes options to vote for location + locationMessage.edit({ components: [] }); - if (locationVotes[selectedLocation].length) { - await locationMessage.reply(locationInfo); - } else { - await locationMessage.reply("No votes were cast for the location."); - return; - } + let locationInfo; + - resolve(); - }); + // Finds the highest voted option, and randomises for ties + const mostVotedLocation = getMostVoted(locationVotes); + if (mostVotedLocation.length !== 1) { + selectedLocation = + mostVotedLocation[ + Math.floor(Math.random() * mostVotedLocation.length) + ]; + locationInfo = `Several options had the highest votes, and the location ${selectedLocation} was randomly selected from the tied options.`; + } else { + selectedLocation = mostVotedLocation[0]; + locationInfo = `The location ${selectedLocation} had the highest votes.`; + } + + if (locationVotes[selectedLocation].length) { + await locationMessage.reply(locationInfo); + } else { + await locationMessage.reply("No votes were cast for the location."); + return; + } + + resolve(); }); }); }; @@ -341,9 +347,10 @@ module.exports = { autoArchiveDuration: 1440 }); - // Adds all area voters to thread - areaVotes[selectedArea].forEach(async (id) => { - await thread.members.add(id); + Object.values(areaVotes).forEach(async (area) => { + area.forEach(async (id) => { + await thread.members.add(id); + }) }); client.channels.fetch(voteOriginId).then(async (channel) => { diff --git a/events/tictactoeButton.js b/events/tictactoeButton.js index 43511d57..9b42f89c 100644 --- a/events/tictactoeButton.js +++ b/events/tictactoeButton.js @@ -1,13 +1,13 @@ -const { handleGameButton } = require("../lib/tictactoe/tttHelper"); +// const { handleGameButton } = require("../lib/tictactoe/tttHelper"); -module.exports = { - once: false, - name: "interactionCreate", - execute(interaction) { - if (interaction.isButton() && interaction.message.interaction.commandName == "tictactoe") { - handleGameButton(interaction); - } else { - return; - } - }, -}; +// module.exports = { +// once: false, +// name: "interactionCreate", +// execute(interaction) { +// if (interaction.isButton() && interaction.message.interaction.commandName == "tictactoe") { +// handleGameButton(interaction); +// } else { +// return; +// } +// }, +// }; From 1cb8e88b174c72970c40ca929750e43d19e0644a Mon Sep 17 00:00:00 2001 From: mi-mott <98304083+mi-mott@users.noreply.github.com> Date: Sat, 27 May 2023 16:23:50 +1000 Subject: [PATCH 09/19] Lint fix --- events/lunch_buddy.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index dab67504..0882c636 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -114,7 +114,7 @@ module.exports = { const areaVotes = {}; const conductAreaVote = () => { - return new Promise(async (resolve, reject) => { + return new Promise(async (resolve) => { // Setup for voting areasList.forEach((area) => (areaVotes[area] = [])); // Fetch channel object and send voting message @@ -159,7 +159,6 @@ module.exports = { } else { oldVoteString = ` removed your vote for ${priorVoteOption} and`; } - } else if (newOption === "Remove") { newVoteString = " no vote to remove."; } @@ -213,7 +212,7 @@ module.exports = { // Fetch channel and prepare voting message const voteChannel = await client.channels.fetch(voteOriginId); - + // client.channels.fetch(voteOriginId).then(async (voteChannel) => { const locationsButtons = locationData.sub.map( (element) => @@ -310,7 +309,6 @@ module.exports = { locationMessage.edit({ components: [] }); let locationInfo; - // Finds the highest voted option, and randomises for ties const mostVotedLocation = getMostVoted(locationVotes); @@ -338,23 +336,25 @@ module.exports = { }; const createMeetupThread = () => { - const dateString = new Date().toLocaleDateString('en-AU') + const dateString = new Date().toLocaleDateString("en-AU"); - client.channels.fetch(threadDestinationId).then( async (channel) => { + client.channels.fetch(threadDestinationId).then(async (channel) => { // Creates thread which expires after 1 day const thread = await channel.threads.create({ name: `${dateString}-${selectedLocation}`, - autoArchiveDuration: 1440 + autoArchiveDuration: 1440, }); Object.values(areaVotes).forEach(async (area) => { area.forEach(async (id) => { await thread.members.add(id); - }) + }); }); - client.channels.fetch(voteOriginId).then(async (channel) => { - await channel.send(`Created a thread for today's lunch buddy meet: ${thread}`) + client.channels.fetch(voteOriginId).then(async (threadId) => { + await threadId.send( + `Created a thread for today's lunch buddy meet: ${thread}`, + ); }); }); }; From 2a532ad8e872998d7f57f64c5043aa2382a101e0 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Fri, 25 Aug 2023 12:53:19 +1000 Subject: [PATCH 10/19] Removed promises and adjusted placement of vote function calls --- events/lunch_buddy.js | 357 ++++++++++++++++++++---------------------- 1 file changed, 172 insertions(+), 185 deletions(-) diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index 0882c636..4977abf3 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -107,231 +107,220 @@ module.exports = { name: "ready", once: true, execute(client) { - cron.schedule("* * * * *", async function () { + cron.schedule("* * * * *", async () => { let locationData; let selectedArea; let selectedLocation; const areaVotes = {}; - const conductAreaVote = () => { - return new Promise(async (resolve) => { - // Setup for voting - areasList.forEach((area) => (areaVotes[area] = [])); - // Fetch channel object and send voting message + const conductAreaVote = async () => { + // Setup for voting + areasList.forEach((area) => (areaVotes[area] = [])); - const voteChannel = await client.channels.fetch(voteOriginId); + // Fetch channel object and send voting message + const voteChannel = await client.channels.fetch(voteOriginId); - const areaMessage = await voteChannel.send({ - embeds: [generateAreasEmbed()], - components: areasActionRows, - }); + const areaMessage = await voteChannel.send({ + embeds: [generateAreasEmbed()], + components: areasActionRows, + }); - // Setup receiving message interactions - const areaCollector = areaMessage.createMessageComponentCollector({ - filter: areasButtonsFilter, - time: interactionTimeout, - idle: interactionTimeout, - }); + // Setup receiving message interactions + const areaCollector = areaMessage.createMessageComponentCollector({ + filter: areasButtonsFilter, + time: interactionTimeout, + idle: interactionTimeout, + }); - areaCollector.on("collect", async (interaction) => { - const interactorId = String(interaction.user.id); - const priorVoteOption = getVoteOption(interactorId, areaVotes); - const newOption = interaction.customId.replace(areaButtonCustomId, ""); - - let newVoteString = ` voted for ${newOption}!`; - let oldVoteString = ""; - - // Checks whether voter has previously cast vote and edits accordingly - if (priorVoteOption) { - if (priorVoteOption === newOption) { - interaction.reply({ - content: "You have already voted for this option.", - ephemeral: true, - }); - return; - } - // Removes previously cast vote - const location = areaVotes[priorVoteOption].indexOf(interactorId); - areaVotes[priorVoteOption].splice(location, 1); - - if (newOption === "Remove") { - newVoteString = " removed your vote."; - } else { - oldVoteString = ` removed your vote for ${priorVoteOption} and`; - } - } else if (newOption === "Remove") { - newVoteString = " no vote to remove."; + areaCollector.on("collect", async (interaction) => { + const interactorId = String(interaction.user.id); + const priorVoteOption = getVoteOption(interactorId, areaVotes); + const newOption = interaction.customId.replace(areaButtonCustomId, ""); + + let newVoteString = ` voted for ${newOption}!`; + let oldVoteString = ""; + + // Checks whether voter has previously cast vote and edits accordingly + if (priorVoteOption) { + if (priorVoteOption === newOption) { + interaction.reply({ + content: "You have already voted for this option.", + ephemeral: true, + }); + return; } + // Removes previously cast vote + const location = areaVotes[priorVoteOption].indexOf(interactorId); + areaVotes[priorVoteOption].splice(location, 1); - const voteString = `You have${oldVoteString}${newVoteString}`; - - // Appends new vote if cast - if (newOption !== "Remove") { - areaVotes[newOption].push(interactorId); + if (newOption === "Remove") { + newVoteString = " removed your vote."; + } else { + oldVoteString = ` removed your vote for ${priorVoteOption} and`; } + } else if (newOption === "Remove") { + newVoteString = " no vote to remove."; + } - interaction.reply({ content: voteString, ephemeral: true }); - areaMessage.edit({ embeds: [generateAreasEmbed(areaVotes)] }); - }); + const voteString = `You have${oldVoteString}${newVoteString}`; - areaCollector.on("end", async () => { - // Removes options to vote for area - await areaMessage.edit({ components: [] }); + // Appends new vote if cast + if (newOption !== "Remove") { + areaVotes[newOption].push(interactorId); + } - let areaInfo; + interaction.reply({ content: voteString, ephemeral: true }); + areaMessage.edit({ embeds: [generateAreasEmbed(areaVotes)] }); + }); - // Finds the highest voted option, and randomises for ties - const mostVoted = getMostVoted(areaVotes); + areaCollector.on("end", async () => { + // Removes options to vote for area + await areaMessage.edit({ components: [] }); - if (mostVoted.length !== 1) { - selectedArea = mostVoted[Math.floor(Math.random() * mostVoted.length)]; - areaInfo = `Several options had the highest votes, and the area ${selectedArea} was randomly selected from the tied options.`; - } else { - selectedArea = mostVoted[0]; - areaInfo = `The area ${selectedArea} had the highest votes.`; - } + let areaInfo; - if (areaVotes[selectedArea].length) { - await areaMessage.reply(areaInfo); - } else { - await areaMessage.reply("No votes were cast for the area."); - return; - } + // Finds the highest voted option, and randomises for ties + const mostVoted = getMostVoted(areaVotes); - locationData = getLocations(selectedArea); + if (mostVoted.length !== 1) { + selectedArea = mostVoted[Math.floor(Math.random() * mostVoted.length)]; + areaInfo = `Several options had the highest votes, and the area ${selectedArea} was randomly selected from the tied options.`; + } else { + selectedArea = mostVoted[0]; + areaInfo = `The area ${selectedArea} had the highest votes.`; + } - resolve(); - }); + if (areaVotes[selectedArea].length) { + await areaMessage.reply(areaInfo); + locationData = getLocations(selectedArea); + await conductLocationVote(); + } else { + await areaMessage.reply("No votes were cast for the area."); + } }); }; - const conductLocationVote = () => { - return new Promise(async (resolve) => { - const locationsList = locationData.sub.map((element) => element.name); + const conductLocationVote = async () => { + const locationsList = locationData.sub.map((element) => element.name); - // Fetch channel and prepare voting message + // Fetch channel and prepare voting message - const voteChannel = await client.channels.fetch(voteOriginId); + const voteChannel = await client.channels.fetch(voteOriginId); - // client.channels.fetch(voteOriginId).then(async (voteChannel) => { - const locationsButtons = locationData.sub.map( - (element) => - new MessageButton({ - style: "PRIMARY", - label: element.name, - customId: `${element.name}${locationButtonCustomId}`, - }), - ); - locationsButtons.push( + // client.channels.fetch(voteOriginId).then(async (voteChannel) => { + const locationsButtons = locationData.sub.map( + (element) => new MessageButton({ - style: "DANGER", - label: "Remove Vote", - customId: `Remove${locationButtonCustomId}`, + style: "PRIMARY", + label: element.name, + customId: `${element.name}${locationButtonCustomId}`, + }), + ); + locationsButtons.push( + new MessageButton({ + style: "DANGER", + label: "Remove Vote", + customId: `Remove${locationButtonCustomId}`, + }), + ); + const locationsButtonsIds = locationData.sub.map( + (element) => `${element.name}${locationButtonCustomId}`, + ); + locationsButtonsIds.push(`Remove${locationButtonCustomId}`); + const locationsActionRows = []; + for (let i = 0; i < locationsButtons.length; i += maxRowButtons) { + locationsActionRows.push( + new MessageActionRow({ + components: locationsButtons.slice(i, i + maxRowButtons), }), ); - const locationsButtonsIds = locationData.sub.map( - (element) => `${element.name}${locationButtonCustomId}`, - ); - locationsButtonsIds.push(`Remove${locationButtonCustomId}`); - const locationsActionRows = []; - for (let i = 0; i < locationsButtons.length; i += maxRowButtons) { - locationsActionRows.push( - new MessageActionRow({ - components: locationsButtons.slice(i, i + maxRowButtons), - }), - ); - } + } - const locationVotes = {}; - locationsList.forEach((location) => (locationVotes[location] = [])); + const locationVotes = {}; + locationsList.forEach((location) => (locationVotes[location] = [])); - const locationMessage = await voteChannel.send({ - embeds: [generateLocationsEmbed(selectedArea)], - components: locationsActionRows, - }); + const locationMessage = await voteChannel.send({ + embeds: [generateLocationsEmbed(selectedArea)], + components: locationsActionRows, + }); - const locationsButtonsFilter = (resInteraction) => { - return locationsButtonsIds.includes(resInteraction.customId); - }; + const locationsButtonsFilter = (resInteraction) => { + return locationsButtonsIds.includes(resInteraction.customId); + }; - // Setup receiving message interactions - const locationCollector = locationMessage.createMessageComponentCollector({ - filter: locationsButtonsFilter, - time: interactionTimeout, - idle: interactionTimeout, - }); + // Setup receiving message interactions + const locationCollector = locationMessage.createMessageComponentCollector({ + filter: locationsButtonsFilter, + time: interactionTimeout, + idle: interactionTimeout, + }); - locationCollector.on("collect", async (interaction) => { - const interactorId = String(interaction.user.id); - const priorVoteOption = getVoteOption(interactorId, locationVotes); - const newOption = interaction.customId.replace(locationButtonCustomId, ""); - - let newVoteString = ` voted for ${newOption}!`; - let oldVoteString = ""; - - // Checks whether voter has previously cast vote and edits accordingly - if (priorVoteOption) { - if (priorVoteOption === newOption) { - interaction.reply({ - content: "You have already voted for this option.", - ephemeral: true, - }); - return; - } - // Removes previously cast vote - const location = locationVotes[priorVoteOption].indexOf(interactorId); - locationVotes[priorVoteOption].splice(location, 1); - - if (newOption === "Remove") { - newVoteString = " removed your vote."; - } else { - oldVoteString = ` removed your vote for ${priorVoteOption} and`; - } - } else if (newOption === "Remove") { - newVoteString = " no vote to remove."; + locationCollector.on("collect", async (interaction) => { + const interactorId = String(interaction.user.id); + const priorVoteOption = getVoteOption(interactorId, locationVotes); + const newOption = interaction.customId.replace(locationButtonCustomId, ""); + + let newVoteString = ` voted for ${newOption}!`; + let oldVoteString = ""; + + // Checks whether voter has previously cast vote and edits accordingly + if (priorVoteOption) { + if (priorVoteOption === newOption) { + interaction.reply({ + content: "You have already voted for this option.", + ephemeral: true, + }); + return; } + // Removes previously cast vote + const location = locationVotes[priorVoteOption].indexOf(interactorId); + locationVotes[priorVoteOption].splice(location, 1); - const voteString = `You have${oldVoteString}${newVoteString}`; - - // Appends new vote if cast - if (newOption !== "Remove") { - locationVotes[newOption].push(interactorId); + if (newOption === "Remove") { + newVoteString = " removed your vote."; + } else { + oldVoteString = ` removed your vote for ${priorVoteOption} and`; } + } else if (newOption === "Remove") { + newVoteString = " no vote to remove."; + } - interaction.reply({ content: voteString, ephemeral: true }); - locationMessage.edit({ - embeds: [generateLocationsEmbed(selectedArea, locationVotes)], - }); - }); - - locationCollector.on("end", async () => { - // Removes options to vote for location - locationMessage.edit({ components: [] }); + const voteString = `You have${oldVoteString}${newVoteString}`; - let locationInfo; + // Appends new vote if cast + if (newOption !== "Remove") { + locationVotes[newOption].push(interactorId); + } - // Finds the highest voted option, and randomises for ties - const mostVotedLocation = getMostVoted(locationVotes); - if (mostVotedLocation.length !== 1) { - selectedLocation = - mostVotedLocation[ - Math.floor(Math.random() * mostVotedLocation.length) - ]; - locationInfo = `Several options had the highest votes, and the location ${selectedLocation} was randomly selected from the tied options.`; - } else { - selectedLocation = mostVotedLocation[0]; - locationInfo = `The location ${selectedLocation} had the highest votes.`; - } + interaction.reply({ content: voteString, ephemeral: true }); + locationMessage.edit({ + embeds: [generateLocationsEmbed(selectedArea, locationVotes)], + }); + }); - if (locationVotes[selectedLocation].length) { - await locationMessage.reply(locationInfo); - } else { - await locationMessage.reply("No votes were cast for the location."); - return; - } + locationCollector.on("end", async () => { + // Removes options to vote for location + locationMessage.edit({ components: [] }); + + let locationInfo; + + // Finds the highest voted option, and randomises for ties + const mostVotedLocation = getMostVoted(locationVotes); + if (mostVotedLocation.length !== 1) { + selectedLocation = + mostVotedLocation[Math.floor(Math.random() * mostVotedLocation.length)]; + locationInfo = `Several options had the highest votes, and the location ${selectedLocation} was randomly selected from the tied options.`; + } else { + selectedLocation = mostVotedLocation[0]; + locationInfo = `The location ${selectedLocation} had the highest votes.`; + } - resolve(); - }); + if (locationVotes[selectedLocation].length) { + await locationMessage.reply(locationInfo); + createMeetupThread(); + } else { + await locationMessage.reply("No votes were cast for the location."); + } }); }; @@ -360,8 +349,6 @@ module.exports = { }; await conductAreaVote(); - await conductLocationVote(); - createMeetupThread(); }); }, }; From 9819756fefcf95a69b2ba353eaaceef3e713a804 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Fri, 1 Sep 2023 10:26:19 +1000 Subject: [PATCH 11/19] Adjusted thread users, append location vote pings --- events/lunch_buddy.js | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index 4977abf3..1444896b 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -112,6 +112,7 @@ module.exports = { let selectedArea; let selectedLocation; const areaVotes = {}; + const locationVotes = {}; const conductAreaVote = async () => { // Setup for voting @@ -236,10 +237,21 @@ module.exports = { ); } - const locationVotes = {}; locationsList.forEach((location) => (locationVotes[location] = [])); + const toPing = []; + Object.values(areaVotes).forEach((area) => { + area.forEach((id) => { + toPing.push(id) + }); + }); + + const pingStr = toPing.reduce((str, id) => { + return str + `<@${id}>`; + }, "||") + "||"; + const locationMessage = await voteChannel.send({ + content: pingStr, embeds: [generateLocationsEmbed(selectedArea)], components: locationsActionRows, }); @@ -334,11 +346,21 @@ module.exports = { autoArchiveDuration: 1440, }); - Object.values(areaVotes).forEach(async (area) => { - area.forEach(async (id) => { - await thread.members.add(id); + const toAdd = []; + Object.values(areaVotes).forEach((area) => { + area.forEach((id) => { + if (!toAdd.includes(id)) toAdd.push(id); }); }); + Object.values(locationVotes).forEach((location) => { + location.forEach((id) => { + if (!toAdd.includes(id)) toAdd.push(id); + }) + }) + + toAdd.forEach(async (id) => { + await thread.members.add(id); + }) client.channels.fetch(voteOriginId).then(async (threadId) => { await threadId.send( From 12d6c034ceb07e21b99fee736a33c7c552db6550 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Fri, 1 Sep 2023 11:07:45 +1000 Subject: [PATCH 12/19] Linting fixes --- events/lunch_buddy.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index 1444896b..f84dee6d 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -242,13 +242,11 @@ module.exports = { const toPing = []; Object.values(areaVotes).forEach((area) => { area.forEach((id) => { - toPing.push(id) + toPing.push(id); }); }); - const pingStr = toPing.reduce((str, id) => { - return str + `<@${id}>`; - }, "||") + "||"; + const pingStr = toPing.reduce((str, id) => str + `<@${id}>`, "||") + "||"; const locationMessage = await voteChannel.send({ content: pingStr, @@ -355,12 +353,12 @@ module.exports = { Object.values(locationVotes).forEach((location) => { location.forEach((id) => { if (!toAdd.includes(id)) toAdd.push(id); - }) - }) + }); + }); toAdd.forEach(async (id) => { await thread.members.add(id); - }) + }); client.channels.fetch(voteOriginId).then(async (threadId) => { await threadId.send( From 9536332dfedb3343a5c0d0f028b092e2acb83dd8 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Sat, 9 Sep 2023 09:22:20 +1000 Subject: [PATCH 13/19] Locations Update --- data/lunch_buddy_locations.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/data/lunch_buddy_locations.js b/data/lunch_buddy_locations.js index 6aff5770..f7cbd7e8 100644 --- a/data/lunch_buddy_locations.js +++ b/data/lunch_buddy_locations.js @@ -52,10 +52,19 @@ const locations = [ ], }, { - value: "Quadrangle Food Court (under renovation)", + value: "Quadrangle Food Court", sub: [ { - name: "Plume Cafe (Open)", + name: "Soul Origin", + }, + { + name: "PappaRich", + }, + { + name: "Nene Chicken", + }, + { + name: "Plume Cafe", }, ], }, @@ -83,6 +92,9 @@ const locations = [ { name: "Campus Village Cafe", }, + { + name: "Home Ground Kiosk", + }, ], }, { From 72f9cd19b9328a178e81110fc118c927e0fa652e Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Sat, 7 Oct 2023 15:36:24 +1100 Subject: [PATCH 14/19] Adds "any" option and append additional vote info --- events/lunch_buddy.js | 64 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index f84dee6d..b35151b5 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -9,6 +9,11 @@ const interactionTimeout = 10000; const voteOriginId = "959995388289495050"; const threadDestinationId = "959995388289495050"; +const generalAreaInfo = + "This lunch buddy vote commenced at 10am, you must vote for the area by 11am. A location vote will run afterwards until 12pm."; +const generalLocationInfo = + "This lunch buddy vote commenced at 10am, you must vote for the location by 12pm, when one will be chosen."; + const getLocations = (area) => { for (const object of lunchBuddyLocations.locations) { if (object.value === area) { @@ -22,14 +27,21 @@ const generateAreasEmbed = (areaVotes = undefined) => { const areas = lunchBuddyLocations.locations.map( (element) => `${element.value}: ${areaVotes ? areaVotes[element.value].length : 0}`, ); + areas.push(`Any: ${areaVotes ? areaVotes["Any"].length : 0}`); return new MessageEmbed() .setTitle("Meetup Area Selection") .setColor(0x0099ff) .setDescription("Please select an option below to vote for that area!") - .setFields({ - name: "Options", - value: areas.join("\n"), - }); + .setFields( + { + name: "Info", + value: generalAreaInfo, + }, + { + name: "Options", + value: areas.join("\n"), + }, + ); }; const generateLocationsEmbed = (area, votes = undefined) => { @@ -37,17 +49,25 @@ const generateLocationsEmbed = (area, votes = undefined) => { const locations = locationData.sub.map( (element) => `${element.name}: ${votes ? votes[element.name].length : 0}`, ); + locations.push(`Any: ${votes ? votes["Any"].length : 0}`); return new MessageEmbed() .setTitle(`Meetup Location Selection - ${area}`) .setColor(0x0099ff) .setDescription("Please select an option below to vote for that location!") - .setFields({ - name: "Options", - value: locations.join("\n"), - }); + .setFields( + { + name: "Info", + value: generalLocationInfo, + }, + { + name: "Options", + value: locations.join("\n"), + }, + ); }; const areasList = lunchBuddyLocations.locations.map((element) => element.value); +areasList.push("Any"); const areasButtons = lunchBuddyLocations.locations.map( (element) => new MessageButton({ @@ -56,6 +76,13 @@ const areasButtons = lunchBuddyLocations.locations.map( customId: `${element.value}${areaButtonCustomId}`, }), ); +areasButtons.push( + new MessageButton({ + style: "PRIMARY", + label: "Surprise Me!", + customId: `Any${areaButtonCustomId}`, + }), +); areasButtons.push( new MessageButton({ style: "DANGER", @@ -66,6 +93,7 @@ areasButtons.push( const areasButtonsIds = lunchBuddyLocations.locations.map( (element) => `${element.value}${areaButtonCustomId}`, ); +areasButtonsIds.push(`Any${areaButtonCustomId}`); areasButtonsIds.push(`Remove${areaButtonCustomId}`); const areasActionRows = []; for (let i = 0; i < areasButtons.length; i += maxRowButtons) { @@ -90,7 +118,10 @@ const getVoteOption = (userId, votes) => { const getMostVoted = (votes) => { let maxValue = 0; let results = []; + for (const option of Object.keys(votes)) { + if (option == "Any") continue; + const optionVotes = votes[option].length; if (optionVotes > maxValue) { maxValue = optionVotes; @@ -191,7 +222,7 @@ module.exports = { areaInfo = `The area ${selectedArea} had the highest votes.`; } - if (areaVotes[selectedArea].length) { + if (areaVotes[selectedArea].length || areaVotes["Any"].length) { await areaMessage.reply(areaInfo); locationData = getLocations(selectedArea); await conductLocationVote(); @@ -203,6 +234,7 @@ module.exports = { const conductLocationVote = async () => { const locationsList = locationData.sub.map((element) => element.name); + locationsList.push("Any"); // Fetch channel and prepare voting message @@ -217,6 +249,13 @@ module.exports = { customId: `${element.name}${locationButtonCustomId}`, }), ); + locationsButtons.push( + new MessageButton({ + style: "PRIMARY", + label: "Surprise Me!", + customId: `Any${locationButtonCustomId}`, + }), + ); locationsButtons.push( new MessageButton({ style: "DANGER", @@ -227,6 +266,7 @@ module.exports = { const locationsButtonsIds = locationData.sub.map( (element) => `${element.name}${locationButtonCustomId}`, ); + locationsButtonsIds.push(`Any${locationButtonCustomId}`); locationsButtonsIds.push(`Remove${locationButtonCustomId}`); const locationsActionRows = []; for (let i = 0; i < locationsButtons.length; i += maxRowButtons) { @@ -246,7 +286,7 @@ module.exports = { }); }); - const pingStr = toPing.reduce((str, id) => str + `<@${id}>`, "||") + "||"; + const pingStr = toPing.reduce((str, id) => str + `<@${id}>`, ""); const locationMessage = await voteChannel.send({ content: pingStr, @@ -325,7 +365,7 @@ module.exports = { locationInfo = `The location ${selectedLocation} had the highest votes.`; } - if (locationVotes[selectedLocation].length) { + if (locationVotes[selectedLocation].length || locationVotes["Any"].length) { await locationMessage.reply(locationInfo); createMeetupThread(); } else { @@ -340,7 +380,7 @@ module.exports = { client.channels.fetch(threadDestinationId).then(async (channel) => { // Creates thread which expires after 1 day const thread = await channel.threads.create({ - name: `${dateString}-${selectedLocation}`, + name: `${dateString} - ${selectedLocation}`, autoArchiveDuration: 1440, }); From a415a947340383109824b5b5c39e6dc7875129e5 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Tue, 24 Oct 2023 12:02:11 +1100 Subject: [PATCH 15/19] Appended code for live run timing --- events/lunch_buddy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index b35151b5..e55af2a0 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -5,7 +5,7 @@ const lunchBuddyLocations = require("../data/lunch_buddy_locations"); const maxRowButtons = 4; const areaButtonCustomId = "AreaButton"; const locationButtonCustomId = "LocationButton"; -const interactionTimeout = 10000; +const interactionTimeout = 1000 * 60 * 60; const voteOriginId = "959995388289495050"; const threadDestinationId = "959995388289495050"; @@ -138,7 +138,7 @@ module.exports = { name: "ready", once: true, execute(client) { - cron.schedule("* * * * *", async () => { + cron.schedule("0 10 * * *", async () => { let locationData; let selectedArea; let selectedLocation; From 051144a4a76187dd7811287ead830576b6324129 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Wed, 17 Jan 2024 21:45:44 +1100 Subject: [PATCH 16/19] Update to use config file --- config/lunch_buddy.json | 6 ++++++ events/lunch_buddy.js | 15 +++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 config/lunch_buddy.json diff --git a/config/lunch_buddy.json b/config/lunch_buddy.json new file mode 100644 index 00000000..1a98b380 --- /dev/null +++ b/config/lunch_buddy.json @@ -0,0 +1,6 @@ +{ + "voteOriginId": "959995388289495050", + "threadDestinationId": "959995388289495050", + "interactionTimeout": 360000, + "cronString": "0 10 * * *" +} \ No newline at end of file diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index e55af2a0..19d74618 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -1,13 +1,16 @@ const { MessageEmbed, MessageButton, MessageActionRow } = require("discord.js"); const cron = require("node-cron"); const lunchBuddyLocations = require("../data/lunch_buddy_locations"); +const config = require("../config/lunch_buddy.json"); const maxRowButtons = 4; const areaButtonCustomId = "AreaButton"; const locationButtonCustomId = "LocationButton"; -const interactionTimeout = 1000 * 60 * 60; -const voteOriginId = "959995388289495050"; -const threadDestinationId = "959995388289495050"; + +const voteOriginId = config.voteOriginId; +const threadDestinationId = config.threadDestinationId; +const interactionTimeout = config.interactionTimeout; +const cronString = config.cronString; const generalAreaInfo = "This lunch buddy vote commenced at 10am, you must vote for the area by 11am. A location vote will run afterwards until 12pm."; @@ -23,7 +26,7 @@ const getLocations = (area) => { return undefined; }; -const generateAreasEmbed = (areaVotes = undefined) => { +const generateAreasEmbed = (areaVotes) => { const areas = lunchBuddyLocations.locations.map( (element) => `${element.value}: ${areaVotes ? areaVotes[element.value].length : 0}`, ); @@ -44,7 +47,7 @@ const generateAreasEmbed = (areaVotes = undefined) => { ); }; -const generateLocationsEmbed = (area, votes = undefined) => { +const generateLocationsEmbed = (area, votes) => { const locationData = getLocations(area); const locations = locationData.sub.map( (element) => `${element.name}: ${votes ? votes[element.name].length : 0}`, @@ -138,7 +141,7 @@ module.exports = { name: "ready", once: true, execute(client) { - cron.schedule("0 10 * * *", async () => { + cron.schedule(cronString, async () => { let locationData; let selectedArea; let selectedLocation; From 310ccea068196f0b888fa677a7e7fbe8057f5509 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Wed, 17 Jan 2024 21:50:57 +1100 Subject: [PATCH 17/19] Allow disabling of feature without editing code and disable --- config/lunch_buddy.json | 2 +- events/lunch_buddy.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config/lunch_buddy.json b/config/lunch_buddy.json index 1a98b380..53e72a9b 100644 --- a/config/lunch_buddy.json +++ b/config/lunch_buddy.json @@ -2,5 +2,5 @@ "voteOriginId": "959995388289495050", "threadDestinationId": "959995388289495050", "interactionTimeout": 360000, - "cronString": "0 10 * * *" + "cronString": "" } \ No newline at end of file diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index 19d74618..380fca30 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -141,6 +141,11 @@ module.exports = { name: "ready", once: true, execute(client) { + // Quick return if any config is not setup + if (!voteOriginId || !threadDestinationId || !interactionTimeout || !cronString) { + return; + } + cron.schedule(cronString, async () => { let locationData; let selectedArea; From 541b8f53d68c78cb83dace4206138ef4e010b413 Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Sun, 21 Jan 2024 23:02:44 +1100 Subject: [PATCH 18/19] Minor adjustment to readme and npm commands --- README.md | 5 +++-- package.json | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 36f29917..35c1e2f5 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,11 @@ - `DISCORD_TOKEN` with the token of the bot - `APP_ID` with the ID of the bot application - Install dependencies with `npm install` -- Register slash commands with `node deploy-commands.js` or `npm run de` +- Register slash commands with `npm run deploy` or `node deploy-commands.js` +- Ensure a PostgreSQL database is setup according to "config/database.yml" - Start the bot with `node index.js` ## Running the bot with Nodemon - Nodemon has been installed, this addition allows for continuous integration with and hot reloads the bot upon saving. -- Run the bot with Nodemon using npm run server \ No newline at end of file +- Run the bot with Nodemon using `npm run server` \ No newline at end of file diff --git a/package.json b/package.json index a065fbf4..1711f0a3 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "lint": "eslint . --ext .js", "lint:fix": "eslint --fix . --ext .js", "test": "echo \"Error: no test specified\" && exit 1", - "de": "node deploy-commands.js", + "deploy": "node deploy-commands.js", "start": "node index.js", "server": "nodemon index.js" }, From 3d5a97eccdc10c592eaad053d4970a2479cb277d Mon Sep 17 00:00:00 2001 From: Wolfdragon24 Date: Sun, 21 Jan 2024 23:12:32 +1100 Subject: [PATCH 19/19] Appended clarifying comment regarding edge case of only any votes --- events/lunch_buddy.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/events/lunch_buddy.js b/events/lunch_buddy.js index 380fca30..1063a4bd 100644 --- a/events/lunch_buddy.js +++ b/events/lunch_buddy.js @@ -122,6 +122,8 @@ const getMostVoted = (votes) => { let maxValue = 0; let results = []; + // Where only "Any" votes are present, all options will be returned as their + // vote length equals the maxValue variable of 0 for (const option of Object.keys(votes)) { if (option == "Any") continue;