mirror of
https://github.com/MrTalon63/lets-go-gambling.git
synced 2026-03-09 09:17:58 +01:00
Somewhat working POC
This commit is contained in:
parent
fda9e02ef4
commit
35b6c98539
29 changed files with 2752 additions and 0 deletions
88
.dockerignore
Normal file
88
.dockerignore
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
43
.github/workflows/docker-build.yaml
vendored
Normal file
43
.github/workflows/docker-build.yaml
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
name: Docker Image CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: "ghcr.io"
|
||||
IMAGE: "lets-go-gambling"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Docker registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/mrtalon63/${{ env.IMAGE }}:latest
|
||||
${{ env.REGISTRY }}/mrtalon63/${{ env.IMAGE }}:${{ github.RUN_ID }}
|
||||
19
Dockerfile
Normal file
19
Dockerfile
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
FROM node:lts-alpine AS base
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
FROM base AS prod-deps
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
|
||||
|
||||
FROM base AS build
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
||||
RUN pnpm run build
|
||||
|
||||
FROM base
|
||||
COPY --from=prod-deps /app/node_modules /app/node_modules
|
||||
COPY --from=build /app/build /app/build
|
||||
COPY package.json .
|
||||
CMD [ "pnpm", "start" ]
|
||||
12
eslint.config.mjs
Normal file
12
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import globals from "globals";
|
||||
import pluginJs from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{files: ["**/*.{js,mjs,cjs,ts}"]},
|
||||
{languageOptions: { globals: globals.node }},
|
||||
pluginJs.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
];
|
||||
31
package.json
Normal file
31
package.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "lets-go-gambling",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "nodemon --ignore 'data/*.json' -r dotenv/config src/index.ts",
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "MrTalon63 <marcin@mczop.eu>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"discord.js": "^14.16.3",
|
||||
"glob": "^11.0.0",
|
||||
"korwinjs": "^1.0.0",
|
||||
"pg": "^8.13.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.15.0",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/pg": "^8.11.10",
|
||||
"dotenv": "^16.4.5",
|
||||
"eslint": "^9.15.0",
|
||||
"nodemon": "^3.1.7",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.6.3",
|
||||
"typescript-eslint": "^8.15.0"
|
||||
}
|
||||
}
|
||||
1840
pnpm-lock.yaml
generated
Normal file
1840
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load diff
62
src/client.ts
Normal file
62
src/client.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import { Client, Collection, GatewayIntentBits, User, Options } from "discord.js";
|
||||
import { glob } from "glob";
|
||||
|
||||
import db from "./utils/db";
|
||||
|
||||
import { Command } from "./interfaces/commands";
|
||||
import { Event } from "./interfaces/events";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const pkg = require("../package.json");
|
||||
|
||||
class Bot extends Client {
|
||||
public commands: Collection<string, Command> = new Collection();
|
||||
public events: Collection<string, Event> = new Collection();
|
||||
public readonly version = pkg.version;
|
||||
public readonly prefix = process.env.PREFIX!;
|
||||
public readonly owner = process.env.OWNER;
|
||||
public log = console;
|
||||
public db = db;
|
||||
|
||||
public constructor() {
|
||||
super({
|
||||
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessagePolls, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildEmojisAndStickers, GatewayIntentBits.GuildMessageReactions],
|
||||
makeCache: Options.cacheWithLimits(),
|
||||
});
|
||||
}
|
||||
|
||||
public async start(): Promise<void> {
|
||||
this.log.debug("Logging in with token...");
|
||||
this.login(process.env.TOKEN);
|
||||
|
||||
this.log.debug("Loading commands and events...");
|
||||
const commandFiles: string[] = await glob(`${__dirname}/commands/**/*{.ts,.js}`);
|
||||
commandFiles.map(async (fileName: string) => {
|
||||
const file: Command = await import(`../${fileName}`);
|
||||
this.commands.set(file.name, file);
|
||||
if (file.aliases) file.aliases.map((alias) => this.commands.set(alias, file));
|
||||
});
|
||||
|
||||
const eventFiles: string[] = await glob(`${__dirname}/events/**/*{.ts,.js}`);
|
||||
eventFiles.map(async (fileName: string) => {
|
||||
const file: Event = await import(`../${fileName}`);
|
||||
this.events.set(file.name, file);
|
||||
this.on(file.event, file.run.bind(this, this));
|
||||
});
|
||||
|
||||
this.log.debug("Initialization complete!");
|
||||
}
|
||||
|
||||
public getUserFromMention(mention: string): User | undefined {
|
||||
if (!mention) return;
|
||||
if (mention.startsWith("<@") && mention.endsWith(">")) {
|
||||
mention = mention.slice(2, -1);
|
||||
if (mention.startsWith("!")) {
|
||||
mention = mention.slice(1);
|
||||
}
|
||||
}
|
||||
return this.users.cache.get(mention);
|
||||
}
|
||||
}
|
||||
|
||||
export default Bot;
|
||||
37
src/commands/economy/admin/add.ts
Normal file
37
src/commands/economy/admin/add.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../../interfaces/commands";
|
||||
|
||||
export const run: RunFunction = async (client, message, args) => {
|
||||
if (message.author.id !== client.owner) return;
|
||||
|
||||
const user = client.getUserFromMention(args[0]);
|
||||
const amount = parseInt(args[1]);
|
||||
if (!user || isNaN(amount)) {
|
||||
message.reply("Użycie `add <użytkownik | id> <kwota>`");
|
||||
return;
|
||||
}
|
||||
|
||||
const userData = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [user.id]);
|
||||
if (userData.rowCount === 0) {
|
||||
message.reply("Nie znaleziono użytkownika");
|
||||
return;
|
||||
}
|
||||
|
||||
await client.db("UPDATE gamblebot.users SET balance = balance + $1 WHERE udid = $2", [amount, user.id]);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("Dodano pieniądze")
|
||||
.setDescription(`Dodano ${amount}zł do konta użytkownika ${user.tag}`)
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "add";
|
||||
export const description = "Add money to user";
|
||||
37
src/commands/economy/admin/remove.ts
Normal file
37
src/commands/economy/admin/remove.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../../interfaces/commands";
|
||||
|
||||
export const run: RunFunction = async (client, message, args) => {
|
||||
if (message.author.id !== client.owner) return;
|
||||
|
||||
const user = client.getUserFromMention(args[0]);
|
||||
const amount = parseInt(args[1]);
|
||||
if (!user || isNaN(amount)) {
|
||||
message.reply("Użycie `remove <użytkownik | id> <kwota>`");
|
||||
return;
|
||||
}
|
||||
|
||||
const userData = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [user.id]);
|
||||
if (userData.rowCount === 0) {
|
||||
message.reply("Nie znaleziono użytkownika");
|
||||
return;
|
||||
}
|
||||
|
||||
await client.db("UPDATE gamblebot.users SET balance = balance - $1 WHERE udid = $2", [amount, user.id]);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("Zabrano pieniądze")
|
||||
.setDescription(`Zabrano ${amount}zł z konta użytkownika ${user.tag}`)
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "remove";
|
||||
export const description = "Removes money from user";
|
||||
56
src/commands/economy/balance.ts
Normal file
56
src/commands/economy/balance.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
import { User } from "../../types";
|
||||
|
||||
export const run: RunFunction = async (client, message, args) => {
|
||||
let userData: User;
|
||||
let title = "Twoje saldo";
|
||||
if (args[0] && client.getUserFromMention(args[0])) {
|
||||
const user = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [client.getUserFromMention(args[0])?.id]);
|
||||
if (user.rowCount === 0) {
|
||||
message.reply("Nie znaleziono użytkownika");
|
||||
return;
|
||||
}
|
||||
userData = user.rows[0];
|
||||
title = `Saldo użytkownika ${message.guild?.members.cache.get(user.rows[0].udid)?.user.tag}`;
|
||||
} else {
|
||||
const user = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [message.author.id]);
|
||||
if (user.rowCount === 0) {
|
||||
message.reply("Nie znaleziono użytkownika");
|
||||
return;
|
||||
}
|
||||
userData = user.rows[0];
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle(title)
|
||||
.addFields([
|
||||
{
|
||||
name: "Gotówka:",
|
||||
value: `${userData.balance}zł`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: `Stan konta:`,
|
||||
value: `${userData.bank_balance}zł`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: `Łączna wartość:`,
|
||||
value: `${parseInt(userData.balance) + parseInt(userData.bank_balance)}zł`,
|
||||
inline: true,
|
||||
},
|
||||
])
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "balance";
|
||||
export const aliases = ["bal"];
|
||||
export const description = "Returns the balance of the user";
|
||||
49
src/commands/economy/deposit.ts
Normal file
49
src/commands/economy/deposit.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
import { User } from "../../types";
|
||||
|
||||
export const run: RunFunction = async (client, message, args) => {
|
||||
if (!args[0]) {
|
||||
message.channel.send("Podaj kwotę którą chcesz wpłacić!");
|
||||
return;
|
||||
}
|
||||
const user = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [message.author.id]);
|
||||
if (user.rowCount === 0) {
|
||||
message.reply("Nie znaleziono użytkownika");
|
||||
return;
|
||||
}
|
||||
|
||||
const userData: User = user.rows[0];
|
||||
const depAll = args[0] === "all";
|
||||
|
||||
if (args[0] === "all") {
|
||||
await client.db("UPDATE gamblebot.users SET bank_balance = balance + bank_balance, balance = 0 WHERE udid = $1", [message.author.id]);
|
||||
} else {
|
||||
const amount = parseInt(args[0]);
|
||||
if (isNaN(amount)) {
|
||||
message.reply("Niepoprawne argumenty");
|
||||
return;
|
||||
}
|
||||
if (parseInt(userData.balance) < amount) {
|
||||
message.reply("Nie masz tyle gotówki!");
|
||||
return;
|
||||
}
|
||||
await client.db("UPDATE gamblebot.users SET balance = balance - $1, bank_balance = bank_balance + $1 WHERE udid = $2", [amount, message.author.id]);
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("Wpłacono pieniądze")
|
||||
.setDescription(`Wpłacono ${depAll ? `${userData.balance}zł` : `${args[0]}zł`} do banku`)
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "deposit";
|
||||
export const aliases = ["dep", "wplac"];
|
||||
export const description = "Deposit money to bank";
|
||||
36
src/commands/economy/leaderboard.ts
Normal file
36
src/commands/economy/leaderboard.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
|
||||
export const run: RunFunction = async (client, message) => {
|
||||
const balances = await client.db("SELECT udid, (COALESCE(balance,0) + COALESCE(bank_balance,0)) AS sums FROM gamblebot.users ORDER BY sums DESC", []);
|
||||
if (balances.rowCount === 0) {
|
||||
message.reply("Nie znaleziono użytkowników");
|
||||
return;
|
||||
}
|
||||
|
||||
const top10 = balances.rows.slice(0, 10) as { udid: string; sums: string }[];
|
||||
await message.guild?.members.fetch();
|
||||
|
||||
const filtered = top10.filter((user) => parseInt(user.sums) > 0);
|
||||
const fields = filtered.map((user, index) => ({
|
||||
name: `${index + 1}. ${client.getUserFromMention(user.udid)?.tag || "Nieznany użytkownik"}`,
|
||||
value: `Całkowite saldo: ${user.sums}zł`,
|
||||
inline: false,
|
||||
}));
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle(`Top 10 użytkowników serwera ${message.guild?.name}`)
|
||||
.setFields(fields)
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "leaderboard";
|
||||
export const aliases = ["top"];
|
||||
export const description = "Returns the balance of the user";
|
||||
45
src/commands/economy/pay.ts
Normal file
45
src/commands/economy/pay.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
import { User } from "../../types";
|
||||
|
||||
export const run: RunFunction = async (client, message, args) => {
|
||||
const payer = message.author;
|
||||
const payee = client.getUserFromMention(args[0]);
|
||||
const amount = parseInt(args[1]);
|
||||
if (!payee || isNaN(amount)) {
|
||||
message.reply("Użycie: `pay <użytkownik | id> <kwota>`");
|
||||
return;
|
||||
}
|
||||
|
||||
const payerQuery = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [payer.id]);
|
||||
if (payerQuery.rowCount === 0) {
|
||||
message.reply("Nie znaleziono użytkownika");
|
||||
return;
|
||||
}
|
||||
const payerData = payerQuery.rows[0] as User;
|
||||
|
||||
if (parseInt(payerData.bank_balance) < amount) {
|
||||
message.reply("Nie masz tyle pieniędzy na koncie!");
|
||||
return;
|
||||
}
|
||||
|
||||
await client.db("UPDATE gamblebot.users SET bank_balance = bank_balance - $1 WHERE udid = $2", [amount, payer.id]);
|
||||
await client.db("UPDATE gamblebot.users SET bank_balance = bank_balance + $1 WHERE udid = $2", [amount, payee.id]);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("Dodano pieniądze")
|
||||
.setDescription(`Przelano ${amount}zł do ${payee.tag}`)
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "pay";
|
||||
export const aliases = ["give", "daj", "przelej"];
|
||||
export const description = "Pay money to user";
|
||||
49
src/commands/economy/withdraw.ts
Normal file
49
src/commands/economy/withdraw.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
import { User } from "../../types";
|
||||
|
||||
export const run: RunFunction = async (client, message, args) => {
|
||||
if (!args[0]) {
|
||||
message.channel.send("Podaj kwotę którą chcesz wypłacić!");
|
||||
return;
|
||||
}
|
||||
const user = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [message.author.id]);
|
||||
if (user.rowCount === 0) {
|
||||
message.reply("Nie znaleziono użytkownika");
|
||||
return;
|
||||
}
|
||||
|
||||
const userData: User = user.rows[0];
|
||||
const depAll = args[0] === "all";
|
||||
|
||||
if (args[0] === "all") {
|
||||
await client.db("UPDATE gamblebot.users SET balance = balance + bank_balance, bank_balance = 0 WHERE udid = $1", [message.author.id]);
|
||||
} else {
|
||||
const amount = parseInt(args[0]);
|
||||
if (isNaN(amount)) {
|
||||
message.reply("Niepoprawne argumenty");
|
||||
return;
|
||||
}
|
||||
if (parseInt(userData.bank_balance) < amount) {
|
||||
message.reply("Nie masz tyle na koncie!");
|
||||
return;
|
||||
}
|
||||
await client.db("UPDATE gamblebot.users SET balance = balance + $1, bank_balance = bank_balance - $1 WHERE udid = $2", [amount, message.author.id]);
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("Wypłacono pieniądze")
|
||||
.setDescription(`Wypłacono ${depAll ? `${userData.balance}zł` : `${args[0]}zł`} z banku`)
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "withdraw";
|
||||
export const aliases = ["with", "wth", "wyplac"];
|
||||
export const description = "Withdraw money from bank";
|
||||
39
src/commands/economy/work.ts
Normal file
39
src/commands/economy/work.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
import { User } from "../../types";
|
||||
|
||||
const workTexts = [`Postanawiasz sprzedawać truskawki ukradzione sąsiadowi z działki. Zarabiasz {amount}zł.`, `Sprzedajesz zardzewiałe monety jako „antyki” na pchlim targu. Twoje konto powiększa się o {amount}zł.`, `Przemycasz cukierki do szkoły i sprzedajesz je pod stołem wpadło {amount}zł z zysku!`, `Tworzysz fałszywą stronę z prognozami giełdowymi, żeby sprzedawać 'pewne' wskazówki inwestycyjne. Zarobiłeś {amount}zł, zanim zbanowali ci konto.`, `Wyprodukowałeś własne napoje energetyczne (skład: sok i cukier) i sprzedajesz jako „100% naturalny doping”. Zarabiasz {amount}zł.`, `Pomagasz znajomym załatwić 'ekskluzywne' skiny do gier w zamian za małą prowizję. Po dwóch dniach jesteś bogatszy o {amount}zł.`, `Stworzyłeś biznes mycia okien sąsiadom za 5 zł od okna. Zarabiasz {amount}zł!`, `Otwierasz stoisko z 'oryginalnymi' podróbkami perfum pod szkołą. Sprzedajesz kilkanaście flakonów i wychodzisz na plus {amount}zł.`, `Zarabiasz na 'reklamach' na serwerze - każdy, kto chce wspomnieć o swojej działalności, płaci drobną opłatę. Twój bilans to {amount}zł`];
|
||||
|
||||
export const run: RunFunction = async (client, message) => {
|
||||
const userData = await client.db("SELECT * FROM gamblebot.users WHERE udid = $1", [message.author.id]);
|
||||
if (userData.rowCount === 0) {
|
||||
message.reply("Nie znaleziono użytkownika");
|
||||
return;
|
||||
}
|
||||
|
||||
const user: User = userData.rows[0];
|
||||
if (parseInt(user.last_work) + 1000 * 60 * 60 > Date.now()) {
|
||||
message.reply(`Musisz odczekać ${new Date(parseInt(user.last_work) + 1000 * 60 * 60 - Date.now()).getMinutes()}m ${new Date(parseInt(user.last_work) + 1000 * 60 * 60 - Date.now()).getSeconds()}s zanim zaczniesz znowu pracować`);
|
||||
return;
|
||||
}
|
||||
|
||||
const revenue = Math.floor(Math.random() * 1000);
|
||||
|
||||
await client.db("UPDATE gamblebot.users SET balance = balance + $1, last_work = $2 WHERE udid = $3", [revenue, Date.now(), message.author.id]);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("Praca")
|
||||
.setDescription(workTexts[Math.floor(Math.random() * workTexts.length)].replace("{amount}", revenue.toString()))
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "work";
|
||||
export const aliases = ["praca"];
|
||||
export const description = "Work for money";
|
||||
46
src/commands/info.ts
Normal file
46
src/commands/info.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../interfaces/commands";
|
||||
|
||||
export const run: RunFunction = async (client, message) => {
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("Pong!")
|
||||
.addFields([
|
||||
{
|
||||
name: "Discord API ping:",
|
||||
value: `${Math.round(message.client.ws.ping)} ms`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: `Bot ping:`,
|
||||
value: `${Math.round(Date.now() - message.createdTimestamp)} ms`,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: `Aktualna wersja:`,
|
||||
value: client.version,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: `Prefix:`,
|
||||
value: client.prefix,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: `Ilość użytkowników:`,
|
||||
value: message.guild?.memberCount.toString(),
|
||||
inline: true,
|
||||
},
|
||||
])
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "info";
|
||||
export const aliases = ["p", "ping"];
|
||||
export const description = "Ping!";
|
||||
32
src/commands/other/cat.ts
Normal file
32
src/commands/other/cat.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
|
||||
export const run: RunFunction = async (client, message) => {
|
||||
const req = await fetch("https://api.thecatapi.com/v1/images/search", {
|
||||
headers: {
|
||||
"x-api-key": process.env.CAT_API_KEY || "",
|
||||
"content-type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!req.ok) {
|
||||
message.reply("Wystąpił błąd podczas pobierania obrazka kota");
|
||||
return;
|
||||
}
|
||||
const data = await req.json();
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("Kot")
|
||||
.setImage(data[0].url)
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "cat";
|
||||
export const aliases = ["kot"];
|
||||
export const description = "Generate random cat image";
|
||||
32
src/commands/other/dog.ts
Normal file
32
src/commands/other/dog.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
|
||||
export const run: RunFunction = async (client, message) => {
|
||||
const req = await fetch("https://api.thedogapi.com/v1/images/search", {
|
||||
headers: {
|
||||
"x-api-key": process.env.DOG_API_KEY || "",
|
||||
"content-type": "application/json",
|
||||
},
|
||||
});
|
||||
if (!req.ok) {
|
||||
message.reply("Wystąpił błąd podczas pobierania obrazka psa");
|
||||
return;
|
||||
}
|
||||
const data = await req.json();
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("Pies")
|
||||
.setImage(data[0].url)
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "dog";
|
||||
export const aliases = ["pies"];
|
||||
export const description = "Generate random dog image";
|
||||
10
src/commands/other/korwin.ts
Normal file
10
src/commands/other/korwin.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import korwin from "korwinjs";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
|
||||
export const run: RunFunction = async (client, message) => {
|
||||
message.reply(await korwin());
|
||||
};
|
||||
|
||||
export const name = "korwin";
|
||||
export const description = "Korwin wypowiedź";
|
||||
42
src/commands/other/llm.ts
Normal file
42
src/commands/other/llm.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
|
||||
export const run: RunFunction = async (client, message, args) => {
|
||||
const prompt = args.join(" ");
|
||||
if (!prompt) {
|
||||
message.channel.send("Podaj tekst do przetworzenia.");
|
||||
return;
|
||||
}
|
||||
|
||||
let req;
|
||||
try {
|
||||
req = await fetch(`https://text.pollinations.ai/${prompt}`);
|
||||
} catch {
|
||||
message.reply("Wystąpił błąd podczas generowania odpowiedzi");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!req.ok) {
|
||||
message.reply("Wystąpił błąd podczas generowania odpowiedzi");
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await req.text();
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("LLM")
|
||||
.setDescription(res)
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
|
||||
message.channel.send({ embeds: [embed] });
|
||||
};
|
||||
|
||||
export const name = "llm";
|
||||
export const aliases = ["largelanguagemodel"];
|
||||
export const description = "Send request to LLM";
|
||||
43
src/commands/other/tti.ts
Normal file
43
src/commands/other/tti.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { EmbedBuilder, AttachmentBuilder } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/commands";
|
||||
|
||||
export const run: RunFunction = async (client, message, args) => {
|
||||
const prompt = args.join(" ");
|
||||
if (!prompt) {
|
||||
message.channel.send("Podaj tekst do przetworzenia.");
|
||||
return;
|
||||
}
|
||||
|
||||
let req;
|
||||
try {
|
||||
req = await fetch(`https://image.pollinations.ai/prompt/${prompt}`);
|
||||
} catch {
|
||||
message.reply("Wystąpił błąd podczas generowania obrazka");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!req.ok) {
|
||||
message.reply("Wystąpił błąd podczas generowania obrazka");
|
||||
return;
|
||||
}
|
||||
|
||||
const image = Buffer.from(await req.arrayBuffer());
|
||||
const atta = new AttachmentBuilder(image, { name: "tti.png" });
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Blue")
|
||||
.setTitle("Text to image")
|
||||
.setImage(`attachment://tti.png`)
|
||||
.setTimestamp(new Date())
|
||||
.setFooter({
|
||||
text: `Wygenerowane dla ${message.author.tag}`,
|
||||
iconURL: message.author.displayAvatarURL(),
|
||||
});
|
||||
|
||||
message.channel.send({ embeds: [embed], files: [atta] });
|
||||
};
|
||||
|
||||
export const name = "tti";
|
||||
export const aliases = ["texttoimage", "text-to-image"];
|
||||
export const description = "Text to images";
|
||||
10
src/events/clientEvents/readyEvent.ts
Normal file
10
src/events/clientEvents/readyEvent.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Events } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/events";
|
||||
|
||||
export const run: RunFunction = async (client) => {
|
||||
client.log.info(`${client.user?.tag} is ready!`);
|
||||
};
|
||||
|
||||
export const name = "Client ready";
|
||||
export const event = Events.ClientReady;
|
||||
17
src/events/guildEvents/commandHandler.ts
Normal file
17
src/events/guildEvents/commandHandler.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { OmitPartialGroupDMChannel, Message, Events } from "discord.js";
|
||||
|
||||
import { RunFunction } from "../../interfaces/events";
|
||||
|
||||
export const run: RunFunction = async (client, message: OmitPartialGroupDMChannel<Message>) => {
|
||||
if (message.author.bot) return;
|
||||
if (!message.content.startsWith(client.prefix)) return;
|
||||
if (!message.guild) return;
|
||||
const args = message.content.slice(client.prefix.length).trim().split(/ +/g);
|
||||
const command = args.shift()?.toLowerCase() || "";
|
||||
const cmd = client.commands.get(command);
|
||||
if (!cmd) return;
|
||||
cmd.run(client, message, args);
|
||||
};
|
||||
|
||||
export const name = "Command Handler";
|
||||
export const event = Events.MessageCreate;
|
||||
8
src/index.ts
Normal file
8
src/index.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import Bot from "./client";
|
||||
|
||||
console.info("Starting bot...");
|
||||
const client = new Bot();
|
||||
client.start().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
14
src/interfaces/commands.ts
Normal file
14
src/interfaces/commands.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { Message, OmitPartialGroupDMChannel } from "discord.js";
|
||||
|
||||
import Bot from "../client";
|
||||
|
||||
export interface Command {
|
||||
name: string;
|
||||
aliases: string[];
|
||||
description: string;
|
||||
run: RunFunction;
|
||||
}
|
||||
|
||||
export interface RunFunction {
|
||||
(client: Bot, message: OmitPartialGroupDMChannel<Message>, args: string[]): Promise<void>;
|
||||
}
|
||||
12
src/interfaces/events.ts
Normal file
12
src/interfaces/events.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import Bot from "../client";
|
||||
|
||||
export interface Event {
|
||||
name: string;
|
||||
event: string;
|
||||
run: RunFunction;
|
||||
}
|
||||
|
||||
export interface RunFunction {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(client: Bot, ...args: any[]): Promise<void>;
|
||||
}
|
||||
15
src/types.ts
Normal file
15
src/types.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
type User = {
|
||||
udid: string;
|
||||
balance: string;
|
||||
bank_balance: string;
|
||||
last_work: string;
|
||||
last_crime: string;
|
||||
last_prostitution: string;
|
||||
};
|
||||
|
||||
type items = {
|
||||
name: string;
|
||||
quantity: number;
|
||||
};
|
||||
|
||||
export { User, items };
|
||||
16
src/utils/db.ts
Normal file
16
src/utils/db.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { Pool } from "pg";
|
||||
|
||||
const pool = new Pool({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
async function query(text: string, params: any[]) {
|
||||
const start = Date.now();
|
||||
const res = await pool.query(text, params);
|
||||
const duration = Date.now() - start;
|
||||
console.log("executed query", { text, duration, rows: res.rowCount });
|
||||
return res;
|
||||
}
|
||||
|
||||
export default query;
|
||||
12
tsconfig.json
Normal file
12
tsconfig.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "commonjs",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue