Skip to content

Commit

Permalink
feat: global user & server message leaderboards (#245)
Browse files Browse the repository at this point in the history
  • Loading branch information
dev-737 authored Feb 21, 2025
1 parent d82672d commit 9ff2e7e
Show file tree
Hide file tree
Showing 13 changed files with 432 additions and 85 deletions.
12 changes: 12 additions & 0 deletions locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,18 @@ errors:
banned: |
{emoji} You have been banned from using InterChat for violating our [guidelines](https://interchat.tech/guidelines).
If you think an appeal is applicable create a ticket in the [support server]( {support_invite} ).
config:
setInvite:
success: |
### {emoji} Invite Link Set
- Your server's invite will be used when people use `/joinserver`.
- It will be displayed in `/leaderboard server`.
removed: '{emoji} Invite removed successfully!'
invalid: '{emoji} Invalid invite. Please make sure you have entered a valid invite link. Eg. `https://discord.gg/discord`'
notFromServer: '{emoji} This invite is not from this server.'


global:
webhookNoLongerExists: '{emoji} The webhook for this channel no longer exists. To continue using InterChat, please re-create the webhook by using `/connection unpause`.'
noReason: No reason provided.
Expand Down
13 changes: 7 additions & 6 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -186,19 +186,20 @@ model UserData {
}

model Announcement {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
content String
thumbnailUrl String?
imageUrl String?
createdAt DateTime @default(now())
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
content String
thumbnailUrl String?
imageUrl String?
createdAt DateTime @default(now())
}

model ServerData {
id String @id @map("_id") @db.String
premiumStatus Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
inviteCode String?
messageCount Int @default(0)
lastMessageAt DateTime @default(now())
}
6 changes: 5 additions & 1 deletion src/commands/Information/rank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ export default class RankCommand extends BaseCommand {
});
}

