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

feat: global user & server message leaderboards #245

Merged
merged 1 commit into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading