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