async execute(ctx: Context): Promise<void> {
async execute(ctx: Context) {
await ctx.reply('This command is currently disabled. Use `/leaderboard user` instead.');
}

async executeOld(ctx: Context): Promise<void> {
await ctx.deferReply();

try {
Expand Down
31 changes: 31 additions & 0 deletions src/commands/Main/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2025 InterChat
*
* InterChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* InterChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with InterChat. If not, see <https://www.gnu.org/licenses/>.
*/

import ConfigSetInviteSubcommand from '#src/commands/Main/config/set-invite.js';
import BaseCommand from '#src/core/BaseCommand.js';
export default class ConfigCommand extends BaseCommand {
constructor() {
super({
name: 'config',
description: 'Configure Server settings for InterChat.',
types: { slash: true, prefix: true },
subcommands: {
'set-invite': new ConfigSetInviteSubcommand(),
},
});
}
}
88 changes: 88 additions & 0 deletions src/commands/Main/config/set-invite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (C) 2025 InterChat
*
* InterChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* InterChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with InterChat. If not, see <https://www.gnu.org/licenses/>.
*/

import BaseCommand from '#src/core/BaseCommand.js';
import Context from '#src/core/CommandContext/Context.js';
import db from '#src/utils/Db.js';
import { ApplicationCommandOptionType, Invite } from 'discord.js';

export default class ConfigSetInviteSubcommand extends BaseCommand {
constructor() {
super({
name: 'set-invite',
description:
'Set the invite link for the server. People can use it to join through InterChat leaderboards.',
types: { slash: true, prefix: true },
options: [
{
type: ApplicationCommandOptionType.String,
name: 'invite',
description: 'The invite link to set for the server. (Leave empty to remove)',
required: false,
},
],
});
}
async execute(ctx: Context) {
if (!ctx.inGuild()) return;
await ctx.deferReply();

const inviteLink = ctx.options.getString('invite');
if (!inviteLink?.length) {
await db.serverData.upsert({
where: { id: ctx.guild.id },
create: { id: ctx.guildId },
update: { inviteCode: null },
});

await ctx.replyEmbed('config.setInvite.removed', {
edit: true,
t: { emoji: ctx.getEmoji('tick_icon') },
});
return;
}

const inviteCode = inviteLink.match(Invite.InvitesPattern)?.[1];
if (!inviteCode) {
await ctx.replyEmbed('config.setInvite.invalid', {
edit: true,
t: { emoji: ctx.getEmoji('x_icon') },
});
return;
}

const inviteInGuild = (await ctx.guild.invites.fetch()).get(inviteCode);
if (!inviteInGuild) {
await ctx.replyEmbed('config.setInvite.notFromServer', {
edit: true,
t: { emoji: ctx.getEmoji('x_icon') },
});
return;
}

await db.serverData.upsert({
where: { id: ctx.guild.id },
create: { id: ctx.guildId, inviteCode },
update: { inviteCode },
});

await ctx.replyEmbed('config.setInvite.success', {
edit: true,
t: { emoji: ctx.getEmoji('tick_icon') },
});
}
}
76 changes: 0 additions & 76 deletions src/commands/Main/leaderboard.ts

This file was deleted.

33 changes: 33 additions & 0 deletions src/commands/Main/leaderboard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2025 InterChat
*
* InterChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* InterChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with InterChat. If not, see <https://www.gnu.org/licenses/>.
*/

import ServerLeaderboardCommand from '#src/commands/Main/leaderboard/server.js';
import UserLeaderboardCommand from '#src/commands/Main/leaderboard/user.js';
import BaseCommand from '#src/core/BaseCommand.js';
export default class LeaderboardCommand extends BaseCommand {
constructor() {
super({
name: 'leaderboard',
description: 'leaderboard rahhh',
types: { slash: true, prefix: true },
subcommands: {
user: new UserLeaderboardCommand(),
server: new ServerLeaderboardCommand(),
},
});
}
}
48 changes: 48 additions & 0 deletions src/commands/Main/leaderboard/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2025 InterChat
*
* InterChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* InterChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with InterChat. If not, see <https://www.gnu.org/licenses/>.
*/

import BaseCommand from '#src/core/BaseCommand.js';
import type Context from '#src/core/CommandContext/Context.js';
import Constants from '#src/utils/Constants.js';
import { formatServerLeaderboard, getLeaderboard } from '#src/utils/Leaderboard.js';
import { resolveColor } from 'discord.js';

export default class ServerLeaderboardCommand extends BaseCommand {
constructor() {
super({
name: 'server',
description: 'Shows the global server leaderboard for InterChat (with invites).',
types: { slash: true, prefix: true },
});
}

async execute(ctx: Context) {
const leaderboard = await getLeaderboard('server', 10);
const leaderboardTable = await formatServerLeaderboard(leaderboard, ctx.client);

await ctx.reply({
embeds: [
{
title: `${ctx.getEmoji('hash_icon')} Global Server Leaderboard`,
description: leaderboardTable,
color: resolveColor(Constants.Colors.invisible),
footer: { text: 'Resets every month. Send a message in any hub to get on it!' },
},
],
});
}
}
48 changes: 48 additions & 0 deletions src/commands/Main/leaderboard/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2025 InterChat
*
* InterChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* InterChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with InterChat. If not, see <https://www.gnu.org/licenses/>.
*/

import BaseCommand from '#src/core/BaseCommand.js';
import type Context from '#src/core/CommandContext/Context.js';
import Constants from '#src/utils/Constants.js';
import { formatUserLeaderboard, getLeaderboard } from '#src/utils/Leaderboard.js';
import { resolveColor } from 'discord.js';

export default class UserLeaderboardCommand extends BaseCommand {
constructor() {
super({
name: 'user',
description: 'Shows the global user leaderboard for InterChat (with messages).',
types: { slash: true, prefix: true },
});
}

async execute(ctx: Context) {
const leaderboard = await getLeaderboard('user', 10);
const leaderboardTable = await formatUserLeaderboard(leaderboard, ctx.client);

await ctx.reply({
embeds: [
{
title: `${ctx.getEmoji('hash_icon')} Global User Leaderboard`,
description: leaderboardTable,
color: resolveColor(Constants.Colors.invisible),
footer: { text: 'Resets every month. Send a message in any hub to get on it!' },
},
],
});
}
}
Loading

0 comments on commit 9ff2e7e

Please sign in to comment.