code
commit
404412da9e
@ -0,0 +1,9 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
@ -0,0 +1,45 @@
|
|||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
commonjs: true,
|
||||||
|
es6: true,
|
||||||
|
node: true
|
||||||
|
},
|
||||||
|
extends: ['eslint:recommended', 'prettier/@typescript-eslint', 'plugin:prettier/recommended'],
|
||||||
|
globals: {
|
||||||
|
NodeJS: true,
|
||||||
|
BigInt: true
|
||||||
|
},
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 6,
|
||||||
|
sourceType: 'module'
|
||||||
|
},
|
||||||
|
plugins: ['@typescript-eslint'],
|
||||||
|
rules: {
|
||||||
|
'prettier/prettier': 'warn',
|
||||||
|
'no-cond-assign': [2, 'except-parens'],
|
||||||
|
'no-unused-vars': 0,
|
||||||
|
'@typescript-eslint/no-unused-vars': 1,
|
||||||
|
'no-empty': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowEmptyCatch: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'prefer-const': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
destructuring: 'all'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'spaced-comment': 'warn'
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['slash-up.config.js'],
|
||||||
|
env: {
|
||||||
|
node: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -0,0 +1,15 @@
|
|||||||
|
# Packages
|
||||||
|
node_modules/
|
||||||
|
yarn.lock
|
||||||
|
package_lock.json
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
.tmp/
|
||||||
|
.vscode/**/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.env
|
||||||
|
dist/
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"printWidth": 120
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"deepscan.vscode-deepscan",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"editorconfig.editorconfig"
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
# slash-create-template in TypeScript
|
||||||
|
This templates helps you in creating slash commands in TypeScript from a webserver.
|
||||||
|
|
||||||
|
| [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Snazzah/slash-create-template/tree/typescript) | [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/GL2qbv?referralCode=snazzah) |
|
||||||
|
|:-:|:-:|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
```sh
|
||||||
|
npx slash-up init typescript slash-commands
|
||||||
|
cd slash-commands
|
||||||
|
# edit variables in the ".env" file!
|
||||||
|
# Create and edit commands in the `commands` folder
|
||||||
|
npx slash-up sync
|
||||||
|
yarn build
|
||||||
|
yarn start
|
||||||
|
```
|
||||||
|
|
||||||
|
### From Railway/Heroku
|
||||||
|
For Railway and Heroku users, you must sync commands locally to push any command changes to Discord. You can do this by using `slash-up sync` within your Git repository.
|
||||||
|
|
||||||
|
Heroku users will have their commands synced when they initially deploy to Heroku.
|
||||||
|
|
||||||
|
### Using PM2
|
||||||
|
```sh
|
||||||
|
npm i -g pm2
|
||||||
|
# Follow the installation process above
|
||||||
|
pm2 start pm2.json
|
||||||
|
pm2 dump # recommended
|
||||||
|
```
|
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "/create (TypeScript)",
|
||||||
|
"description": "Deploy a slash-create server for Discord interactions.",
|
||||||
|
"repository": "https://github.com/Snazzah/slash-create-template/tree/typescript",
|
||||||
|
"logo": "https://slash-create.js.org/static/logo-nomargin.png",
|
||||||
|
"scripts": {
|
||||||
|
"postdeploy": "npx slash-up sync"
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"DISCORD_APP_ID": {
|
||||||
|
"description": "The application ID of the Discord app"
|
||||||
|
},
|
||||||
|
"DISCORD_PUBLIC_KEY": {
|
||||||
|
"description": "The public key of the Discord app"
|
||||||
|
},
|
||||||
|
"DISCORD_BOT_TOKEN": {
|
||||||
|
"description": "The bot token of the Discord app"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"keywords": ["node", "fastify", "discord", "interactions"]
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
> slash-create-template@1.0.0 start
|
||||||
|
> cd dist && node index.js
|
||||||
|
|
||||||
|
03/12 12:47:34 info Registered command hello
|
||||||
|
ready!
|
||||||
|
03/12 12:47:35 info Commands synced!
|
||||||
|
03/12 12:47:47 info ZeroMomentum#6560 (435206857276260353) ran command hello
|
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "slash-create-template",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A template for slash-create",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"sync": "slash-up sync",
|
||||||
|
"sync:dev": "slash-up sync -e development",
|
||||||
|
"start": "cd dist && node index.js",
|
||||||
|
"build": "npx tsc",
|
||||||
|
"lint": "npx eslint --ext .ts ./src",
|
||||||
|
"lint:fix": "npx eslint --ext .ts ./src --fix"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/client": "^4.11.0",
|
||||||
|
"cat-loggr": "^1.1.0",
|
||||||
|
"discord.js": "^14.7.1",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"fastify": "^3.9.2",
|
||||||
|
"node-fetch": "^3.3.1",
|
||||||
|
"robert": "^2.6.5",
|
||||||
|
"slash-create": "^5.2.0",
|
||||||
|
"stream": "^0.0.2",
|
||||||
|
"undici": "^5.20.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/express": "^4.17.11",
|
||||||
|
"@types/node": "^14.14.37",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.19.0",
|
||||||
|
"@typescript-eslint/parser": "^4.19.0",
|
||||||
|
"eslint": "^7.15.0",
|
||||||
|
"eslint-config-prettier": "^7.0.0",
|
||||||
|
"eslint-plugin-prettier": "^3.3.0",
|
||||||
|
"prettier": "^2.2.1",
|
||||||
|
"prisma": "^4.11.0",
|
||||||
|
"slash-up": "^1.0.11",
|
||||||
|
"ts-node": "^9.1.1",
|
||||||
|
"typescript": "^4.2.3"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"apps": [
|
||||||
|
{
|
||||||
|
"name": "slash-commands",
|
||||||
|
"script": "node",
|
||||||
|
"args": "dist/index.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,30 @@
|
|||||||
|
// This is your Prisma schema file,
|
||||||
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||||
|
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "postgresql"
|
||||||
|
url = env("DATABASE_URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
model GuildConfig {
|
||||||
|
id String @id
|
||||||
|
welcome_message String @default("Hello %USER%!")
|
||||||
|
welcome_channel String?
|
||||||
|
daily_message_text String @default("daily message")
|
||||||
|
daily_message_channel String?
|
||||||
|
daily_message_time DateTime @default(now()) @db.Timetz
|
||||||
|
users User[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id String
|
||||||
|
guild GuildConfig @relation(fields: [guild_id], references: [id])
|
||||||
|
guild_id String
|
||||||
|
messages Int @default(0)
|
||||||
|
|
||||||
|
@@id([id, guild_id])
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
// This is the slash-up config file.
|
||||||
|
// Make sure to fill in "token" and "applicationId" before using.
|
||||||
|
// You can also use environment variables from the ".env" file if any.
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// The Token of the Discord bot
|
||||||
|
token: process.env.TOKEN,
|
||||||
|
// The Application ID of the Discord bot
|
||||||
|
applicationId: process.env.APPLICATION_ID,
|
||||||
|
// This is where the path to command files are, .ts files are supported!
|
||||||
|
commandPath: './src/commands',
|
||||||
|
// You can use different environments with --env (-e)
|
||||||
|
env: {
|
||||||
|
development: {
|
||||||
|
// The "globalToGuild" option makes global commands sync to the specified guild instead.
|
||||||
|
globalToGuild: process.env.DEVELOPMENT_GUILD_ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,27 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
import { SlashCommand, SlashCreator, CommandContext, MessageEmbed } from 'slash-create'
|
||||||
|
|
||||||
|
export default class LeaderboardCommand extends SlashCommand {
|
||||||
|
constructor(creator: SlashCreator) {
|
||||||
|
super(creator, {
|
||||||
|
name: 'leaderboard',
|
||||||
|
description: 'see top 10 messages'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
const users = await prisma.user.findMany({
|
||||||
|
where: { guild_id: ctx.guildID },
|
||||||
|
take: 10,
|
||||||
|
orderBy: { messages: 'desc' }
|
||||||
|
})
|
||||||
|
let st = ''
|
||||||
|
for (const u of users) {
|
||||||
|
let uu = await this.client.users.fetch(u.id)
|
||||||
|
st += `${uu.username}#${uu.discriminator} - ${u.messages} message(s)\n`
|
||||||
|
}
|
||||||
|
return st
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
import { CommandContext, CommandOptionType, SlashCommand, SlashCreator } from 'slash-create'
|
||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
|
||||||
|
export default class MessagesCommand extends SlashCommand {
|
||||||
|
constructor(creator: SlashCreator) {
|
||||||
|
super(creator, {
|
||||||
|
name: 'messages',
|
||||||
|
description: 'show message count, either for yourself, or someone else',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'user',
|
||||||
|
description: 'person to show messages for (blank shows your own)',
|
||||||
|
required: false,
|
||||||
|
type: CommandOptionType.USER
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
if (ctx.options.user == null) {
|
||||||
|
const u = await prisma.user.findFirst({ where: { id: ctx.member?.id, guild: { id: ctx.guildID } } })
|
||||||
|
if (!u) return `you have no messages!`
|
||||||
|
return `you have ${u.messages} message(s)`
|
||||||
|
} else {
|
||||||
|
const uid = ctx.options.user
|
||||||
|
const u = await prisma.user.findFirst({ where: { id: uid, guild: { id: ctx.guildID } } })
|
||||||
|
if (!u) return `this user has no messages!`
|
||||||
|
const uu = await this.client.users.fetch(u.id)
|
||||||
|
return `${uu.username}#${uu.discriminator} has ${u.messages} message(s)`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import { SlashCommand, SlashCreator, CommandContext } from 'slash-create';
|
||||||
|
|
||||||
|
export default class PingCommand extends SlashCommand {
|
||||||
|
constructor(creator: SlashCreator) {
|
||||||
|
super(creator, {
|
||||||
|
name: 'ping',
|
||||||
|
description: 'pongs'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
async run(_ctx: CommandContext) {
|
||||||
|
return `pong from ${this.client.user.tag}!`;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/* eslint-disable prettier/prettier */
|
||||||
|
import { SlashCommand, SlashCreator, CommandOptionType, CommandContext } from 'slash-create';
|
||||||
|
|
||||||
|
export default class StockCommand extends SlashCommand {
|
||||||
|
constructor(creator: SlashCreator) {
|
||||||
|
super(creator, {
|
||||||
|
name: 'stock',
|
||||||
|
description: 'checks stock price',
|
||||||
|
options: [{ type: CommandOptionType.STRING, name: 'ticker', description: 'the ticker to check', required: true }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
const tkr = ctx.options.ticker
|
||||||
|
const req = await fetch(`https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${tkr}&apikey=8O1INVBY11E0GRGC`)
|
||||||
|
const info = await req.json()
|
||||||
|
if (Object.keys(info['Global Quote']).length == 0) {
|
||||||
|
return `stock not found!`
|
||||||
|
}
|
||||||
|
const i = info['Global Quote']
|
||||||
|
return `stock info for ${i['01. symbol']} - OPEN: ${i['02. open']} - PRICE: ${i['05. price']} - % CHANGE: ${i['10. change percent']}`
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
import dotenv from 'dotenv'
|
||||||
|
import { SlashCreator, GatewayServer } from 'slash-create'
|
||||||
|
import path from 'path'
|
||||||
|
import CatLoggr from 'cat-loggr/ts'
|
||||||
|
import { Client, GatewayDispatchEvents, Events, Guild, Message } from 'discord.js'
|
||||||
|
import { PrismaClient } from '@prisma/client'
|
||||||
|
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
const client = new Client({ intents: [131071] })
|
||||||
|
|
||||||
|
let dotenvPath = path.join(process.cwd(), '.env')
|
||||||
|
if (path.parse(process.cwd()).name === 'dist') dotenvPath = path.join(process.cwd(), '..', '.env')
|
||||||
|
|
||||||
|
dotenv.config({ path: dotenvPath })
|
||||||
|
|
||||||
|
const logger = new CatLoggr().setLevel(process.env.COMMANDS_DEBUG === 'true' ? 'debug' : 'info')
|
||||||
|
const creator = new SlashCreator({
|
||||||
|
client,
|
||||||
|
applicationID: process.env.APPLICATION_ID ?? 'AASDF',
|
||||||
|
publicKey: process.env.PUBLIC_KEY,
|
||||||
|
token: process.env.TOKEN
|
||||||
|
})
|
||||||
|
|
||||||
|
creator.on('debug', (message) => logger.log(message))
|
||||||
|
creator.on('warn', (message) => logger.warn(message))
|
||||||
|
creator.on('error', (error) => logger.error(error))
|
||||||
|
creator.on('synced', () => logger.info('Commands synced!'))
|
||||||
|
creator.on('commandRun', (command, _, ctx) =>
|
||||||
|
logger.info(`${ctx.user.username}#${ctx.user.discriminator} (${ctx.user.id}) ran command ${command.commandName}`)
|
||||||
|
)
|
||||||
|
creator.on('commandRegister', (command) => logger.info(`Registered command ${command.commandName}`))
|
||||||
|
creator.on('commandError', (command, error) => logger.error(`Command ${command.commandName}:`, error))
|
||||||
|
|
||||||
|
creator
|
||||||
|
.withServer(new GatewayServer((handler) => client.ws.on(GatewayDispatchEvents.InteractionCreate, handler)))
|
||||||
|
.registerCommandsIn(path.join(__dirname, 'commands'))
|
||||||
|
.syncCommands()
|
||||||
|
|
||||||
|
client.once('ready', async () => console.log('ready!'))
|
||||||
|
|
||||||
|
client.on(Events.GuildCreate, async (g: Guild) => {
|
||||||
|
await prisma.guildConfig.create({
|
||||||
|
data: {
|
||||||
|
id: g.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
client.on(Events.MessageCreate, async (msg: Message) => {
|
||||||
|
if (!msg.guild || msg.author == client.user) return
|
||||||
|
const u = await prisma.user.findFirst({
|
||||||
|
where: {
|
||||||
|
guild_id: msg.guild.id,
|
||||||
|
id: msg.author.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!u) {
|
||||||
|
await prisma.user.create({
|
||||||
|
data: {
|
||||||
|
guild_id: msg.guild.id,
|
||||||
|
id: msg.author.id,
|
||||||
|
messages: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const newMessagesCount = (u.messages ?? 0) + 1
|
||||||
|
await prisma.user.update({
|
||||||
|
where: {
|
||||||
|
id_guild_id: { id: msg.author.id, guild_id: msg.guild.id }
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
messages: newMessagesCount
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
client.login(process.env.TOKEN)
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"module": "commonjs",
|
||||||
|
"outDir": "dist",
|
||||||
|
"strict": false,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"typeRoots": ["./node_modules/@types", "types"]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist",
|
||||||
|
"testing",
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue