Compare commits
41 Commits
Author | SHA1 | Date |
---|---|---|
|
ebe707ae26 | |
|
6dab4b64b0 | |
|
c7d12c25f4 | |
|
b2c821991d | |
|
841382df3d | |
|
51db47c828 | |
|
1a29eb7f33 | |
|
0b8ae5c4e7 | |
|
073f8339ee | |
|
f0a3e7d0da | |
|
3d72e4b586 | |
|
ec6781afc9 | |
|
ebcc7d4a31 | |
|
434599e411 | |
|
ef70de972a | |
|
0a2a1259be | |
|
8f5dc6a1e6 | |
|
ee09ad8c9c | |
|
ee501e4333 | |
|
acc168673a | |
|
9869a602af | |
|
87aed21868 | |
|
a7ecac486b | |
|
2e3435db51 | |
|
f4c10e372d | |
|
74c5c6e4e9 | |
|
cd95894691 | |
|
123aaa89a0 | |
|
05ac1a79dd | |
|
5ccccae1f4 | |
|
0b8ac79e5c | |
|
6a951dff06 | |
|
69e9ba6a6e | |
|
d36304a774 | |
|
5ed49c6cab | |
|
9677a886d9 | |
|
bc5f7a0473 | |
|
f1767c915c | |
|
d8b5f010c2 | |
|
5a8cd8e8bb | |
|
7f7f7e2445 |
|
@ -0,0 +1,5 @@
|
|||
* @burn-e99
|
||||
|
||||
config.example.ts @davidopluslau
|
||||
README.md @davidopluslau
|
||||
src/buttons/event-creation/activities.ts @davidopluslau
|
|
@ -0,0 +1,42 @@
|
|||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
# This workflow will install Deno then run `deno lint` and `deno test`.
|
||||
# For more information see: https://github.com/denoland/setup-deno
|
||||
|
||||
name: Deno
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
pull_request:
|
||||
branches: ["master"]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Setup repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Deno
|
||||
# uses: denoland/setup-deno@v1
|
||||
uses: denoland/setup-deno@61fe2df320078202e33d7d5ad347e7dcfa0e8f31 # v1.1.2
|
||||
with:
|
||||
deno-version: v1.x
|
||||
|
||||
- name: Verify formatting
|
||||
run: deno fmt --check
|
||||
|
||||
- name: Run linter
|
||||
run: deno lint
|
||||
|
||||
# Add this back in when tests are added
|
||||
# - name: Run tests
|
||||
# run: deno test -A
|
|
@ -13,7 +13,26 @@
|
|||
"https://deno.land": true
|
||||
},
|
||||
"cSpell.words": [
|
||||
"DEVMODE",
|
||||
"LOCALMODE",
|
||||
"sproc",
|
||||
"USTZ"
|
||||
]
|
||||
],
|
||||
"macros.list": {
|
||||
"updateDbImport": [
|
||||
{"command": "type", "args": {"text": "\nimport dbc"}},
|
||||
{"command": "$delay", "args": {"delay": 100}},
|
||||
"acceptSelectedSuggestion",
|
||||
"cursorDown",
|
||||
"deleteWordLeft",
|
||||
"deleteRight",
|
||||
"deleteRight",
|
||||
"cursorEnd",
|
||||
"cursorWordLeft",
|
||||
"cursorWordLeft",
|
||||
"cursorLeft",
|
||||
{"command": "type", "args": {"text": "/common"}},
|
||||
"workbench.action.files.save"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
# CONTRIBUTING TO GROUP UP
|
||||
## Things to check before committing a change
|
||||
- Formatting and linting
|
||||
- Run `deno fmt` to set all formatting correct
|
||||
- Run `deno lint` to check for any issues that need fixed
|
||||
- Are you making a change that will be updating the version number?
|
||||
- Update the version number in `README.md` and `config.example.ts`, and update the date in `README.md`
|
||||
- Create a tag on your commit marking this version (name it Vx.x.x)
|
||||
## Things to check after committing a change
|
||||
- Check in on Sonar to see if your commit caused new issues to appear. If it did, please fix them
|
|
@ -3,7 +3,7 @@
|
|||
### Public Bot Information
|
||||
Publicly available versions of `Group Up#1305` (Discord ID: `847256159123013722`) (herein referred to as _The Bot_ or _Bot_) do not automatically track or collect user information via Discord.
|
||||
|
||||
Upon inviting _The Bot_ to a user's guild, _The Bot_ sends the guild name, Discord Guild ID, and current count of guild members to Burn_E99#1062 (herein referred to as _The Developer_) via a private Discord Guild. The guild name, Discord Guild ID, and current count of guild members are only used to roughly gage how popular _The Bot_ is and to determine if _The Bot_'s hosting solution needs to be improved. These pieces of information will never be sold or shared with anyone.
|
||||
Upon inviting _The Bot_ to a user's guild, _The Bot_ sends the guild name, Discord Guild ID, and current count of guild members to `@burn_e99` (herein referred to as _The Developer_) via a private Discord Guild. The guild name, Discord Guild ID, and current count of guild members are only used to roughly gage how popular _The Bot_ is and to determine if _The Bot_'s hosting solution needs to be improved. These pieces of information will never be sold or shared with anyone.
|
||||
|
||||
_The Bot_ reads every message that it is allowed to, meaning if _The Bot_ is allowed to see a channel in a guild, it reads every new message sent in said channel. This is for the automated cleanup of designated Event Channels.
|
||||
|
||||
|
@ -11,7 +11,7 @@ _The Bot_ does not read any user messages sent in the past, but does read its ow
|
|||
|
||||
* Messages that do not begin with _The Bot_'s command prefix are not saved or stored anywhere. Messages that do not begin with _The Bot_'s command prefix that are sent outside of a designated Event Channel are ignored and not processed.
|
||||
* Slash Commands sent to _The Bot_ do not automatically log user data, and most commands to not log any data. The commands that log data are the report command (in Discord, this command is known as `/report [message]`), the Event Channel setup command (known as `/setup`), and the Create New Event command (known as `/create-event` or the `Create New Event` button).
|
||||
* The report command only stores the text placed within the message that is directly after the command (herein referred to as _The Report Text_). This command is entirely optional, meaning users never need to run this command under normal usage of _The Bot_. This command is only intended to be used to report roll commands that did not output what was expected. This command will accept any value for _The Report Text_, thus it is up to the user to remove any sensitive information before sending the command. _The Report Text_ is stored in a private Discord Guild in a channel that only _The Developer_ can see. _The Report Text_ is solely used to improve _The Bot_, either by providing a feature suggestions or alerting _The Developer_ to bugs that need patched.
|
||||
* The report command stores the Discord Guild ID, Discord User ID, and the text placed within the message that is directly after the command (herein referred to as _The Report Text_). This command is entirely optional, meaning users never need to run this command under normal usage of _The Bot_. This command is only intended to be used to report roll commands that did not output what was expected. This command will accept any value for _The Report Text_, thus it is up to the user to remove any sensitive information before sending the command. _The Report Text_, Discord Guild ID, and Discord User ID are stored in a private Discord Guild in a channel that only _The Developer_ can see. _The Report Text_ is solely used to improve _The Bot_, either by providing a feature suggestions or alerting _The Developer_ to bugs that need patched. The Discord Guild ID and Discord User ID are only used to determine which reports need to be deleted as detailed in the _Deleting Your Data_ section below.
|
||||
* The Event Channel setup command only stores Discord IDs. The setup command will always store the Discord Channel ID and Discord Guild ID from where it was run.
|
||||
* If the Event Channel setup command was run with the `with-manager-role` option, the submitted Discord Role ID and Discord Channel ID for the desired Manager Role and Log Channel will also be stored.
|
||||
* The Create New Event command stores the following data for every event that is created:
|
||||
|
@ -38,4 +38,4 @@ Due to the nature of open source code, _Rehosts_ may not use the same codebase t
|
|||
If you wish to remove all data that _The Bot_ has on your Guild, simply remove _The Bot_ from your Guild. Upon removal, _The Bot_ deletes all data on Event Channel, all data on Events created in the Guild, and all Custom Activities created in the Guild.
|
||||
|
||||
## User Data Deletion
|
||||
If you would like to ensure that all of your submitted reports are removed from _The Bot_'s private development server, please contact _The Developer_ via Discord (by sending a direct message to `Burn_E99#1062`) or via email (<ean@milligan.dev>) with a message along the lines of `"Please remove all of my submitted reports from your development server."`. Submitted reports are deleted from the server as they are processed, which happens roughly once a week, but this can be accelerated if requested.
|
||||
If you would like to ensure that all of your submitted reports are removed from _The Bot_'s private development server, please contact _The Developer_ via Discord (by sending a direct message to `@burn_e99`) or via email (<ean@milligan.dev>) with a message along the lines of `"Please remove all of my submitted reports from your development server."`. Submitted reports are deleted from the server as they are processed, which happens roughly once a week, but this can be accelerated if requested.
|
||||
|
|
15
README.md
15
README.md
|
@ -1,4 +1,4 @@
|
|||
# Group Up - An Event Scheduling Discord Bot | V1.0.3 - 2022/05/26
|
||||
# Group Up - An Event Scheduling Discord Bot | V2.0.0 - 2024/12/24
|
||||
[](https://sonarcloud.io/summary/new_code?id=GroupUp)
|
||||
[](https://sonarcloud.io/summary/new_code?id=GroupUp) [](https://sonarcloud.io/summary/new_code?id=GroupUp) [](https://sonarcloud.io/summary/new_code?id=GroupUp) [](https://sonarcloud.io/summary/new_code?id=GroupUp) [](https://sonarcloud.io/summary/new_code?id=GroupUp) [](https://sonarcloud.io/summary/new_code?id=GroupUp)
|
||||
|
||||
|
@ -11,7 +11,7 @@ I am hosting this bot for public use and you may find its invite link below. If
|
|||
|
||||
After inviting the bot, if you want to create a dedicated event channel, simply run `/setup` in the desired channel and follow the on-screen prompts. If you don't want a dedicated channel, just run `/create-event` anywhere.
|
||||
|
||||
Note: The `MANAGE_GUILD`, `MANAGE_CHANNELS`, and `MANAGE_ROLES` permissions are only necessary for the `/setup` command. Once you create all of the event channel that you need, you may remove these permissions from the bot without causing any issues.
|
||||
Note: The `MANAGE_GUILD`, `MANAGE_CHANNELS`, and `MANAGE_ROLES` permissions are only necessary for the `/setup` command. Once you create all of the event channels that you need, you may remove these permissions from the bot without causing any issues.
|
||||
|
||||
[Bot Invite Link](https://discord.com/api/oauth2/authorize?client_id=847256159123013722&permissions=268527664&scope=bot%20applications.commands)
|
||||
|
||||
|
@ -43,7 +43,12 @@ If you run into any errors or problems with the bot, or think you have a good id
|
|||
---
|
||||
|
||||
## Self Hosting Group Up
|
||||
Group Up is built on [Deno](https://deno.land/) `v1.33.1` using [Discordeno](https://discordeno.mod.land/) `v17.0.1`. If you choose to run this yourself, you will need to rename `config.example.ts` to `config.ts` and edit some values. You will need to create a new [Discord Application](https://discord.com/developers/applications) and copy the newly generated token into the `"token"` field. If you want to utilize some of the bots dev features, you will need to fill in the keys `"logChannel"` and `"reportChannel"` with text channel IDs and `"devServer"` with a guild ID.
|
||||
Group Up is built on [Deno](https://deno.land/) using [Discordeno](https://discordeno.mod.land/) `v17.0.1`.
|
||||
|
||||
Group Up `V1.1.6` and lower requires Deno `V.33.1`.
|
||||
Group Up `V2.0.0` and up requires Deno `V2.0.0`.
|
||||
|
||||
If you choose to run this yourself, you will need to rename `config.example.ts` to `config.ts` and edit some values. You will need to create a new [Discord Application](https://discord.com/developers/applications) and copy the newly generated token into the `"token"` field. If you want to utilize some of the bots dev features, you will need to fill in the keys `"logChannel"` and `"reportChannel"` with text channel IDs and `"devServer"` with a guild ID.
|
||||
|
||||
You will also need to install and setup a MySQL database with a user for the bot to use to add/modify the database. This user must have the `"DB Manager"` admin rights and `"REFERENCES"` Global Privileges. Once the DB is installed and a user is setup, run the provided `db\initialize.ts` to create the schema and tables. After this, run `db\populateDefaults.ts` to insert some needed values into the tables.
|
||||
|
||||
|
@ -54,6 +59,6 @@ Once everything is set up, starting the bot can simply be done with `deno run --
|
|||
## Privacy Policy and Terms of Service
|
||||
Group Up has a Privacy Policy and Terms of Service to detail expectations of what user data is stored and how users should use Group Up. The following Privacy Policy and Terms of Service only apply to the officially hosted version of Group Up (`Group Up#1305`, Discord ID: `847256159123013722`).
|
||||
|
||||
Privacy Policy TL;DR: Group Up stores data relating to events, event channels, and text from the `/report` command. For more detailed information, please check out the full [PRIVACY POLICY](https://github.com/Burn-E99/TheArtificer/blob/master/PRIVACY.md).
|
||||
Privacy Policy TL;DR: Group Up stores data relating to events, event channels, and text from the `/report` command. For more detailed information, please check out the full [PRIVACY POLICY](https://github.com/Burn-E99/GroupUp/blob/master/PRIVACY.md).
|
||||
|
||||
Terms of Service TL;DR: Don't abuse or attempt to hack/damage Group Up. If you do, you may be banned from use. For more detailed information, please check out the full [TERMS OF SERVICE](https://github.com/Burn-E99/TheArtificer/blob/master/TERMS.md).
|
||||
Terms of Service TL;DR: Don't abuse or attempt to hack/damage Group Up. If you do, you may be banned from use. For more detailed information, please check out the full [TERMS OF SERVICE](https://github.com/Burn-E99/GroupUp/blob/master/TERMS.md).
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
export const config = {
|
||||
export const config = { // !! NOTICE !! All fields below are required unless they are explicitly noted as OPTIONAL. If a field is OPTIONAL, do not remove it from this file, just leave it at the default value
|
||||
'name': 'Group Up', // Name of the bot
|
||||
'version': '1.0.3', // Version of the bot
|
||||
'version': '2.0.0', // Version of the bot
|
||||
'token': 'the_bot_token', // Discord API Token for this bot
|
||||
'localToken': 'local_testing_token', // Discord API Token for a secondary OPTIONAL testing bot, THIS MUST BE DIFFERENT FROM "token"
|
||||
'prefix': '/', // Prefix for all commands
|
||||
'db': { // Settings for the MySQL database, this is required for use with the API, if you do not want to set this up, you will need to rip all code relating to the DB out of the bot
|
||||
'localToken': 'local_testing_token', // Discord API Token for a secondary OPTIONAL testing bot, THIS SHOULD BE DIFFERENT FROM "token"
|
||||
'prefix': '/', // Prefix for all commands, as this bot uses slash commands, this needs to be '/'
|
||||
'db': { // Settings for the MySQL database, this is required to keep track of the currently active events.
|
||||
'host': '', // IP address for the db, usually localhost
|
||||
'localhost': '', // IP address for a secondary OPTIONAL local testing DB, usually also is localhost, but depends on your dev environment
|
||||
'port': 3306, // Port for the db
|
||||
|
@ -12,17 +12,18 @@ export const config = {
|
|||
'password': '', // Password for the account, user account may need to be authenticated with the "Standard" Authentication Type if this does not work out of the box
|
||||
'name': '', // Name of the database Schema to use for the bot
|
||||
},
|
||||
'link': { // Links to various sites
|
||||
'sourceCode': 'https://github.com/Burn-E99/GroupUp', // Link to the repository
|
||||
'supportServer': '', // Invite link to the Discord support server
|
||||
'addToCalendar': '', // Link to where the icsGenerator is hosted
|
||||
'links': { // Links to various sites
|
||||
'sourceCode': 'https://github.com/Burn-E99/GroupUp', // Link to the repository, OPTIONAL
|
||||
'supportServer': '', // Invite link to the Discord support server, OPTIONAL
|
||||
'addToCalendar': '', // Link to where the icsGenerator is hosted, OPTIONAL
|
||||
'creatorIcon': '', // Link to where the GroupUpSinglePerson.png (or similar image) is hosted
|
||||
},
|
||||
'logChannel': 0n, // Discord channel ID where the bot should put startup messages and other error messages needed
|
||||
'reportChannel': 0n, // Discord channel ID where reports will be sent when using the built-in report command
|
||||
'devServer': 0n, // Discord guild ID where testing of indev features/commands will be handled, used in conjunction with the DEVMODE bool in mod.ts
|
||||
'owner': 0n, // Discord user ID of the bot admin
|
||||
'botLists': [ // Array of objects containing all bot lists that stats should be posted to
|
||||
'defaultDateFormat': 'MONTH/DAY/YEAR', // Default format that Group Up will suggest to the user. Must match one of the options in the 'DateTimeFormats' enum inside 'src/buttons/event-creation/dateTimeUtils.ts'
|
||||
'logChannel': 0n, // Discord channel ID where the bot should put startup messages and other error messages needed. This value is a bigint, so please ensure you have a `n` after the ID you get from Discord. OPTIONAL
|
||||
'reportChannel': 0n, // Discord channel ID where reports will be sent when using the built-in report command. This value is a bigint, so please ensure you have a `n` after the ID you get from Discord. OPTIONAL
|
||||
'devServer': 0n, // Discord guild ID where testing of indev features/commands will be handled, used in conjunction with the DEVMODE bool in mod.ts. This value is a bigint, so please ensure you have a `n` after the ID you get from Discord. OPTIONAL
|
||||
'owner': 0n, // Discord user ID of the bot admin. This value is a bigint, so please ensure you have a `n` after the ID you get from Discord.
|
||||
'botLists': [ // Array of objects containing all bot lists that stats should be posted to, OPTIONAL
|
||||
{ // Bot List object, duplicate for each bot list
|
||||
'name': 'Bot List Name', // Name of bot list, not used
|
||||
'enabled': false, // Should statistics be posted to this list?
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// DATA WILL BE LOST IF DB ALREADY EXISTS, RUN AT OWN RISK
|
||||
|
||||
import config from '../config.ts';
|
||||
import { dbClient } from '../src/db.ts';
|
||||
import { dbClient } from '../src/db/client.ts';
|
||||
|
||||
console.log('Attempting to create DB');
|
||||
await dbClient.execute(`CREATE SCHEMA IF NOT EXISTS ${config.db.name};`);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// This file will populate the tables with default values
|
||||
import { dbClient } from '../src/db.ts';
|
||||
import { dbClient } from '../src/db/client.ts';
|
||||
|
||||
console.log('Attempting to insert default actions into command_cnt');
|
||||
const actions = [
|
||||
|
|
2
deps.ts
2
deps.ts
|
@ -47,4 +47,4 @@ export type {
|
|||
|
||||
export { Client } from 'https://deno.land/x/mysql@v2.11.0/mod.ts';
|
||||
|
||||
export { initLog, log, LogTypes as LT } from 'https://raw.githubusercontent.com/Burn-E99/Log4Deno/V1.1.0/mod.ts';
|
||||
export { initLog, log, LogTypes as LT } from 'https://raw.githubusercontent.com/Burn-E99/Log4Deno/V2.0.0/mod.ts';
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { log, LT } from '../../../deps.ts';
|
||||
|
||||
// Activity should either have maxMembers or options specified, NOT both
|
||||
export type Activity = {
|
||||
name: string;
|
||||
|
@ -13,12 +15,20 @@ export const Activities: Array<Activity> = [
|
|||
{
|
||||
name: 'Raids',
|
||||
options: [
|
||||
{
|
||||
name: "Salvation's Edge",
|
||||
maxMembers: 6,
|
||||
},
|
||||
{
|
||||
name: "Crota's End",
|
||||
maxMembers: 6,
|
||||
},
|
||||
{
|
||||
name: 'Root of Nightmares',
|
||||
maxMembers: 6,
|
||||
},
|
||||
{
|
||||
name: 'King\'s Fall',
|
||||
name: "King's Fall",
|
||||
maxMembers: 6,
|
||||
},
|
||||
{
|
||||
|
@ -46,6 +56,10 @@ export const Activities: Array<Activity> = [
|
|||
{
|
||||
name: 'Dungeons',
|
||||
options: [
|
||||
{
|
||||
name: "Warlord's Ruin",
|
||||
maxMembers: 3,
|
||||
},
|
||||
{
|
||||
name: 'Ghosts of the Deep',
|
||||
maxMembers: 3,
|
||||
|
@ -146,11 +160,52 @@ export const Activities: Array<Activity> = [
|
|||
name: '//node.ovrd.AVALON//',
|
||||
maxMembers: 3,
|
||||
},
|
||||
{
|
||||
name: 'Zero Hour',
|
||||
maxMembers: 3,
|
||||
},
|
||||
{
|
||||
name: 'The Whisper',
|
||||
maxMembers: 3,
|
||||
},
|
||||
{
|
||||
name: 'Presage',
|
||||
maxMembers: 3,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Miscellaneous/Seasonal',
|
||||
options: [
|
||||
{
|
||||
name: 'Excision',
|
||||
maxMembers: 12,
|
||||
},
|
||||
{
|
||||
name: 'Pantheon',
|
||||
options: [
|
||||
{
|
||||
name: 'Atraks Sovereign (Week 1)',
|
||||
maxMembers: 6,
|
||||
},
|
||||
{
|
||||
name: 'Oryx Exalted (Week 2)',
|
||||
maxMembers: 6,
|
||||
},
|
||||
{
|
||||
name: 'Rhulk Indomitable (Week 3)',
|
||||
maxMembers: 6,
|
||||
},
|
||||
{
|
||||
name: 'Nezarec Sublime (Week 4)',
|
||||
maxMembers: 6,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Onslaught',
|
||||
maxMembers: 3,
|
||||
},
|
||||
{
|
||||
name: 'Fishing',
|
||||
maxMembers: 3,
|
||||
|
@ -225,3 +280,33 @@ export const Activities: Array<Activity> = [
|
|||
],
|
||||
},
|
||||
];
|
||||
|
||||
// Activities Verification, verifies fields are proper lengths and amount of activities will actually fit in Discord
|
||||
const actVerification = (currentAct: Activity, currentDepth = 0) => {
|
||||
if (currentDepth > 4) {
|
||||
log(LT.ERROR, `'${currentAct.name}' is too deep (${currentDepth} > 4)!`);
|
||||
}
|
||||
if (currentAct.name.length > 100) {
|
||||
log(LT.ERROR, `'${currentAct.name}' is too long (${currentAct.name.length} > 100)!`);
|
||||
}
|
||||
if (currentAct.options && currentAct.maxMembers) {
|
||||
log(LT.ERROR, `'${currentAct.name}' has both maxMembers and options specified (ONLY ONE ALLOWED)!`);
|
||||
}
|
||||
if (!currentAct.options && !currentAct.maxMembers) {
|
||||
log(LT.ERROR, `'${currentAct.name}' is missing both maxMembers and options specified (ONE IS NEEDED)!`);
|
||||
}
|
||||
if (currentAct.options) {
|
||||
if (currentAct.options.length > 25) {
|
||||
log(LT.ERROR, `'${currentAct.name}' has too many options (${currentAct.options.length} > 25)!`);
|
||||
}
|
||||
for (const act of currentAct.options) {
|
||||
actVerification(act, currentDepth + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Use a fake root activity to allow testing to occur simply
|
||||
actVerification({
|
||||
name: 'root',
|
||||
options: Activities,
|
||||
});
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
import config from '../../../config.ts';
|
||||
import { editEventDetailsBtnName } from './utils.ts';
|
||||
|
||||
enum DateTimeFormats {
|
||||
MMDDYYYY = 'MONTH/DAY/YEAR',
|
||||
DDMMYYYY = 'DAY/MONTH/YEAR',
|
||||
}
|
||||
const monthsLong: Array<string> = ['JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER'];
|
||||
export const monthsShort: Array<string> = monthsLong.map((month) => month.slice(0, 3));
|
||||
const tzMap: Map<string, string> = new Map([
|
||||
|
@ -52,7 +59,8 @@ const tzMap: Map<string, string> = new Map([
|
|||
['CHST', '+10:00'],
|
||||
['SST', '-11:00'],
|
||||
]);
|
||||
const shorthandUSTZ: Array<string> = ['ET', 'CT', 'MT', 'PT'];
|
||||
const shorthandUSTZ: Array<string> = ['ET', 'CT', 'MT', 'PT', 'HT', 'AKT'];
|
||||
const allUSTZ: Array<string> = ['EST', 'CST', 'MST', 'PST', 'HST', 'AKST', 'EDT', 'CDT', 'MDT', 'PDT', 'HDT', 'AKDT'];
|
||||
|
||||
// Takes user input Time and makes it actually usable
|
||||
const parseEventTime = (preParsedEventTime: string): [string, string, string] => {
|
||||
|
@ -93,14 +101,33 @@ export const isDSTActive = (): boolean => {
|
|||
return today.getTimezoneOffset() < Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
|
||||
};
|
||||
|
||||
const editButtonMessage = `click \`${editEventDetailsBtnName}\` and change`;
|
||||
const warningText = (incorrectTZ: string, correctTZ: string, newEvent: boolean) =>
|
||||
`⚠️⚠️⚠️ WARNING! Did you mean to enter \`${incorrectTZ}\` for the time zone? ⚠️⚠️⚠️\nCurrently (as of the posting of this message), Daylight Savings Time is ${
|
||||
isDSTActive() ? '' : 'not '
|
||||
}active in most of the United States. If DST is ${isDSTActive() ? '' : 'not '}in effect for you (and will be when this event is scheduled to happen), ${
|
||||
newEvent ? editButtonMessage : 'please dismiss this message and start over, using'
|
||||
} the time zone ${newEvent ? 'to ' : ''}\`${correctTZ}\`, or shorten it to \`${correctTZ.slice(0, -2)}T\` to let ${config.name} automatically use the correct time zone.\n\n`;
|
||||
|
||||
const usTZDSTCheck = (timeZone: string, newEvent: boolean): string => {
|
||||
if (allUSTZ.includes(timeZone)) {
|
||||
if (isDSTActive() && timeZone.endsWith('ST')) {
|
||||
return warningText(timeZone, `${timeZone.slice(0, -2)}DT`, newEvent);
|
||||
} else if (!isDSTActive() && timeZone.endsWith('DT')) {
|
||||
return warningText(timeZone, `${timeZone.slice(0, -2)}ST`, newEvent);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
// Takes user input Time Zone and makes it actually usable
|
||||
const parseEventTimeZone = (preParsedEventTimeZone: string): [string, string] => {
|
||||
if (shorthandUSTZ.includes(preParsedEventTimeZone)) {
|
||||
// Handle shorthand US timezones, adding S for standard time and D for Daylight Savings
|
||||
if (isDSTActive()) {
|
||||
preParsedEventTimeZone = `${preParsedEventTimeZone.slice(0, 1)}DT`;
|
||||
preParsedEventTimeZone = `${preParsedEventTimeZone.slice(0, -1)}DT`;
|
||||
} else {
|
||||
preParsedEventTimeZone = `${preParsedEventTimeZone.slice(0, 1)}ST`;
|
||||
preParsedEventTimeZone = `${preParsedEventTimeZone.slice(0, -1)}ST`;
|
||||
}
|
||||
}
|
||||
if (tzMap.has(preParsedEventTimeZone)) {
|
||||
|
@ -113,8 +140,8 @@ const parseEventTimeZone = (preParsedEventTimeZone: string): [string, string] =>
|
|||
addPlusSign = true;
|
||||
}
|
||||
// Determine if we need to prepend UTC/GMT, handle adding the + into the string
|
||||
if (!preParsedEventTimeZone.startsWith('UTC') && preParsedEventTimeZone.startsWith('GMT')) {
|
||||
preParsedEventTimeZone = `UTC${addPlusSign && '+'}${preParsedEventTimeZone}`;
|
||||
if (!preParsedEventTimeZone.startsWith('UTC') || preParsedEventTimeZone.startsWith('GMT')) {
|
||||
preParsedEventTimeZone = `UTC${addPlusSign ? '+' : ''}${preParsedEventTimeZone.startsWith('GMT') ? preParsedEventTimeZone.slice(3) : preParsedEventTimeZone}`;
|
||||
} else if (addPlusSign) {
|
||||
preParsedEventTimeZone = `${preParsedEventTimeZone.slice(0, 3)}+${preParsedEventTimeZone.slice(3)}`;
|
||||
}
|
||||
|
@ -122,10 +149,49 @@ const parseEventTimeZone = (preParsedEventTimeZone: string): [string, string] =>
|
|||
}
|
||||
};
|
||||
|
||||
const determineDateTimeOrder = (parsedSlot1: string, parsedSlot2: string, parsedSlot3: string): [string, string, string] => {
|
||||
// Default these to MMDDYYYY in case something goes wrong and does not properly override them
|
||||
let parsedEventMonth = parsedSlot1;
|
||||
let parsedEventDay = parsedSlot2;
|
||||
let parsedEventYear = parsedSlot3;
|
||||
|
||||
const slot1AsInt = parseInt(parsedSlot1);
|
||||
const slot2AsInt = parseInt(parsedSlot2);
|
||||
if (!isNaN(slot1AsInt) && slot1AsInt > 999) {
|
||||
// First parsing slot appears to be a year, assume user used ISO8601 format
|
||||
parsedEventYear = parsedSlot1;
|
||||
parsedEventMonth = parsedSlot2;
|
||||
parsedEventDay = parsedSlot3;
|
||||
} else if (!isNaN(slot1AsInt) && slot1AsInt > 12) {
|
||||
// First parsing slot appears to be a day, assume user used DDMMYYYY format
|
||||
parsedEventDay = parsedSlot1;
|
||||
parsedEventMonth = parsedSlot2;
|
||||
parsedEventYear = parsedSlot3;
|
||||
} else if (!isNaN(slot2AsInt) && slot2AsInt > 12) {
|
||||
// Second parsing slot appears to be a day, assume user used MMDDYYYY format
|
||||
parsedEventMonth = parsedSlot1;
|
||||
parsedEventDay = parsedSlot2;
|
||||
parsedEventYear = parsedSlot3;
|
||||
} else if (config.defaultDateFormat === DateTimeFormats.DDMMYYYY) {
|
||||
// Year was not first, and cannot locate a day from the string, fall back to bot's default setting
|
||||
parsedEventDay = parsedSlot1;
|
||||
parsedEventMonth = parsedSlot2;
|
||||
parsedEventYear = parsedSlot3;
|
||||
} else if (config.defaultDateFormat === DateTimeFormats.MMDDYYYY) {
|
||||
// Year was not first, and cannot locate a day from the string, fall back to bot's default setting
|
||||
parsedEventMonth = parsedSlot1;
|
||||
parsedEventDay = parsedSlot2;
|
||||
parsedEventYear = parsedSlot3;
|
||||
}
|
||||
|
||||
return [parsedEventMonth, parsedEventDay, parsedEventYear];
|
||||
};
|
||||
|
||||
// Takes user input Date and makes it actually usable
|
||||
const parseEventDate = (preParsedEventDate: string): [string, string, string] => {
|
||||
const today = new Date();
|
||||
let [parsedEventMonth, parsedEventDay, parsedEventYear] = preParsedEventDate.split(/[\s,\\/-]+/g);
|
||||
const [parsedSlot1, parsedSlot2, parsedSlot3] = preParsedEventDate.split(/[\s,\\/-]+/g);
|
||||
let [parsedEventMonth, parsedEventDay, parsedEventYear] = determineDateTimeOrder(parsedSlot1, parsedSlot2, parsedSlot3);
|
||||
|
||||
if (isNaN(parseInt(parsedEventDay))) {
|
||||
// User only provided one word, we're assuming it was TOMORROW, and all others will be treated as today
|
||||
|
@ -154,12 +220,13 @@ const parseEventDate = (preParsedEventDate: string): [string, string, string] =>
|
|||
};
|
||||
|
||||
// Take full raw Date/Time input and convert it to a proper Date
|
||||
export const getDateFromRawInput = (rawEventTime: string, rawEventTimeZone: string, rawEventDate: string): [Date, string, boolean, boolean] => {
|
||||
export const getDateFromRawInput = (rawEventTime: string, rawEventTimeZone: string, rawEventDate: string, newEvent: boolean): [Date, string, boolean, boolean, string] => {
|
||||
// Verify/Set Time
|
||||
const [parsedEventTimeHours, parsedEventTimeMinutes, parsedEventTimePeriod] = parseEventTime(rawEventTime.replaceAll(':', '').toUpperCase());
|
||||
|
||||
// Verify/Set Time Zone
|
||||
const [parsedEventTimeZone, userInputTimeZone] = parseEventTimeZone(rawEventTimeZone.replaceAll(' ', '').trim().toUpperCase());
|
||||
const usTZWarning = usTZDSTCheck(userInputTimeZone, newEvent);
|
||||
|
||||
// Verify/Set Date
|
||||
const [parsedEventYear, parsedEventMonth, parsedEventDay] = parseEventDate(rawEventDate.trim().toUpperCase());
|
||||
|
@ -172,5 +239,6 @@ export const getDateFromRawInput = (rawEventTime: string, rawEventTimeZone: stri
|
|||
} ${parsedEventDay}, ${parsedEventYear}`,
|
||||
parsedDateTime.getTime() > new Date().getTime(),
|
||||
!isNaN(parsedDateTime.getTime()),
|
||||
usTZWarning,
|
||||
];
|
||||
};
|
||||
|
|
|
@ -9,7 +9,8 @@ import utils from '../../utils.ts';
|
|||
import { customId as createCustomActivityBtnId } from './step1a-openCustomModal.ts';
|
||||
import { customId as finalizeEventBtnId } from './step2-finalize.ts';
|
||||
import { monthsShort } from './dateTimeUtils.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import { createEventSlashName } from '../../commands/slashCommandNames.ts';
|
||||
|
||||
export const customId = 'gameSel';
|
||||
|
@ -51,7 +52,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
let prefillDescription = '';
|
||||
if (interaction.message?.embeds[0].fields && interaction.message.embeds[0].fields[LfgEmbedIndexes.StartTime].name === lfgStartTimeName) {
|
||||
if (interaction.message.embeds[0].fields[LfgEmbedIndexes.StartTime].value !== invalidDateTimeStr) {
|
||||
let rawEventDateTime = interaction.message.embeds[0].fields[LfgEmbedIndexes.StartTime].value.split('\n')[0].split(' ');
|
||||
const rawEventDateTime = interaction.message.embeds[0].fields[LfgEmbedIndexes.StartTime].value.split('\n')[0].split(' ');
|
||||
const monthIdx = rawEventDateTime.findIndex((item) => monthsShort.includes(item.toUpperCase()));
|
||||
prefillTime = rawEventDateTime.slice(0, monthIdx - 1).join(' ').trim();
|
||||
prefillTimeZone = (rawEventDateTime[monthIdx - 1] || '').trim();
|
||||
|
@ -110,7 +111,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('step1-gameSelection.ts:ping', interaction, e));
|
||||
|
||||
// Update the original game selector
|
||||
await bot.helpers.editOriginalInteractionResponse(tokenMap.get(generateMapId(interaction.guildId, interaction.channelId, interaction.member.id))?.token || '', {
|
||||
await bot.helpers.editOriginalInteractionResponse(tokenMap.get(generateMapId(interaction.guildId, interaction.channelId, interaction.member.id))?.token ?? '', {
|
||||
components: selectMenus,
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('step1-gameSelection.ts:edit', interaction, e));
|
||||
} else {
|
||||
|
|
|
@ -2,11 +2,12 @@ import { Bot, Interaction, InteractionResponseTypes } from '../../../deps.ts';
|
|||
import { generateCustomActivityFields, idSeparator, pathIdxSeparator } from '../eventUtils.ts';
|
||||
import { customId as verifyCustomActivityId } from './step1b-verifyCustomActivity.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
|
||||
export const customId = 'customAct';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
const execute = (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.customId && interaction.member && interaction.guildId && interaction.channelId) {
|
||||
// Light Telemetry
|
||||
dbClient.execute(queries.callIncCnt('btn-customAct')).catch((e) => utils.commonLoggers.dbError('step1a-openCustomModal.ts', 'call sproc INC_CNT on', e));
|
||||
|
|
|
@ -6,12 +6,13 @@ import { addTokenToMap, deleteTokenEarly } from '../tokenCleanup.ts';
|
|||
import { Activities, Activity } from './activities.ts';
|
||||
import { getDateFromRawInput } from './dateTimeUtils.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
|
||||
export const customId = 'finalize';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.components?.length && interaction.guildId && interaction.channelId && interaction.member && interaction.member.user) {
|
||||
if (interaction.data?.components?.length && interaction.guildId && interaction.channelId && interaction?.member?.user) {
|
||||
// User selected activity and has filled out fields, delete the selectMenus
|
||||
await deleteTokenEarly(bot, interaction, interaction.guildId, interaction.channelId, interaction.member.id);
|
||||
|
||||
|
@ -66,7 +67,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
}
|
||||
|
||||
// Get Date Object from user input
|
||||
const [eventDateTime, eventDateTimeStr, eventInFuture, dateTimeValid] = getDateFromRawInput(rawEventTime, rawEventTimeZone, rawEventDate);
|
||||
const [eventDateTime, eventDateTimeStr, eventInFuture, dateTimeValid, usTZWarning] = getDateFromRawInput(rawEventTime, rawEventTimeZone, rawEventDate, true);
|
||||
|
||||
addTokenToMap(bot, interaction, interaction.guildId, interaction.channelId, interaction.member.id);
|
||||
bot.helpers.sendInteractionResponse(
|
||||
|
@ -88,6 +89,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
customIdIdxPath,
|
||||
eventInFuture,
|
||||
dateTimeValid,
|
||||
usTZWarning,
|
||||
),
|
||||
).catch((e: Error) => utils.commonLoggers.interactionSendError('step2-finalize.ts', interaction, e));
|
||||
} else {
|
||||
|
|
|
@ -2,15 +2,16 @@ import { ApplicationCommandFlags, Bot, Interaction, InteractionResponseTypes, Me
|
|||
import { generateLFGButtons } from './utils.ts';
|
||||
import { idSeparator, LfgEmbedIndexes } from '../eventUtils.ts';
|
||||
import { deleteTokenEarly } from '../tokenCleanup.ts';
|
||||
import { dmTestMessage, safelyDismissMsg, sendDirectMessage, somethingWentWrong, warnColor } from '../../commandUtils.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { commonFixes, dmTestMessage, safelyDismissMsg, sendDirectMessage, somethingWentWrong, warnColor } from '../../commandUtils.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import utils from '../../utils.ts';
|
||||
|
||||
export const customId = 'createEvent';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (
|
||||
interaction.data?.customId && interaction.member && interaction.guildId && interaction.channelId && interaction.message && interaction.message.embeds[0] && interaction.message.embeds[0].fields
|
||||
interaction.data?.customId && interaction.member && interaction.guildId && interaction.channelId && interaction?.message?.embeds?.[0]?.fields
|
||||
) {
|
||||
// Light Telemetry
|
||||
dbClient.execute(queries.callIncCnt(interaction.data.customId.includes(idSeparator) ? 'btn-createWLEvt' : 'btn-createEvt')).catch((e) =>
|
||||
|
@ -51,7 +52,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
}],
|
||||
}).catch((e: Error) => utils.commonLoggers.messageSendError('step3-createEvent.ts', 'createEvent', e));
|
||||
if (!eventMessage) {
|
||||
somethingWentWrong(bot, interaction, 'creatingEventSendMessageFinalizeEventStep');
|
||||
somethingWentWrong(bot, interaction, 'creatingEventSendMessageFinalizeEventStep', commonFixes.CANT_SEND_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import { customId as editEventCustomId } from '../live-event/editEvent.ts';
|
|||
|
||||
export const getNestedActivity = (idxPath: Array<number>, activities: Array<Activity>): Array<Activity> => {
|
||||
const nextIdx = idxPath[0];
|
||||
if (idxPath.length && activities[nextIdx] && activities[nextIdx].options) {
|
||||
if (idxPath.length && activities[nextIdx]?.options) {
|
||||
idxPath.shift();
|
||||
return getNestedActivity(idxPath, activities[nextIdx].options || []);
|
||||
} else {
|
||||
|
@ -55,7 +55,7 @@ export const generateActionRow = (baseValue: string, activities: Array<Activity>
|
|||
|
||||
const createEventBtnName = 'Create Event';
|
||||
const createWhitelistedBtnName = 'Create Whitelisted Event';
|
||||
const editEventDetailsBtnName = 'Edit Event Details';
|
||||
export const editEventDetailsBtnName = 'Edit Event Details';
|
||||
export const invalidDateTimeStr = '`Invalid Date/Time`';
|
||||
const finalizeButtons = (idxPath: string, eventInFuture: boolean): [ButtonComponent, ButtonComponent, ButtonComponent] | [ButtonComponent] => {
|
||||
const editButton: ButtonComponent = {
|
||||
|
@ -129,6 +129,7 @@ export const createLFGPost = (
|
|||
idxPath: string,
|
||||
eventInFuture: boolean,
|
||||
dateTimeValid: boolean,
|
||||
usTZWarning: string,
|
||||
): InteractionResponse => {
|
||||
const icsDetails = `${category}: ${activity.name}`;
|
||||
const dateTimePastFutureStr = dateTimeValid ? 'in the past' : 'with an invalid date/time';
|
||||
|
@ -138,7 +139,7 @@ export const createLFGPost = (
|
|||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
content: eventInFuture
|
||||
? `Please verify the information below, then click on the \`${createEventBtnName}\` or \`${createWhitelistedBtnName}\` button, or change the event \`Date/Time\` or \`Description\` with the \`${editEventDetailsBtnName}\` button below. \n\n${
|
||||
? `${usTZWarning}🛑🛑🛑 HEY! ONE MORE THING! 🛑🛑🛑\n\nPlease verify the information below, then click on the \`${createEventBtnName}\` or \`${createWhitelistedBtnName}\` button, or change the event \`Date/Time\` or \`Description\` with the \`${editEventDetailsBtnName}\` button below. \n\n${
|
||||
selfDestructMessage(new Date().getTime())
|
||||
}`
|
||||
: `You cannot create an event ${dateTimePastFutureStr}. Please change the event's \`Date/Time\` to be ${dateTimeValidStr} with the \`${editEventDetailsBtnName}\` button below.`,
|
||||
|
@ -160,7 +161,7 @@ export const createLFGPost = (
|
|||
name: 'Description:',
|
||||
value: eventDescription,
|
||||
}, {
|
||||
name: generateMemberTitle(memberList, activity.maxMembers || 0),
|
||||
name: generateMemberTitle(memberList, activity.maxMembers ?? 0),
|
||||
value: generateMemberList(memberList),
|
||||
inline: true,
|
||||
}, {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import config from '../../config.ts';
|
||||
import { ActionRow, MessageComponentTypes, TextStyles } from '../../deps.ts';
|
||||
import { LFGMember } from '../types/commandTypes.ts';
|
||||
import { isDSTActive } from './event-creation/dateTimeUtils.ts';
|
||||
|
@ -26,10 +27,12 @@ export const alternateEventBtnStr = 'Join as Alternate';
|
|||
export const noDescProvided = 'No description provided.';
|
||||
|
||||
// Member List generators
|
||||
const escapeMemberNameForDisplay = (memberName: string): string => memberName.replaceAll('\\', '').replaceAll('_', '\\_');
|
||||
export const generateMemberTitle = (memberList: Array<LFGMember>, maxMembers: number): string => `Members Joined: ${memberList.length}/${maxMembers}`;
|
||||
export const generateMemberList = (memberList: Array<LFGMember>): string => memberList.length ? memberList.map((member) => `${member.name} - <@${member.id}>`).join('\n') : noMembersStr;
|
||||
export const generateMemberList = (memberList: Array<LFGMember>): string =>
|
||||
memberList.length ? memberList.map((member) => `${escapeMemberNameForDisplay(member.name)} - <@${member.id}>`).join('\n') : noMembersStr;
|
||||
export const generateAlternateList = (alternateList: Array<LFGMember>): string =>
|
||||
alternateList.length ? alternateList.map((member) => `${member.name} - <@${member.id}>${member.joined ? ' *' : ''}`).join('\n') : noMembersStr;
|
||||
alternateList.length ? alternateList.map((member) => `${escapeMemberNameForDisplay(member.name)} - <@${member.id}>${member.joined ? ' *' : ''}`).join('\n') : noMembersStr;
|
||||
|
||||
// Fields for event creation and editing modals
|
||||
export const eventTimeId = 'eventTime';
|
||||
|
@ -84,7 +87,7 @@ export const dateTimeFields = (prefillTime = '', prefillTimeZone = '', prefillDa
|
|||
type: MessageComponentTypes.InputText,
|
||||
customId: eventDateId,
|
||||
label: 'Start Date:',
|
||||
placeholder: 'Enter date as "MONTH/DAY/YEAR" or "Month Day, Year"',
|
||||
placeholder: `Enter date as "${config.defaultDateFormat}" or "Month Day, Year"`,
|
||||
style: TextStyles.Short,
|
||||
minLength: 1,
|
||||
maxLength: 20,
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { Bot, Interaction } from '../../../deps.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import { somethingWentWrong } from '../../commandUtils.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import { alternateMemberToEvent } from './utils.ts';
|
||||
|
||||
export const customId = 'alternateEvent';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.customId && interaction.member && interaction.member.user && interaction.channelId && interaction.message && interaction.message.embeds[0]) {
|
||||
const execute = (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.customId && interaction?.member?.user && interaction.channelId && interaction?.message?.embeds?.[0]) {
|
||||
// Light Telemetry
|
||||
dbClient.execute(queries.callIncCnt('btn-altEvent')).catch((e) => utils.commonLoggers.dbError('alternateEvent.ts', 'call sproc INC_CNT on', e));
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Bot, Interaction } from '../../../deps.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import { somethingWentWrong } from '../../commandUtils.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import { alternateMemberToEvent } from './utils.ts';
|
||||
|
@ -7,7 +8,7 @@ import { alternateMemberToEvent } from './utils.ts';
|
|||
export const customId = 'alternateRequest';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.customId && interaction.user && interaction.message && interaction.message.embeds[0] && interaction.message.embeds[0].description) {
|
||||
if (interaction.data?.customId && interaction.user && interaction?.message?.embeds?.[0]?.description) {
|
||||
// Light Telemetry
|
||||
dbClient.execute(queries.callIncCnt('btn-joinReqAlt')).catch((e) => utils.commonLoggers.dbError('alternateRequest.ts', 'call sproc INC_CNT on', e));
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
}
|
||||
|
||||
// Get Date Object from user input
|
||||
const [eventDateTime, eventDateTimeStr, eventInFuture, dateTimeValid] = getDateFromRawInput(newTime, newTimeZone, newDate);
|
||||
const [eventDateTime, eventDateTimeStr, eventInFuture, dateTimeValid, usTZWarning] = getDateFromRawInput(newTime, newTimeZone, newDate, false);
|
||||
if (!eventInFuture || !dateTimeValid) {
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
|
@ -70,7 +70,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
content: applyEditMessage(new Date().getTime()),
|
||||
content: applyEditMessage(new Date().getTime(), usTZWarning),
|
||||
embeds: [eventMessage.embeds[0]],
|
||||
components: applyEditButtons(interaction.data.customId.split(idSeparator)[1] || ''),
|
||||
},
|
||||
|
|
|
@ -31,7 +31,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
content: applyEditMessage(new Date().getTime()),
|
||||
content: applyEditMessage(new Date().getTime(), ''),
|
||||
embeds: [eventMessage.embeds[0]],
|
||||
components: applyEditButtons(interaction.data.customId.split(idSeparator)[1] || ''),
|
||||
},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ApplicationCommandFlags, Bot, Interaction, InteractionResponseTypes } from '../../../deps.ts';
|
||||
import { dbClient, generateGuildSettingKey, lfgChannelSettings, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings, queries } from '../../db/common.ts';
|
||||
import { failColor, infoColor1, infoColor2, safelyDismissMsg, sendDirectMessage, somethingWentWrong, successColor } from '../../commandUtils.ts';
|
||||
import { generateMemberList, idSeparator, pathIdxEnder, pathIdxSeparator } from '../eventUtils.ts';
|
||||
import utils from '../../utils.ts';
|
||||
|
@ -11,7 +12,7 @@ export const confirmedCustomId = 'confirmedCustomId';
|
|||
export const confirmStr = 'yes';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.customId && interaction.data?.components?.length && interaction.channelId && interaction.guildId && interaction.member && interaction.member.user) {
|
||||
if (interaction.data?.customId && interaction.data?.components?.length && interaction.channelId && interaction.guildId && interaction?.member?.user) {
|
||||
// Light Telemetry
|
||||
dbClient.execute(queries.callIncCnt('btn-confirmDelEvent')).catch((e) => utils.commonLoggers.dbError('deleteConfirmed.ts@incCnt', 'call sproc INC_CNT on', e));
|
||||
|
||||
|
@ -37,81 +38,100 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
const userId = interaction.member.id;
|
||||
const userName = interaction.member.user.username;
|
||||
// Delete event
|
||||
bot.helpers.deleteMessage(evtChannelId, evtMessageId, 'User deleted event').then(() => {
|
||||
dbClient.execute(queries.deleteEvent, [evtChannelId, evtMessageId]).catch((e) => utils.commonLoggers.dbError('deleteConfirmed.ts@deleteEvent', 'delete event from', e));
|
||||
bot.helpers
|
||||
.deleteMessage(evtChannelId, evtMessageId, 'User deleted event')
|
||||
.then(() => {
|
||||
dbClient.execute(queries.deleteEvent, [evtChannelId, evtMessageId]).catch((e) => utils.commonLoggers.dbError('deleteConfirmed.ts@deleteEvent', 'delete event from', e));
|
||||
|
||||
// Acknowledge user so discord doesn't get annoyed
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
embeds: [{
|
||||
color: successColor,
|
||||
title: 'Event successfully deleted.',
|
||||
description: safelyDismissMsg,
|
||||
}],
|
||||
},
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('deleteConfirmed.ts', interaction, e));
|
||||
// Acknowledge user so discord doesn't get annoyed
|
||||
bot.helpers
|
||||
.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
embeds: [
|
||||
{
|
||||
color: successColor,
|
||||
title: 'Event successfully deleted.',
|
||||
description: safelyDismissMsg,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
.catch((e: Error) => utils.commonLoggers.interactionSendError('deleteConfirmed.ts', interaction, e));
|
||||
|
||||
if (actionByManager) {
|
||||
const ownerId = BigInt(eventMessage?.embeds[0].footer?.iconUrl?.split('#')[1] || '0');
|
||||
const eventEmbed = eventMessage?.embeds[0] || { title: 'Event not found', color: failColor };
|
||||
bot.helpers.sendMessage(lfgChannelSetting.logChannelId, {
|
||||
embeds: [{
|
||||
color: infoColor2,
|
||||
title: `Event deleted by a ${config.name} Manager`,
|
||||
description: `The following event was deleted by ${userName} - <@${userId}>.`,
|
||||
timestamp: new Date().getTime(),
|
||||
}, eventEmbed],
|
||||
}).catch((e: Error) => utils.commonLoggers.messageSendError('deleteConfirmed.ts', 'send log message', e));
|
||||
if (actionByManager) {
|
||||
const ownerId = BigInt(eventMessage?.embeds[0].footer?.iconUrl?.split('#')[1] || '0');
|
||||
const eventEmbed = eventMessage?.embeds[0] || { title: 'Event not found', color: failColor };
|
||||
bot.helpers
|
||||
.sendMessage(lfgChannelSetting.logChannelId, {
|
||||
embeds: [
|
||||
{
|
||||
color: infoColor2,
|
||||
title: `Event deleted by a ${config.name} Manager`,
|
||||
description: `The following event was deleted by ${userName} - <@${userId}>.`,
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
eventEmbed,
|
||||
],
|
||||
})
|
||||
.catch((e: Error) => utils.commonLoggers.messageSendError('deleteConfirmed.ts', 'send log message', e));
|
||||
|
||||
sendDirectMessage(bot, ownerId, {
|
||||
embeds: [{
|
||||
color: infoColor2,
|
||||
title: `Notice: A ${config.name} Manager has deleted one of your events in ${guildName}`,
|
||||
description: 'The deleted event is listed below.',
|
||||
fields: [
|
||||
sendDirectMessage(bot, ownerId, {
|
||||
embeds: [
|
||||
{
|
||||
name: `${config.name} Manager:`,
|
||||
value: generateMemberList([{
|
||||
id: userId,
|
||||
name: userName,
|
||||
}]),
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: 'Are you unhappy with this action?',
|
||||
value: `Please reach out to the ${config.name} Manager that performed this action, or the moderators/administrators of ${guildName}.`,
|
||||
color: infoColor2,
|
||||
title: `Notice: A ${config.name} Manager has deleted one of your events in ${guildName}`,
|
||||
description: 'The deleted event is listed below.',
|
||||
fields: [
|
||||
{
|
||||
name: `${config.name} Manager:`,
|
||||
value: generateMemberList([
|
||||
{
|
||||
id: userId,
|
||||
name: userName,
|
||||
},
|
||||
]),
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: 'Are you unhappy with this action?',
|
||||
value: `Please reach out to the ${config.name} Manager that performed this action, or the moderators/administrators of ${guildName}.`,
|
||||
},
|
||||
],
|
||||
},
|
||||
eventEmbed,
|
||||
],
|
||||
}, eventEmbed],
|
||||
}).catch((e: Error) => utils.commonLoggers.messageSendError('deleteConfirmed.ts', 'send DM fail', e));
|
||||
}
|
||||
}).catch((e) => {
|
||||
utils.commonLoggers.messageDeleteError('deleteConfirmed.ts', 'deleteEventFailedDB', e);
|
||||
somethingWentWrong(bot, interaction, 'deleteEventMessageInDeleteConfirmedButton');
|
||||
});
|
||||
} else {
|
||||
}).catch((e: Error) => utils.commonLoggers.messageSendError('deleteConfirmed.ts', 'send DM fail', e));
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
utils.commonLoggers.messageDeleteError('deleteConfirmed.ts', 'deleteEventFailedDB', e);
|
||||
somethingWentWrong(bot, interaction, 'deleteEventMessageInDeleteConfirmedButton');
|
||||
});
|
||||
} else if (tempDataMap.get(confirmedCustomId)) {
|
||||
// User either did not type yes confirm field was missing, lets see which it was
|
||||
if (tempDataMap.get(confirmedCustomId)) {
|
||||
// User did not type yes.
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
// User did not type yes.
|
||||
bot.helpers
|
||||
.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
embeds: [{
|
||||
color: infoColor1,
|
||||
title: 'Event not deleted.',
|
||||
description: `If you are trying to delete the event, please make sure you type \`${confirmStr}\` into the field provided.
|
||||
embeds: [
|
||||
{
|
||||
color: infoColor1,
|
||||
title: 'Event not deleted.',
|
||||
description: `If you are trying to delete the event, please make sure you type \`${confirmStr}\` into the field provided.
|
||||
|
||||
${safelyDismissMsg}`,
|
||||
}],
|
||||
},
|
||||
],
|
||||
},
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('deleteConfirmed.ts', interaction, e));
|
||||
} else {
|
||||
// Field was missing
|
||||
somethingWentWrong(bot, interaction, 'noIdsFromDeleteConfirmedButton');
|
||||
}
|
||||
})
|
||||
.catch((e: Error) => utils.commonLoggers.interactionSendError('deleteConfirmed.ts', interaction, e));
|
||||
} else {
|
||||
// Field was missing
|
||||
somethingWentWrong(bot, interaction, 'noIdsFromDeleteConfirmedButton');
|
||||
}
|
||||
} else {
|
||||
somethingWentWrong(bot, interaction, 'noDataFromDeleteConfirmedButton');
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Bot, Interaction, InteractionResponseTypes, MessageComponentTypes, TextStyles } from '../../../deps.ts';
|
||||
import { dbClient, generateGuildSettingKey, lfgChannelSettings, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings, queries } from '../../db/common.ts';
|
||||
import { somethingWentWrong, stopThat } from '../../commandUtils.ts';
|
||||
import { idSeparator, pathIdxEnder, pathIdxSeparator } from '../eventUtils.ts';
|
||||
import { confirmedCustomId, confirmStr, customId as deleteConfirmedCustomId } from './deleteConfirmed.ts';
|
||||
|
@ -7,8 +8,8 @@ import utils from '../../utils.ts';
|
|||
|
||||
export const customId = 'deleteEvent';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.customId && interaction.member && interaction.member.user && interaction.channelId && interaction.guildId && interaction.message && interaction.message.embeds[0]) {
|
||||
const execute = (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.customId && interaction?.member?.user && interaction.channelId && interaction.guildId && interaction?.message?.embeds?.[0]) {
|
||||
// Light Telemetry
|
||||
dbClient.execute(queries.callIncCnt('btn-delEvent')).catch((e) => utils.commonLoggers.dbError('deleteEvent.ts', 'call sproc INC_CNT on', e));
|
||||
|
||||
|
|
|
@ -2,11 +2,12 @@ import { Bot, Interaction, InteractionResponseTypes } from '../../../deps.ts';
|
|||
import { generateCustomActivityFields, idSeparator } from '../eventUtils.ts';
|
||||
import { customId as editActivityCustomId } from './editActivity.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
|
||||
export const customId = 'editActivityCustom';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
const execute = (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.customId && interaction.member && interaction.guildId && interaction.channelId) {
|
||||
// Light Telemetry
|
||||
dbClient.execute(queries.callIncCnt('btn-eeCustomAct')).catch((e) => utils.commonLoggers.dbError('step1a-openCustomModal.ts', 'call sproc INC_CNT on', e));
|
||||
|
|
|
@ -18,7 +18,8 @@ import {
|
|||
import { addTokenToMap, deleteTokenEarly, generateMapId, selfDestructMessage, tokenMap } from '../tokenCleanup.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import config from '../../../config.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import { customId as editActivityCustomCustomId } from './editActivity-custom.ts';
|
||||
import { applyEditButtons, applyEditMessage, getEventMemberCount, getLfgMembers } from './utils.ts';
|
||||
import { LFGMember } from '../../types/commandTypes.ts';
|
||||
|
@ -108,7 +109,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
!selectedActivity.maxMembers || !selectedCategory || !selectedActivity.name || (isNaN(selectedActivity.maxMembers) || (selectedActivity.maxMembers < 1 || selectedActivity.maxMembers > 99))
|
||||
) {
|
||||
// Verify fields exist
|
||||
somethingWentWrong(bot, interaction, `parseFailInEditCustomActivity@${selectedCategory}|${selectedActivity.name}|${selectedActivity.maxMembers || 'undefined'}$`);
|
||||
somethingWentWrong(bot, interaction, `parseFailInEditCustomActivity@${selectedCategory}|${selectedActivity.name}|${selectedActivity.maxMembers ?? 'undefined'}$`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -142,7 +143,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
content: applyEditMessage(new Date().getTime()),
|
||||
content: applyEditMessage(new Date().getTime(), ''),
|
||||
embeds: [eventMessage.embeds[0]],
|
||||
components: applyEditButtons(interaction.data.customId.replaceAll(fillerChar, '').split(idSeparator)[1] || ''),
|
||||
},
|
||||
|
@ -180,7 +181,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('editActivity.ts@ping', interaction, e));
|
||||
|
||||
// Update the original game selector
|
||||
await bot.helpers.editOriginalInteractionResponse(tokenMap.get(generateMapId(interaction.guildId, interaction.channelId, interaction.member.id))?.token || '', {
|
||||
await bot.helpers.editOriginalInteractionResponse(tokenMap.get(generateMapId(interaction.guildId, interaction.channelId, interaction.member.id))?.token ?? '', {
|
||||
components: selectMenus,
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('editActivity.ts@edit', interaction, e));
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Bot, Interaction, InteractionResponseTypes } from '../../../deps.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import { somethingWentWrong } from '../../commandUtils.ts';
|
||||
import { dateTimeFields, idSeparator, LfgEmbedIndexes, pathIdxEnder, pathIdxSeparator } from '../eventUtils.ts';
|
||||
import { monthsShort } from '../event-creation/dateTimeUtils.ts';
|
||||
|
@ -15,7 +16,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
|
||||
const [evtChannelId, evtMessageId] = (interaction.data.customId.replaceAll(pathIdxEnder, '').split(idSeparator)[1] || '').split(pathIdxSeparator).map((id) => BigInt(id || '0'));
|
||||
const eventMessage = await bot.helpers.getMessage(evtChannelId, evtMessageId).catch((e: Error) => utils.commonLoggers.messageGetError('editDateTime.ts', 'get eventMessage', e));
|
||||
let rawEventDateTime = eventMessage?.embeds[0].fields ? eventMessage.embeds[0].fields[LfgEmbedIndexes.StartTime].value.trim().split('\n')[0].split(' ') : [];
|
||||
const rawEventDateTime = eventMessage?.embeds[0].fields ? eventMessage.embeds[0].fields[LfgEmbedIndexes.StartTime].value.trim().split('\n')[0].split(' ') : [];
|
||||
const monthIdx = rawEventDateTime.findIndex((item) => monthsShort.includes(item.toUpperCase()));
|
||||
const prefillTime = rawEventDateTime.slice(0, monthIdx - 1).join(' ').trim();
|
||||
const prefillTimeZone = rawEventDateTime[monthIdx - 1].trim();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Bot, Interaction, InteractionResponseTypes } from '../../../deps.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import { somethingWentWrong } from '../../commandUtils.ts';
|
||||
import { descriptionTextField, idSeparator, LfgEmbedIndexes, pathIdxEnder, pathIdxSeparator } from '../eventUtils.ts';
|
||||
import utils from '../../utils.ts';
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ActionRow, ApplicationCommandFlags, Bot, ButtonStyles, Interaction, InteractionResponseTypes, MessageComponentTypes } from '../../../deps.ts';
|
||||
import { dbClient, generateGuildSettingKey, lfgChannelSettings, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings, queries } from '../../db/common.ts';
|
||||
import { infoColor1, somethingWentWrong, stopThat } from '../../commandUtils.ts';
|
||||
import { idSeparator, pathIdxEnder, pathIdxSeparator } from '../eventUtils.ts';
|
||||
import { addTokenToMap, selfDestructMessage } from '../tokenCleanup.ts';
|
||||
|
@ -11,10 +12,9 @@ import { customId as toggleWLStatusCustomId } from './toggleWLStatus.ts';
|
|||
|
||||
export const customId = 'editEvent';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
const execute = (bot: Bot, interaction: Interaction) => {
|
||||
if (
|
||||
interaction.data?.customId && interaction.member && interaction.channelId && interaction.guildId && interaction.message && interaction.message.components &&
|
||||
interaction.message.components[0].components
|
||||
interaction.data?.customId && interaction.member && interaction.channelId && interaction.guildId && interaction?.message?.components?.[0].components
|
||||
) {
|
||||
// Light Telemetry
|
||||
dbClient.execute(queries.callIncCnt('btn-editEvent')).catch((e) => utils.commonLoggers.dbError('editEvent.ts', 'call sproc INC_CNT on', e));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ApplicationCommandFlags, Bot, Interaction, InteractionResponseTypes } from '../../../deps.ts';
|
||||
import { dbClient, generateGuildSettingKey, lfgChannelSettings, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings, queries } from '../../db/common.ts';
|
||||
import { infoColor1, safelyDismissMsg, sendDirectMessage, somethingWentWrong, successColor, warnColor } from '../../commandUtils.ts';
|
||||
import { generateMemberList, idSeparator, LfgEmbedIndexes } from '../eventUtils.ts';
|
||||
import utils from '../../utils.ts';
|
||||
|
@ -10,8 +11,7 @@ export const customId = 'joinEvent';
|
|||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (
|
||||
interaction.data?.customId && interaction.member && interaction.member.user && interaction.channelId && interaction.guildId && interaction.message && interaction.message.embeds[0] &&
|
||||
interaction.message.embeds[0].fields
|
||||
interaction.data?.customId && interaction?.member?.user && interaction.channelId && interaction.guildId && interaction?.message?.embeds?.[0]?.fields
|
||||
) {
|
||||
// Light Telemetry
|
||||
dbClient.execute(queries.callIncCnt(interaction.data.customId.includes(idSeparator) ? 'btn-joinWLEvent' : 'btn-joinEvent')).catch((e) =>
|
||||
|
@ -61,7 +61,7 @@ ${safelyDismissMsg}`,
|
|||
|
||||
If this request is urgent, please speak with${urgentManagerStr}the owner of [this event](${messageUrl}), <@${ownerId}>, to resolve the issue.
|
||||
|
||||
The status of your recent Join Request for [this event](${messageUrl}) is: \`${joinRequestMap.get(joinRequestKey)?.status || 'Failed to retrieve status'}\`
|
||||
The status of your recent Join Request for [this event](${messageUrl}) is: \`${joinRequestMap.get(joinRequestKey)?.status ?? 'Failed to retrieve status'}\`
|
||||
|
||||
${safelyDismissMsg}`,
|
||||
}],
|
||||
|
@ -106,7 +106,7 @@ ${safelyDismissMsg}`,
|
|||
timestamp: new Date().getTime(),
|
||||
});
|
||||
}).catch((e: Error) => {
|
||||
somethingWentWrong(bot, interaction, 'failedToDMOwnerInRequestToJoinEventButton');
|
||||
somethingWentWrong(bot, interaction, 'failedToDMOwnerInRequestToJoinEventButton', `${config.name} could not message <@${ownerId}>. This likely means <@${ownerId}> has turned off DMs.`);
|
||||
utils.commonLoggers.messageSendError('joinEvent.ts@dmOwner', 'failed to DM owner for join request', e);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@ import { Bot, ButtonStyles, Interaction, InteractionResponseTypes, MessageCompon
|
|||
import { sendDirectMessage, somethingWentWrong, successColor, warnColor } from '../../commandUtils.ts';
|
||||
import { generateMapId, getLfgMembers, joinMemberToEvent, joinRequestMap, joinRequestResponseButtons, JoinRequestStatus } from './utils.ts';
|
||||
import { alternateEventBtnStr, idSeparator } from '../eventUtils.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import { customId as alternateRequestCustomId } from './alternateRequest.ts';
|
||||
import utils from '../../utils.ts';
|
||||
|
||||
|
@ -12,8 +13,7 @@ export const denyStr = 'denied';
|
|||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (
|
||||
interaction.data?.customId && interaction.user && interaction.channelId && interaction.message && interaction.message.embeds[0] && interaction.message.embeds[0].fields &&
|
||||
interaction.message.embeds[0].description
|
||||
interaction.data?.customId && interaction.user && interaction.channelId && interaction?.message?.embeds?.[0]?.fields && interaction?.message?.embeds?.[0]?.description
|
||||
) {
|
||||
const memberRequesting = getLfgMembers(interaction.message.embeds[0].fields[0].value || '')[0];
|
||||
const approved = interaction.data.customId.includes(approveStr);
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { Bot, Interaction } from '../../../deps.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import { somethingWentWrong } from '../../commandUtils.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import { removeMemberFromEvent } from './utils.ts';
|
||||
|
||||
export const customId = 'leaveEvent';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.customId && interaction.member && interaction.channelId && interaction.guildId && interaction.message && interaction.message.embeds[0]) {
|
||||
const execute = (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.customId && interaction.member && interaction.channelId && interaction.guildId && interaction?.message?.embeds?.[0]) {
|
||||
// Light Telemetry
|
||||
dbClient.execute(queries.callIncCnt('btn-leaveEvent')).catch((e) => utils.commonLoggers.dbError('leaveEvent.ts', 'call sproc INC_CNT on', e));
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Bot, Interaction } from '../../../deps.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import { somethingWentWrong } from '../../commandUtils.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import { removeMemberFromEvent } from './utils.ts';
|
||||
|
|
|
@ -3,7 +3,8 @@ import { dmTestMessage, safelyDismissMsg, sendDirectMessage, somethingWentWrong,
|
|||
import { idSeparator, pathIdxEnder, pathIdxSeparator } from '../eventUtils.ts';
|
||||
import { deleteTokenEarly } from '../tokenCleanup.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import { generateLFGButtons } from '../event-creation/utils.ts';
|
||||
|
||||
export const customId = 'toggleWLStatus';
|
||||
|
|
|
@ -4,7 +4,8 @@ import { generateMemberList, idSeparator, LfgEmbedIndexes, pathIdxEnder, pathIdx
|
|||
import { deleteTokenEarly } from '../tokenCleanup.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import config from '../../../config.ts';
|
||||
import { dbClient, generateGuildSettingKey, lfgChannelSettings, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings, queries } from '../../db/common.ts';
|
||||
import { getGuildName } from './utils.ts';
|
||||
|
||||
export const customId = 'updateEvent';
|
||||
|
|
|
@ -6,7 +6,8 @@ import { selfDestructMessage } from '../tokenCleanup.ts';
|
|||
import { approveStr, customId as joinRequestCustomId, denyStr } from './joinRequest.ts';
|
||||
import { customId as updateEventCustomId } from './updateEvent.ts';
|
||||
import { customId as leaveViaDMCustomId } from './leaveViaDM.ts';
|
||||
import { dbClient, queries } from '../../db.ts';
|
||||
import { dbClient } from '../../db/client.ts';
|
||||
import { queries } from '../../db/common.ts';
|
||||
import utils from '../../utils.ts';
|
||||
|
||||
// Join status map to prevent spamming the system
|
||||
|
@ -130,7 +131,7 @@ ${safelyDismissMsg}`,
|
|||
// Generic no response response
|
||||
const noEdit = async (bot: Bot, interaction: Interaction, loudAcknowledge: boolean) => {
|
||||
if (loudAcknowledge) {
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
await bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
|
@ -144,7 +145,7 @@ ${safelyDismissMsg}`,
|
|||
},
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('utils.ts', interaction, e));
|
||||
} else {
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
await bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.DeferredUpdateMessage,
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('utils.ts', interaction, e));
|
||||
}
|
||||
|
@ -193,7 +194,7 @@ export const removeMemberFromEvent = async (
|
|||
await sendDirectMessage(bot, memberToPromote.id, {
|
||||
embeds: [{
|
||||
color: successColor,
|
||||
title: 'Good news, you\'ve been promoted!',
|
||||
title: "Good news, you've been promoted!",
|
||||
description: `A member left [the full event](${utils.idsToMessageUrl(urlIds)}) in \`${await getGuildName(
|
||||
bot,
|
||||
evtGuildId,
|
||||
|
@ -352,8 +353,8 @@ export const joinRequestResponseButtons = (disabled: boolean): ActionRow[] => [{
|
|||
}];
|
||||
|
||||
export const applyEditButtonName = 'Apply Edit';
|
||||
export const applyEditMessage = (currentTime: number) =>
|
||||
`Please verify the updated event below, then click on the \`${applyEditButtonName}\` button. If this does not look right, please dismiss this message and start over.\n\n${
|
||||
export const applyEditMessage = (currentTime: number, usTZWarning: string) =>
|
||||
`${usTZWarning}Please verify the updated event below, then click on the \`${applyEditButtonName}\` button. If this does not look right, please dismiss this message and start over.\n\n${
|
||||
selfDestructMessage(currentTime)
|
||||
}`;
|
||||
export const applyEditButtons = (idxPath: string): ActionRow[] => [{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationCommandFlags, Bot, CreateMessage, Embed, Interaction, InteractionResponseTypes } from '../deps.ts';
|
||||
import config from '../config.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings } from './db.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings } from './db/common.ts';
|
||||
import utils from './utils.ts';
|
||||
import { helpSlashName, infoSlashName, reportSlashName } from './commands/slashCommandNames.ts';
|
||||
|
||||
|
@ -27,7 +27,7 @@ export const isLFGChannel = (guildId: bigint, channelId: bigint) => {
|
|||
};
|
||||
|
||||
// Tell user to try again or report issue
|
||||
export const somethingWentWrong = async (bot: Bot, interaction: Interaction, errorCode: string) =>
|
||||
export const somethingWentWrong = (bot: Bot, interaction: Interaction, errorCode: string, possibleFix = 'No fix provided.') =>
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
|
@ -35,17 +35,26 @@ export const somethingWentWrong = async (bot: Bot, interaction: Interaction, err
|
|||
embeds: [{
|
||||
color: failColor,
|
||||
title: 'Something went wrong...',
|
||||
description: `You should not be able to get here. Please try again and if the issue continues, \`/${reportSlashName}\` this issue to the developers with the error code below.`,
|
||||
description:
|
||||
`You should not be able to get here. If ${config.name} has seen this error before, the developer may have a possible fix for you to try. If one is provided, please attempt it before \`/${reportSlashName}\`ing it. If the issue continues, please \`/${reportSlashName}\` this issue to the developer with the error code below.`,
|
||||
fields: [{
|
||||
name: 'Error Code:',
|
||||
value: `\`${errorCode}\``,
|
||||
}, {
|
||||
name: 'Possible Fix:',
|
||||
value: possibleFix,
|
||||
}],
|
||||
}],
|
||||
},
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('commandUtils.ts@somethingWentWrong', interaction, e));
|
||||
|
||||
// Possible fixes for the user to try before reporting.
|
||||
export const commonFixes = {
|
||||
CANT_SEND_MESSAGE: `Please verify ${config.name} has permission to send messages in this channel.`,
|
||||
};
|
||||
|
||||
// Smack the user for trying to modify an event that isn't theirs
|
||||
export const stopThat = async (bot: Bot, interaction: Interaction, stopWhat: string) =>
|
||||
export const stopThat = (bot: Bot, interaction: Interaction, stopWhat: string) =>
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
import config from '../../config.ts';
|
||||
import { ApplicationCommandOptionTypes, ApplicationCommandTypes, Bot, DiscordEmbedField, Interaction, InteractionResponseTypes } from '../../deps.ts';
|
||||
import { ApplicationCommandOptionTypes, ApplicationCommandTypes, BotWithCache, DiscordEmbedField, Interaction, InteractionResponseTypes } from '../../deps.ts';
|
||||
import { infoColor2, isLFGChannel, somethingWentWrong } from '../commandUtils.ts';
|
||||
import { dbClient, queries } from '../db.ts';
|
||||
import { dbClient } from '../db/client.ts';
|
||||
import { queries } from '../db/common.ts';
|
||||
import { CommandDetails } from '../types/commandTypes.ts';
|
||||
import utils from '../utils.ts';
|
||||
import { auditSlashName } from './slashCommandNames.ts';
|
||||
|
||||
type DupeAct = {
|
||||
upperActTitle?: string;
|
||||
upperActSubtitle?: string;
|
||||
dupeCount: number;
|
||||
};
|
||||
|
||||
type DBSizeTable = {
|
||||
table: string;
|
||||
size: number;
|
||||
rows: number;
|
||||
};
|
||||
|
||||
const auditDbName = 'database';
|
||||
const auditCustomActivities = 'custom-activities';
|
||||
const auditCustomActivitiesName = 'custom-activities';
|
||||
const auditGuildName = 'guilds';
|
||||
|
||||
const details: CommandDetails = {
|
||||
|
@ -22,7 +35,7 @@ const details: CommandDetails = {
|
|||
description: `Developer Command: Checks ${config.name}'s DB size.`,
|
||||
},
|
||||
{
|
||||
name: auditCustomActivities,
|
||||
name: auditCustomActivitiesName,
|
||||
type: ApplicationCommandOptionTypes.SubCommand,
|
||||
description: 'Developer Command: Checks for duplicate custom activities.',
|
||||
},
|
||||
|
@ -34,18 +47,18 @@ const details: CommandDetails = {
|
|||
],
|
||||
};
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
const execute = async (bot: BotWithCache, interaction: Interaction) => {
|
||||
if (interaction.member && interaction.guildId && interaction.data?.options?.[0].options) {
|
||||
dbClient.execute(queries.callIncCnt('cmd-audit')).catch((e) => utils.commonLoggers.dbError('audit.ts@inc', 'call sproc INC_CNT on', e));
|
||||
const auditName = interaction.data.options[0].name;
|
||||
switch (auditName) {
|
||||
case auditDbName:
|
||||
case auditDbName: {
|
||||
// Get DB statistics
|
||||
const auditQuery = await dbClient.query(`SELECT * FROM db_size;`).catch((e) => utils.commonLoggers.dbError('audit.ts@dbSize', 'query', e));
|
||||
const auditQuery: Array<DBSizeTable> = await dbClient.query(`SELECT * FROM db_size;`).catch((e) => utils.commonLoggers.dbError('audit.ts@dbSize', 'query', e));
|
||||
|
||||
// Turn all tables into embed fields, currently only properly will handle 25 tables, but we'll fix that when group up gets 26 tables
|
||||
const embedFields: Array<DiscordEmbedField> = [];
|
||||
auditQuery.forEach((row: any) => {
|
||||
auditQuery.forEach((row) => {
|
||||
embedFields.push({
|
||||
name: `${row.table}`,
|
||||
value: `**Size:** ${row.size} MB
|
||||
|
@ -53,26 +66,129 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
inline: true,
|
||||
});
|
||||
});
|
||||
bot.helpers.sendInteractionResponse(
|
||||
interaction.id,
|
||||
interaction.token,
|
||||
{
|
||||
bot.helpers
|
||||
.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: isLFGChannel(interaction.guildId || 0n, interaction.channelId || 0n),
|
||||
embeds: [
|
||||
{
|
||||
color: infoColor2,
|
||||
title: 'Database Audit',
|
||||
description: 'Lists all tables with their current size and row count.',
|
||||
timestamp: new Date().getTime(),
|
||||
fields: embedFields.slice(0, 25),
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
.catch((e: Error) => utils.commonLoggers.interactionSendError('audit.ts@dbSize', interaction, e));
|
||||
break;
|
||||
}
|
||||
case auditCustomActivitiesName: {
|
||||
const dupActTitles: Array<DupeAct> = await dbClient.query(
|
||||
`SELECT UPPER(activityTitle) as upperActTitle, COUNT(*) as dupeCount FROM custom_activities GROUP BY upperActTitle HAVING dupeCount > 1;`,
|
||||
).catch((e) => utils.commonLoggers.dbError('audit.ts@customActTitle', 'query', e));
|
||||
const dupActSubTitles: Array<DupeAct> = await dbClient.query(
|
||||
`SELECT UPPER(activitySubtitle) as upperActSubtitle, COUNT(*) as dupeCount FROM custom_activities GROUP BY upperActSubtitle HAVING dupeCount > 1;`,
|
||||
).catch((e) => utils.commonLoggers.dbError('audit.ts@customActSubTitle', 'query', e));
|
||||
const dupActs: Array<DupeAct> = await dbClient
|
||||
.query(
|
||||
`SELECT UPPER(activityTitle) as upperActTitle, UPPER(activitySubtitle) as upperActSubtitle, COUNT(*) as dupeCount FROM custom_activities GROUP BY upperActTitle, upperActSubtitle HAVING dupeCount > 1;`,
|
||||
)
|
||||
.catch((e) => utils.commonLoggers.dbError('audit.ts@customAct', 'query', e));
|
||||
|
||||
bot.helpers
|
||||
.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: isLFGChannel(interaction.guildId || 0n, interaction.channelId || 0n),
|
||||
content: 'Duplicate Custom Activity Titles, Subtitles, and Activities:',
|
||||
embeds: [
|
||||
{
|
||||
color: infoColor2,
|
||||
title: 'Duplicate Activity Titles:',
|
||||
description: dupActTitles.map((dupAct) => `${dupAct.upperActTitle}: ${dupAct.dupeCount}`).join('\n'),
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
{
|
||||
color: infoColor2,
|
||||
title: 'Duplicate Activity Subtitles:',
|
||||
description: dupActSubTitles.map((dupAct) => `${dupAct.upperActSubtitle}: ${dupAct.dupeCount}`).join('\n'),
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
{
|
||||
color: infoColor2,
|
||||
title: 'Duplicate Activities (Title/Subtitle):',
|
||||
description: dupActs.map((dupAct) => `${dupAct.upperActTitle}/${dupAct.upperActSubtitle}: ${dupAct.dupeCount}`).join('\n'),
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
.catch((e: Error) => utils.commonLoggers.interactionSendError('audit.ts@dbSize', interaction, e));
|
||||
break;
|
||||
}
|
||||
case auditGuildName: {
|
||||
let totalCount = 0;
|
||||
let auditText = '';
|
||||
|
||||
bot.guilds.forEach((guild) => {
|
||||
totalCount += guild.memberCount;
|
||||
auditText += `Guild: ${guild.name} (${guild.id})
|
||||
Owner: ${guild.ownerId}
|
||||
Tot mem: ${guild.memberCount}
|
||||
|
||||
`;
|
||||
});
|
||||
|
||||
const b = await new Blob([auditText as BlobPart], { 'type': 'text' });
|
||||
const tooBig = await new Blob(['tooBig' as BlobPart], { 'type': 'text' });
|
||||
|
||||
bot.helpers
|
||||
.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: isLFGChannel(interaction.guildId || 0n, interaction.channelId || 0n),
|
||||
embeds: [{
|
||||
color: infoColor2,
|
||||
title: 'Database Audit',
|
||||
description: 'Lists all tables with their current size and row count.',
|
||||
title: 'Guilds Audit',
|
||||
description: `Shows details of the guilds that ${config.name} serves.
|
||||
|
||||
Please see attached file for audit details on cached guilds and members.`,
|
||||
fields: [
|
||||
{
|
||||
name: 'Total Guilds:',
|
||||
value: `${bot.guilds.size}`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: 'Uncached Guilds:',
|
||||
value: `${bot.dispatchedGuildIds.size}`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: 'Total Members\n(may be artificially higher if 1 user is in multiple guilds the bot is in):',
|
||||
value: `${totalCount}`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: 'Average members per guild:',
|
||||
value: `${(totalCount / bot.guilds.size).toFixed(2)}`,
|
||||
inline: true,
|
||||
},
|
||||
],
|
||||
timestamp: new Date().getTime(),
|
||||
fields: embedFields.slice(0, 25),
|
||||
}],
|
||||
file: {
|
||||
'blob': b.size > 8388290 ? tooBig : b,
|
||||
'name': 'auditDetails.txt',
|
||||
},
|
||||
},
|
||||
},
|
||||
).catch((e: Error) => utils.commonLoggers.interactionSendError('audit.ts@dbSize', interaction, e));
|
||||
})
|
||||
.catch((e: Error) => utils.commonLoggers.interactionSendError('audit.ts@guilds', interaction, e));
|
||||
break;
|
||||
case auditCustomActivities:
|
||||
case auditGuildName:
|
||||
}
|
||||
default:
|
||||
somethingWentWrong(bot, interaction, `auditNameNotHandled@${auditName}`);
|
||||
break;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import config from '../../config.ts';
|
||||
import { ApplicationCommandFlags, ApplicationCommandTypes, Bot, Interaction, InteractionResponseTypes } from '../../deps.ts';
|
||||
import { failColor, safelyDismissMsg, somethingWentWrong, successColor } from '../commandUtils.ts';
|
||||
import { dbClient, generateGuildSettingKey, lfgChannelSettings, queries } from '../db.ts';
|
||||
import { dbClient } from '../db/client.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings, queries } from '../db/common.ts';
|
||||
import { CommandDetails } from '../types/commandTypes.ts';
|
||||
import utils from '../utils.ts';
|
||||
import { deleteSlashName, setupSlashName } from './slashCommandNames.ts';
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import config from '../../config.ts';
|
||||
import { ApplicationCommandTypes, Bot, Interaction, InteractionResponseTypes } from '../../deps.ts';
|
||||
import { infoColor1, isLFGChannel } from '../commandUtils.ts';
|
||||
import { dbClient, queries } from '../db.ts';
|
||||
import { dbClient } from '../db/client.ts';
|
||||
import { queries } from '../db/common.ts';
|
||||
import { CommandDetails } from '../types/commandTypes.ts';
|
||||
import utils from '../utils.ts';
|
||||
import { createEventSlashName, helpSlashName, setupSlashName } from './slashCommandNames.ts';
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import config from '../../config.ts';
|
||||
import { ApplicationCommandTypes, Bot, Interaction, InteractionResponseTypes } from '../../deps.ts';
|
||||
import { infoEmbed, isLFGChannel } from '../commandUtils.ts';
|
||||
import { dbClient, queries } from '../db.ts';
|
||||
import { dbClient } from '../db/client.ts';
|
||||
import { queries } from '../db/common.ts';
|
||||
import { CommandDetails } from '../types/commandTypes.ts';
|
||||
import utils from '../utils.ts';
|
||||
import { infoSlashName } from './slashCommandNames.ts';
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { ApplicationCommandFlags, ApplicationCommandOptionTypes, ApplicationCommandTypes, Bot, Interaction, InteractionResponseTypes } from '../../deps.ts';
|
||||
import { alternateMemberToEvent, getGuildName, joinMemberToEvent, removeMemberFromEvent } from '../buttons/live-event/utils.ts';
|
||||
import { generateMemberList } from '../buttons/eventUtils.ts';
|
||||
import { dbClient, generateGuildSettingKey, lfgChannelSettings, queries } from '../db.ts';
|
||||
import { dbClient } from '../db/client.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings, queries } from '../db/common.ts';
|
||||
import { infoColor2, safelyDismissMsg, sendDirectMessage, somethingWentWrong, stopThat, warnColor } from '../commandUtils.ts';
|
||||
import { CommandDetails, LFGMember } from '../types/commandTypes.ts';
|
||||
import config from '../../config.ts';
|
||||
|
@ -44,7 +45,7 @@ const details: CommandDetails = {
|
|||
};
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data?.options?.[0].options && interaction.channelId && interaction.guildId && interaction.member && interaction.member.user) {
|
||||
if (interaction.data?.options?.[0].options && interaction.channelId && interaction.guildId && interaction?.member?.user) {
|
||||
// Get action and log to db
|
||||
const actionName = interaction.data.options[0].name;
|
||||
dbClient.execute(queries.callIncCnt(`cmd-${actionName}`)).catch((e) => utils.commonLoggers.dbError('managerJLA.ts', 'call sproc INC_CNT on', e));
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import config from '../../config.ts';
|
||||
import { ApplicationCommandOptionTypes, ApplicationCommandTypes, Bot, Interaction, InteractionResponseTypes } from '../../deps.ts';
|
||||
import { infoColor2, isLFGChannel, somethingWentWrong, successColor } from '../commandUtils.ts';
|
||||
import { dbClient, queries } from '../db.ts';
|
||||
import { dbClient } from '../db/client.ts';
|
||||
import { queries } from '../db/common.ts';
|
||||
import { CommandDetails } from '../types/commandTypes.ts';
|
||||
import utils from '../utils.ts';
|
||||
import { reportSlashName } from './slashCommandNames.ts';
|
||||
|
@ -30,6 +31,9 @@ const execute = (bot: Bot, interaction: Interaction) => {
|
|||
color: infoColor2,
|
||||
title: 'USER REPORT:',
|
||||
description: interaction.data.options[0].value as string,
|
||||
footer: {
|
||||
text: `${interaction.guildId}-${interaction.user.id}`,
|
||||
},
|
||||
}],
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('report.ts:28', interaction, e));
|
||||
bot.helpers.sendInteractionResponse(
|
||||
|
|
|
@ -14,7 +14,8 @@ import {
|
|||
OverwriteTypes,
|
||||
} from '../../deps.ts';
|
||||
import { failColor, infoColor2, safelyDismissMsg, somethingWentWrong, successColor } from '../commandUtils.ts';
|
||||
import { dbClient, generateGuildSettingKey, lfgChannelSettings, queries } from '../db.ts';
|
||||
import { dbClient } from '../db/client.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings, queries } from '../db/common.ts';
|
||||
import { CommandDetails } from '../types/commandTypes.ts';
|
||||
import utils from '../utils.ts';
|
||||
import { customId as gameSelId } from '../buttons/event-creation/step1-gameSelection.ts';
|
||||
|
@ -240,7 +241,7 @@ The Discord Slash Command system will ensure you provide all the required detail
|
|||
const msgsToDel: Array<bigint> = [];
|
||||
const oldLfgMsgs: Array<bigint> = [];
|
||||
messages.forEach((msg) => {
|
||||
if (msg.authorId === botId && msg.embeds.length && msg.embeds[0].footer && msg.embeds[0].footer.text.includes('Created by:')) {
|
||||
if (msg.authorId === botId && msg.embeds.length && msg.embeds[0].footer?.text.includes('Created by:')) {
|
||||
oldLfgMsgs.push(msg.id);
|
||||
} else {
|
||||
msgsToDel.push(msg.id);
|
||||
|
@ -265,7 +266,7 @@ The Discord Slash Command system will ensure you provide all the required detail
|
|||
oldEvent.embeds[0].fields[LfgEmbedIndexes.StartTime].value = generateTimeFieldStr(eventDateTimeStr, eventDateTime);
|
||||
oldEvent.embeds[0].footer.text = oldEvent.embeds[0].footer.text.split(' | ')[0];
|
||||
const ownerName = oldEvent.embeds[0].footer.text.split(': ')[1];
|
||||
const ownerId = eventMembers.find((member) => ownerName === member.name)?.id || 0n;
|
||||
const ownerId = eventMembers.find((member) => ownerName === member.name)?.id ?? 0n;
|
||||
oldEvent.embeds[0].footer.iconUrl = `${config.links.creatorIcon}#${ownerId}`;
|
||||
bot.helpers.editMessage(oldEvent.channelId, oldEvent.id, {
|
||||
content: '',
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import config from '../../config.ts';
|
||||
import { Client } from '../../deps.ts';
|
||||
import { LOCALMODE } from '../../flags.ts';
|
||||
|
||||
export const dbClient = await new Client().connect({
|
||||
hostname: LOCALMODE ? config.db.localhost : config.db.host,
|
||||
port: config.db.port,
|
||||
db: config.db.name,
|
||||
username: config.db.username,
|
||||
password: config.db.password,
|
||||
});
|
|
@ -1,15 +1,5 @@
|
|||
import config from '../config.ts';
|
||||
import { Client } from '../deps.ts';
|
||||
import { LOCALMODE } from '../flags.ts';
|
||||
import { DBGuildSettings, LfgChannelSetting } from './types/commandTypes.ts';
|
||||
|
||||
export const dbClient = await new Client().connect({
|
||||
hostname: LOCALMODE ? config.db.localhost : config.db.host,
|
||||
port: config.db.port,
|
||||
db: config.db.name,
|
||||
username: config.db.username,
|
||||
password: config.db.password,
|
||||
});
|
||||
import { dbClient } from './client.ts';
|
||||
import { DBGuildSettings, LfgChannelSetting } from '../types/commandTypes.ts';
|
||||
|
||||
export const queries = {
|
||||
callIncCnt: (cmdName: string) => `CALL INC_CNT("${cmdName}");`,
|
|
@ -1,7 +1,8 @@
|
|||
import config from '../../config.ts';
|
||||
import { Bot, log, LT } from '../../deps.ts';
|
||||
import { warnColor } from '../commandUtils.ts';
|
||||
import { dbClient, lfgChannelSettings } from '../db.ts';
|
||||
import { dbClient } from '../db/client.ts';
|
||||
import { lfgChannelSettings } from '../db/common.ts';
|
||||
import utils from '../utils.ts';
|
||||
|
||||
export const guildDelete = async (bot: Bot, guildId: bigint) => {
|
||||
|
|
|
@ -2,9 +2,10 @@ import config from '../../config.ts';
|
|||
import utils from '../utils.ts';
|
||||
import { Bot, botId, Message } from '../../deps.ts';
|
||||
import { infoEmbed } from '../commandUtils.ts';
|
||||
import { dbClient, generateGuildSettingKey, lfgChannelSettings, queries } from '../db.ts';
|
||||
import { dbClient } from '../db/client.ts';
|
||||
import { generateGuildSettingKey, lfgChannelSettings, queries } from '../db/common.ts';
|
||||
|
||||
export const messageCreate = async (bot: Bot, message: Message) => {
|
||||
export const messageCreate = (bot: Bot, message: Message) => {
|
||||
// Ignore self
|
||||
if (botId === message.authorId) return;
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ import { LOCALMODE } from '../../flags.ts';
|
|||
import { getRandomStatus, successColor } from '../commandUtils.ts';
|
||||
import { ActiveEvent } from '../types/commandTypes.ts';
|
||||
import utils from '../utils.ts';
|
||||
import { dbClient, queries } from '../db.ts';
|
||||
import { dbClient } from '../db/client.ts';
|
||||
import { queries } from '../db/common.ts';
|
||||
import { deleteEvent, handleFailures, lockEvent, notifyEventMembers, tenMinutes } from '../notificationSystem.ts';
|
||||
import { updateBotListStatistics } from '../botListPoster.ts';
|
||||
|
||||
|
@ -27,7 +28,7 @@ export const ready = (rawBot: Bot) => {
|
|||
|
||||
// Interval to rotate the status text every 30 seconds to show off more commands
|
||||
if (botStatusIntervalId) clearInterval(botStatusIntervalId);
|
||||
botStatusIntervalId = setInterval(async () => {
|
||||
botStatusIntervalId = setInterval(() => {
|
||||
log(LT.LOG, 'Changing bot status');
|
||||
bot.helpers.editBotStatus({
|
||||
activities: [{
|
||||
|
|
|
@ -4,7 +4,8 @@ import { LfgEmbedIndexes } from './buttons/eventUtils.ts';
|
|||
import { getEventMemberCount, getGuildName, getLfgMembers } from './buttons/live-event/utils.ts';
|
||||
import { failColor, infoColor1, sendDirectMessage, warnColor } from './commandUtils.ts';
|
||||
import { reportSlashName } from './commands/slashCommandNames.ts';
|
||||
import { dbClient, queries } from './db.ts';
|
||||
import { dbClient } from './db/client.ts';
|
||||
import { queries } from './db/common.ts';
|
||||
import { ActiveEvent } from './types/commandTypes.ts';
|
||||
import utils from './utils.ts';
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ApplicationCommandOption, ApplicationCommandTypes, PermissionStrings } from '../../deps.ts';
|
||||
import { ApplicationCommandOption, ApplicationCommandTypes, Bot, BotWithCache, Interaction, PermissionStrings } from '../../deps.ts';
|
||||
|
||||
export type CommandDetails = {
|
||||
name: string;
|
||||
|
@ -11,12 +11,12 @@ export type CommandDetails = {
|
|||
|
||||
export type Command = {
|
||||
details: CommandDetails;
|
||||
execute: Function;
|
||||
execute: ((bot: Bot, interaction: Interaction) => void) | ((bot: BotWithCache, interaction: Interaction) => void);
|
||||
};
|
||||
|
||||
export type Button = {
|
||||
customId: string;
|
||||
execute: Function;
|
||||
execute: ((bot: Bot, interaction: Interaction) => void) | ((bot: BotWithCache, interaction: Interaction) => void);
|
||||
};
|
||||
|
||||
export type LfgChannelSetting = {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { CreateMessage, Interaction, log, LT, Message } from '../deps.ts';
|
||||
import { UrlIds } from './types/commandTypes.ts';
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const jsonStringifyBig = (input: any) => {
|
||||
return JSON.stringify(input, (_key, value) => typeof value === 'bigint' ? value.toString() + 'n' : value);
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ const tzOverrides: Array<Array<string>> = [
|
|||
['PST', '-08:00'],
|
||||
['IST', '+05:30'],
|
||||
];
|
||||
const abbrOverrides: Array<string> = tzOverrides.map(tzSet => tzSet[0]);
|
||||
const abbrOverrides: Array<string> = tzOverrides.map((tzSet) => tzSet[0]);
|
||||
|
||||
// Prefill the map
|
||||
for (const override of tzOverrides) {
|
||||
|
@ -22,11 +22,9 @@ for (const override of tzOverrides) {
|
|||
const attemptAdd = (tzAbbr: string, tzOffset: string) => {
|
||||
if (!abbrOverrides.includes(tzAbbr)) {
|
||||
if (tzMap.has(tzAbbr) && tzMap.get(tzAbbr) !== tzOffset) {
|
||||
console.error(`DOUBLED TZ ABBR WITH DIFF OFFSETS: ${tzAbbr} | ${tzOffset} | ${tzMap.get(tzAbbr)}`)
|
||||
} else {
|
||||
if (!tzAbbr.includes('+') && !tzAbbr.includes('-')) {
|
||||
tzMap.set(tzAbbr, tzOffset);
|
||||
}
|
||||
console.error(`DOUBLED TZ ABBR WITH DIFF OFFSETS: ${tzAbbr} | ${tzOffset} | ${tzMap.get(tzAbbr)}`);
|
||||
} else if (!tzAbbr.includes('+') && !tzAbbr.includes('-')) {
|
||||
tzMap.set(tzAbbr, tzOffset);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -34,10 +32,10 @@ const attemptAdd = (tzAbbr: string, tzOffset: string) => {
|
|||
// Get each TZ from the csv
|
||||
for (const row of csvRows) {
|
||||
const [rawSTDOffset, rawDSTOffset, rawSTDAbbr, rawDSTAbbr] = row.replaceAll('?', '-').toUpperCase().split(',');
|
||||
const STDOffset = (rawSTDOffset || '');
|
||||
const DSTOffset = (rawDSTOffset || '');
|
||||
const STDAbbr = (rawSTDAbbr || '');
|
||||
const DSTAbbr = (rawDSTAbbr || '');
|
||||
const STDOffset = rawSTDOffset || '';
|
||||
const DSTOffset = rawDSTOffset || '';
|
||||
const STDAbbr = rawSTDAbbr || '';
|
||||
const DSTAbbr = rawDSTAbbr || '';
|
||||
|
||||
attemptAdd(STDAbbr, STDOffset);
|
||||
if (STDAbbr !== DSTAbbr) {
|
||||
|
@ -47,7 +45,7 @@ for (const row of csvRows) {
|
|||
|
||||
// Log it out to copy to source
|
||||
const tzIt = tzMap.entries();
|
||||
let tzVal = tzIt.next()
|
||||
let tzVal = tzIt.next();
|
||||
while (!tzVal.done) {
|
||||
if (tzVal.value[0]) {
|
||||
console.log(`['${tzVal.value[0]}','${tzVal.value[1]}'],`);
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
|
||||
<meta name="HandheldFriendly" content="true"/>
|
||||
|
||||
<meta name="author" content="Ean Milligan (ean@milligan.dev)">
|
||||
<meta name="designer" content="Ean Milligan (ean@milligan.dev)">
|
||||
<meta name="publisher" content="Ean Milligan (ean@milligan.dev)">
|
||||
|
||||
<title>Group Up Time Checker</title>
|
||||
<meta name="description" content="The Group Up Discord Bot is a fancy event scheduler. This page converts the time of an event to the user's local time.">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="revisit-after" content="7 days">
|
||||
<meta name="distribution" content="web">
|
||||
<meta name="robots" content="noodp, noydir">
|
||||
|
||||
<meta name="distribution" content="web">
|
||||
<meta name="web_author" content="Ean Milligan (ean@milligan.dev)">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
font-size: 5rem;
|
||||
|
||||
height: 100vh;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
text-align: center;
|
||||
|
||||
color: #dcddde;
|
||||
background-color: #2f3136;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="message">
|
||||
I don't know why you are here, the URL should have a timestamp in it.
|
||||
</div>
|
||||
<script>
|
||||
if (window.location.hash) {
|
||||
var groupDate = new Date(parseInt(window.location.hash.substr(1)));
|
||||
document.getElementById("message").innerText = "Your event is happening at:\n\n" + groupDate.toLocaleString();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue