diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c170f8a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +bbLibConfig.ts +logs + +db/update.ts + +deno.lock diff --git a/.sonarcloud.properties b/.sonarcloud.properties new file mode 100644 index 0000000..06f3344 --- /dev/null +++ b/.sonarcloud.properties @@ -0,0 +1,15 @@ +# Path to sources +sonar.sources=. +#sonar.exclusions= +#sonar.inclusions= + +# Path to tests +#sonar.tests= +#sonar.test.exclusions= +#sonar.test.inclusions= + +# Source encoding +sonar.sourceEncoding=UTF-8 + +# Exclusions for copy-paste detection +#sonar.cpd.exclusions= \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a3b540f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "deno.enable": true, + "deno.lint": true, + "deno.unstable": true, + "deno.import_intellisense_origins": { + "https://deno.land": true + }, + "spellright.language": [ + "en" + ], + "spellright.documentTypes": [], + "deno.suggest.imports.hosts": { + "https://deno.land": true + }, + "cSpell.words": [ + "sproc", + "USTZ" + ] +} \ No newline at end of file diff --git a/bbLibConfig.example.ts b/bbLibConfig.example.ts new file mode 100644 index 0000000..a23dcc7 --- /dev/null +++ b/bbLibConfig.example.ts @@ -0,0 +1,13 @@ +import { BBLibConfig } from './src/types/bbLibConfig.d.ts' +export const bbLibConfig: BBLibConfig = { + 'name': 'BBLib', + 'version': '0.0.0', + '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 + '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 + 'username': '', // Username for the account that will access your DB, this account will need "DB Manager" admin rights and "REFERENCES" Global Privileges + '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 + }, +}; diff --git a/db/initialize.ts b/db/initialize.ts new file mode 100644 index 0000000..24a849b --- /dev/null +++ b/db/initialize.ts @@ -0,0 +1,113 @@ +// This file will create all tables for the groupup schema +// DATA WILL BE LOST IF DB ALREADY EXISTS, RUN AT OWN RISK + +import bbLibConfig from '../bbLibConfig.ts'; + +console.log('Attempting to create DB'); +await dbClient.execute(`CREATE SCHEMA IF NOT EXISTS ${bbLibConfig.db.name};`); +await dbClient.execute(`USE ${bbLibConfig.db.name}`); +console.log('DB created'); + +console.log('Attempt to drop all tables'); +await dbClient.execute(`DROP VIEW IF EXISTS db_size;`); +await dbClient.execute(`DROP PROCEDURE IF EXISTS INC_CNT;`); +await dbClient.execute(`DROP TABLE IF EXISTS command_cnt;`); +await dbClient.execute(`DROP TABLE IF EXISTS guild_settings;`); +await dbClient.execute(`DROP TABLE IF EXISTS active_events;`); +await dbClient.execute(`DROP TABLE IF EXISTS custom_activities;`); +console.log('Tables dropped'); + +console.log('Attempting to create table command_cnt'); +await dbClient.execute(` + CREATE TABLE command_cnt ( + command char(20) NOT NULL, + count bigint unsigned NOT NULL DEFAULT 0, + PRIMARY KEY (command), + UNIQUE KEY command_cnt_command_UNIQUE (command) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +`); +console.log('Table created'); + +console.log('Attempt creating increment Stored Procedure'); +await dbClient.execute(` + CREATE PROCEDURE INC_CNT( + IN cmd CHAR(20) + ) + BEGIN + declare oldCnt bigint unsigned; + set oldCnt = (SELECT count FROM command_cnt WHERE command = cmd); + UPDATE command_cnt SET count = oldCnt + 1 WHERE command = cmd; + END +`); +console.log('Stored Procedure created'); + +console.log('Attempting to create table guild_settings'); +await dbClient.execute(` + CREATE TABLE guild_settings ( + guildId bigint unsigned NOT NULL, + lfgChannelId bigint unsigned NOT NULL, + managerRoleId bigint unsigned NOT NULL, + logChannelId bigint unsigned NOT NULL, + PRIMARY KEY (guildId, lfgChannelId) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +`); +console.log('Table created'); + +console.log('Attempting to create table active_events'); +await dbClient.execute(` + CREATE TABLE active_events ( + messageId bigint unsigned NOT NULL, + channelId bigint unsigned NOT NULL, + guildId bigint unsigned NOT NULL, + ownerId bigint unsigned NOT NULL, + eventTime datetime NOT NULL, + notifiedFlag tinyint(1) NOT NULL DEFAULT 0, + lockedFlag tinyint(1) NOT NULL DEFAULT 0, + PRIMARY KEY (messageId, channelId) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +`); +console.log('Table created'); +/** + * notifiedFlag + * 0 = Not notified + * 1 = Notified Successfully + * -1 = Failed to notify + * lockedFlag + * 0 = Not locked + * 1 = Locked Successfully + * -1 = Failed to lock + * + * If both are -1, the event failed to delete + */ + +console.log('Attempting to create table custom_activities'); +await dbClient.execute(` + CREATE TABLE custom_activities ( + id int unsigned NOT NULL AUTO_INCREMENT, + guildId bigint unsigned NOT NULL, + activityTitle char(35) NOT NULL, + activitySubtitle char(50) NOT NULL, + maxMembers tinyint NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY custom_activities_id_UNIQUE (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +`); +console.log('Table created'); + +// Database sizes view +console.log('Attempting to create view db_size'); +await dbClient.execute(` + CREATE VIEW db_size AS + SELECT + table_name AS "table", + ROUND(((data_length + index_length) / 1024 / 1024), 3) AS "size", + table_rows AS "rows" + FROM information_schema.TABLES + WHERE + table_schema = "${config.db.name}" + AND table_name <> "db_size"; +`); +console.log('View Created'); + +await dbClient.close(); +console.log('Done!'); diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..ce9e5f1 --- /dev/null +++ b/deno.json @@ -0,0 +1,47 @@ +{ + "compilerOptions": { + "allowJs": true, + "lib": [ + "deno.window" + ], + "strict": true + }, + "lint": { + "files": { + "include": [ + "src/", + "db/", + "mod.ts", + "deps.ts", + "config.ts", + "config.example.ts" + ], + "exclude": [] + }, + "rules": { + "tags": [ + "recommended" + ], + "include": [ + "ban-untagged-todo" + ], + "exclude": [] + } + }, + "fmt": { + "include": [ + "src/", + "db/", + "mod.ts", + "deps.ts", + "config.ts", + "config.example.ts" + ], + "exclude": [], + "useTabs": true, + "lineWidth": 200, + "indentWidth": 2, + "singleQuote": true, + "proseWrap": "preserve" + } +} \ No newline at end of file diff --git a/deps.ts b/deps.ts new file mode 100644 index 0000000..4771d08 --- /dev/null +++ b/deps.ts @@ -0,0 +1,45 @@ +// All external dependencies are to be loaded here to make updating dependency versions much easier +export { enableCachePlugin, enableCacheSweepers } from 'https://deno.land/x/discordeno@17.0.1/plugins/cache/mod.ts'; +export type { BotWithCache } from 'https://deno.land/x/discordeno@17.0.1/plugins/cache/mod.ts'; + +export { + ActivityTypes, + ApplicationCommandFlags, + ApplicationCommandOptionTypes, + ApplicationCommandTypes, + BitwisePermissionFlags, + ButtonStyles, + ChannelTypes, + createBot, + getBotIdFromToken, + Intents, + InteractionResponseTypes, + MessageComponentTypes, + OverwriteTypes, + startBot, + TextStyles, +} from 'https://deno.land/x/discordeno@17.0.1/mod.ts'; +export type { + ActionRow, + ApplicationCommand, + ApplicationCommandOption, + Bot, + ButtonComponent, + CreateApplicationCommand, + CreateMessage, + DiscordEmbedField, + Embed, + EventHandlers, + Guild, + Interaction, + InteractionResponse, + MakeRequired, + Message, + PermissionStrings, + SelectMenuComponent, + SelectOption, +} from 'https://deno.land/x/discordeno@17.0.1/mod.ts'; + +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'; diff --git a/src/types/bbLibConfig.d.ts b/src/types/bbLibConfig.d.ts new file mode 100644 index 0000000..28e197d --- /dev/null +++ b/src/types/bbLibConfig.d.ts @@ -0,0 +1,7 @@ +import { DBConfig } from './config.d.ts'; + +export interface BBLibConfig { + name: string; + version: string; + db: DBConfig; +} diff --git a/src/types/config.d.ts b/src/types/config.d.ts new file mode 100644 index 0000000..a184e9d --- /dev/null +++ b/src/types/config.d.ts @@ -0,0 +1,91 @@ +export interface BotConfig { + // Common Fields + name: string; + version: string; + token: string; + localToken: string; + prefix: string; + owner: bigint; + logChannel: bigint; + reportChannel: bigint; + devServer: bigint; + + // Most bots use these + db?: DBConfig; + links?: LinksConfig; + + // Rarely used in bots + emojis?: EmojiConfig[]; + + // Public Bots Only + botLists?: BotListsConfig[]; + + // Artificer Specific, included for compatibility + postfix?: string; + limits?: ArtificerLimits; + api?: ArtificerApi; + logRolls?: boolean; +} + +// DB Config, every bot uses MySQL for compatibility with each other +export interface DBConfig { + host: string; + localhost: string; + port: number; + username: string; + password: string; + name: string; +} + +// Links Config, holds list of named strings that are used in many places +export interface LinksConfig { + sourceCode: string; + supportServer: string; + addToCalendar: string; + creatorIcon: string; +} + +// Emoji to dynamically add more emoji to a bot +export interface EmojiConfig { + name: string; + aliases: string[]; + id: string; + animated: boolean; + deleteSender: boolean; +} + +// Bot List Config for automatically posting statistics +export interface BotListsConfig { + name: string; + enabled: boolean; + apiUrl: string; + headers: BotListsEntity[]; + body: BotListBody; +} +export interface BotListsEntity { + header: string; + value: string; +} +export interface BotListBody { + server_count?: string; + guildCount?: string; + guilds?: string; +} + +// Types just for Artificer +export interface ArtificerLimits { + maxLoops: number; + maxWorkers: number; + workerTimeout: number; +} +export interface ArtificerApi { + enable: boolean; + publicDomain: string; + port: number; + supportURL: string; + rateLimitTime: number; + rateLimitCnt: number; + admin: bigint; + adminKey: string; + email: bigint; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..365b6d7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "allowJs": true, + "lib": ["es2022"], + "strict": true + } +} \ No newline at end of file