Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release: 0.1 #9

Merged
merged 54 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
0e7cb4b
feat: add commas to xp and levels
ToastedDev Jul 11, 2024
130ce37
Merge pull request #8 from ToastedDev/toasted/commas
GalvinPython Jul 11, 2024
63b03f3
feat(xp): add cooldown
ToastedDev Jul 11, 2024
61be2ab
fix(xp): actual cooldown
ToastedDev Jul 11, 2024
bd9ef26
Merge pull request #10 from ToastedDev/dev
GalvinPython Jul 11, 2024
1efe5a3
Merge pull request #11 from GalvinPython/main
GalvinPython Jul 11, 2024
4033879
Merge pull request #12 from GalvinPython/main
GalvinPython Jul 11, 2024
bebedc6
feat(db): refactor
ToastedDev Jul 11, 2024
2a41ac9
feat(db): migrate roles and updates
ToastedDev Jul 11, 2024
c9e73cc
Merge pull request #13 from ToastedDev/dev
GalvinPython Jul 11, 2024
b1384df
feat: added lint workflow
GalvinPython Jul 11, 2024
96011e8
fix(db): updated database and added new metric
GalvinPython Jul 11, 2024
a5dbd81
feat: add customizable cooldowns
ToastedDev Jul 12, 2024
a863b81
Merge pull request #14 from ToastedDev/dev
GalvinPython Jul 12, 2024
8b71762
fix(updates): api now routes to the new database
GalvinPython Jul 12, 2024
4475fc2
fix(updates): api now routes to the new database
GalvinPython Jul 12, 2024
b7acde9
chore(db): remove unused columns
ToastedDev Jul 13, 2024
92a8393
Merge pull request #15 from ToastedDev/dev
GalvinPython Jul 13, 2024
ac8636a
chore: fix errors
ToastedDev Jul 13, 2024
a9f500d
Merge pull request #16 from ToastedDev/dev
GalvinPython Jul 13, 2024
01c3363
fix(errors): now show error page on site
GalvinPython Jul 13, 2024
d7dc9fc
feat(bot): add rankcard
ToastedDev Jul 14, 2024
79cd22f
fix(commands): readd `.toLocaleString()` for text mode in `/xp`
ToastedDev Jul 14, 2024
bf4e796
fix(xp): use highest role color for progress bar
ToastedDev Jul 14, 2024
41124d7
chore: remove unused imports
ToastedDev Jul 14, 2024
c059fdd
fix(commands): readd `.toLocaleString()` for progress in /xp
ToastedDev Jul 14, 2024
ff76fbf
feat(commands): allow specifying a different user for /xp
ToastedDev Jul 14, 2024
ddb560b
feat(rankcard): use banner for background if any
ToastedDev Jul 14, 2024
80af83d
fix(rankcard): use actual data
ToastedDev Jul 14, 2024
f028869
feat(commands): add rank to text mode in `/xp`
ToastedDev Jul 14, 2024
03d759d
Merge pull request #17 from ToastedDev/dev
GalvinPython Jul 14, 2024
c7c5376
feat(updates): refactor
ToastedDev Jul 14, 2024
b6120b3
Merge pull request #18 from ToastedDev/dev
GalvinPython Jul 14, 2024
ce93ddd
feat: add ability to set xp and level for a user
ToastedDev Jul 15, 2024
471bf0d
Merge pull request #19 from ToastedDev/dev
GalvinPython Jul 15, 2024
17e5032
feat: add ready event
GalvinPython Jul 15, 2024
db9af14
fix(api): updateGuildInfo() now works
GalvinPython Jul 15, 2024
f5cc94f
temp delete bun.lockb
GalvinPython Jul 15, 2024
7d05a50
Merge pull request #22 from GalvinPython/main
GalvinPython Jul 15, 2024
17c340b
readd bun.lockb
GalvinPython Jul 16, 2024
b1b4efc
Merge branch 'dev' of https://github.com/GalvinPython/chatr into dev
GalvinPython Jul 16, 2024
e9396a3
feat: add ability to sync xp from polaris (wip)
ToastedDev Jul 16, 2024
ebbcda2
Merge branch 'GalvinPython:dev' into dev
ToastedDev Jul 16, 2024
4bf983d
fix: syncing from polaris actually works now
ToastedDev Jul 16, 2024
e8815e5
feat(bot): add /sync command
ToastedDev Jul 16, 2024
3b06833
feat(bot): add GuildDelete handler
GalvinPython Jul 16, 2024
def1e5a
fix(api): removed unneeded argument
GalvinPython Jul 16, 2024
13d8448
Create LICENSE
GalvinPython Jul 16, 2024
c5bfb80
feat(syncing): allow syncing from mee6
ToastedDev Jul 17, 2024
3fa059a
fix: ignore eslint error
ToastedDev Jul 17, 2024
16d857d
Merge branch 'GalvinPython:dev' into dev
ToastedDev Jul 19, 2024
d5ae4e1
feat: allow syncing from lurkr
ToastedDev Jul 19, 2024
854f939
Merge pull request #24 from ToastedDev/dev
GalvinPython Jul 19, 2024
b033549
bump: 0.1
GalvinPython Jul 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
DISCORD_TOKEN='TOKEN'
DISCORD_WEBHOOK_URL='YOUR_WEBHOOK_HERE'
DISCORD_TOKEN_DEV='DEV_TOKEN'

MYSQL_ADDRESS='YOUR_MYSQL_SERVER_ADDRESS'
MYSQL_PORT='YOUR_MYSQL_SERVER_PORT'
Expand Down
1 change: 1 addition & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ updates:
interval: "weekly"
assignees:
- "GalvinPython"
target-branch: "dev"
28 changes: 28 additions & 0 deletions .github/workflows/eslint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: ESLint Check

on:
push:
branches:
- '*'
pull_request:
types: [opened, reopened, synchronize]

jobs:
lint:
name: ESLint
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '20'

- name: Install dependencies
run: npm install

- name: Run ESLint
run: npm run lint
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Galvin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
54 changes: 47 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,59 @@
# Chatr
A Discord XP bot
A free and open-sourced Discord XP Bot.
![Bot](https://img.shields.io/badge/Invite%20Chatr-5865F2?style=for-the-badge&logo=discord&logoColor=white)
![Discord](https://img.shields.io/discord/1249813817706283019?style=for-the-badge&logo=discord&logoColor=white&label=Support%20Server&color=%235865F2)

> [!CAUTION]
> **Chatr** is currently in development and is open-sourced. The bot is functional in this state, however it shouldn't be used
Please report bugs in `bug-reports` on our server or open an issue on this repo!

# Features
- Earn XP from your messages!
- Customisable xp cooldown on messages
- Online leaderboard
- Rankcard
- Transfer your points from other bots!
- MEE6
- Polaris
- Lurkr
- Other bots soon

> [!WARNING]
> **Chatr** has entered Beta! (don't worry, we will deal with the headaches for you)

# Developer Instructions

This a project created using (Bun)[https://bun.sh]

To install dependencies:

```bash
bun install
```

To run:

Run the **API**
```bash
bun run index.ts
bun run dev:api
```
Run the **Bot**
```bash
bun run dev:bot
```

This project was created using `bun init` in bun v1.1.10. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.

# Changelog
## Beta 0.1
Thanks to @ToastedDev for his contributions to the bot. Here are some changes that were made
* General formatting fixes (#8)
* Refactored the database to be more performant (#13)
* Added a message cooldown (#14)
* Added a rankcard to /xp (#17)
* User management (#19)
* Added syncing (#24)

# Roadmap
* Rewritten site using NextJS
* Auto-updating cached user information
* Better privacy controls
* Live updates
* Track guilds and users xp

Want to add more features? Join our server (linked above) and add a post to `feature-requests`
15 changes: 15 additions & 0 deletions api/db/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import mysql from "mysql2";

// Create a MySQL connection pool
export const pool = mysql.createPool({
host: process.env.MYSQL_ADDRESS as string,
port: parseInt(process.env.MYSQL_PORT as string),
user: process.env.MYSQL_USER as string,
password: process.env.MYSQL_PASSWORD as string,
database: process.env.MYSQL_DATABASE as string,
});

export * from './init';
export * from './queries/guilds';
export * from './queries/users';
export * from './queries/updates';
64 changes: 64 additions & 0 deletions api/db/init.ts
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: investigate foreign keys

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { pool } from ".";

export async function initTables() {
const createGuildsTable = `
CREATE TABLE IF NOT EXISTS guilds (
id VARCHAR(255) NOT NULL PRIMARY KEY,
name VARCHAR(255),
icon VARCHAR(255),
members INT,
cooldown INT DEFAULT 30000,
updates_enabled BOOLEAN DEFAULT FALSE,
updates_channel_id VARCHAR(255) DEFAULT NULL,
is_in_guild BOOLEAN DEFAULT TRUE
)
`;
const createUsersTable = `
CREATE TABLE IF NOT EXISTS users (
id VARCHAR(255) NOT NULL,
guild_id VARCHAR(255) NOT NULL,
name VARCHAR(255),
nickname VARCHAR(255),
pfp VARCHAR(255),
xp INT DEFAULT 0,
level INT DEFAULT 0,
xp_needed_next_level INT,
progress_next_level DECIMAL(6, 2),
PRIMARY KEY (id, guild_id)
)
`;
// FOREIGN KEY (guild_id) REFERENCES guilds(id)
const createRolesTable = `
CREATE TABLE IF NOT EXISTS roles (
id VARCHAR(255) NOT NULL PRIMARY KEY,
guild_id VARCHAR(255) NOT NULL,
name VARCHAR(255),
level INT NOT NULL
)
`;
// FOREIGN KEY (guild_id) REFERENCES guilds(id)

pool.query(createGuildsTable, (err) => {
if (err) {
console.error("Error creating guilds table:", err);
} else {
console.log("Guilds table created");
}
});

pool.query(createUsersTable, (err) => {
if (err) {
console.error("Error creating users table:", err);
} else {
console.log("Users table created");
}
});

pool.query(createRolesTable, (err) => {
if (err) {
console.error("Error creating roles table:", err);
} else {
console.log("Roles table created");
}
});
}
124 changes: 124 additions & 0 deletions api/db/queries/guilds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import type { QueryError } from "mysql2";
import { pool } from "..";

export interface Guild {
id: string;
name: string;
icon: string;
members: number;
cooldown: number;
updates_enabled: 0 | 1;
updates_channel_id: string | null;
}


export async function getGuild(guildId: string): Promise<[QueryError, null] | [null, Guild | null]> {
return new Promise((resolve, reject) => {
pool.query("SELECT * FROM guilds WHERE id = ? AND is_in_guild = ?", [guildId, true], (err, results) => {
if (err) {
reject([err, null]);
} else {
resolve([null, (results as Guild[])[0]]);
}
});
});
}

export async function updateGuild(guild: Omit<Guild, "cooldown" | "updates_enabled" | "updates_channel_id">): Promise<[QueryError | null, null] | [null, Guild[]]> {
return new Promise((resolve, reject) => {
pool.query(
`
INSERT INTO guilds (id, name, icon, members, is_in_guild)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
icon = VALUES(icon),
members = VALUES(members),
is_in_guild = VALUES(is_in_guild)
`,
[
guild.id,
guild.name,
guild.icon,
guild.members,
true,
],
(err, results) => {
if (err) {
reject([err, null]);
} else {
resolve([null, results as Guild[]]);
}
},
);
});
}

export async function removeGuild(guildId: string): Promise<[QueryError, null] | [null, true]> {
return new Promise((resolve, reject) => {
pool.query("UPDATE guilds SET is_in_guild = ? WHERE id = ?", [false, guildId], (err) => {
if (err) {
reject([err, null]);
} else {
resolve([null, true]);
}
});
});
}

export async function setCooldown(guildId: string, cooldown: number): Promise<[QueryError, null] | [null, Guild]> {
return new Promise((resolve, reject) => {
pool.query("UPDATE guilds SET cooldown = ? WHERE id = ?", [cooldown, guildId], (err, results) => {
if (err) {
reject([err, null]);
} else {
resolve([null, (results as Guild[])[0]]);
}
});
})
}

interface BotInfo {
total_guilds: number;
total_members: number;
user_count?: number;
}

export async function getBotInfo(): Promise<[QueryError | null, BotInfo | null]> {
return new Promise((resolve, reject) => {
pool.query("SELECT COUNT(*) AS total_guilds, SUM(members) AS total_members FROM guilds", (err, results) => {
if (err) {
reject([err, null]);
} else {
const botInfo: BotInfo = {
total_guilds: (results as BotInfo[])[0].total_guilds,
total_members: (results as BotInfo[])[0].total_members ?? 0,
};
getUsersCount()
.then(([userCountError, userCount]) => {
if (userCountError) {
reject([userCountError, null]);
} else {
botInfo.user_count = userCount;
resolve([null, botInfo]);
}
})
.catch((error) => {
reject([error, null]);
});
}
});
});
}

export async function getUsersCount(): Promise<[QueryError | null, number]> {
return new Promise((resolve, reject) => {
pool.query("SELECT COUNT(*) AS count FROM users", (err, results) => {
if (err) {
reject([err, null]);
} else {
resolve([null, (results as { count: number }[])[0].count]);
}
});
});
}
Loading
Loading