mirror of
https://github.com/veganhacktivists/arabot.git
synced 2025-12-02 10:50:02 +01:00
Compare commits
31 Commits
feat/new-p
...
coolify
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ebf8a6938 | ||
|
|
bc7f2ffcfd | ||
|
|
86f391e131 | ||
|
|
63c3b14b1c | ||
|
|
a5187ec567 | ||
|
|
222c3cb81a | ||
|
|
8f8580398e | ||
|
|
fe88e9f87b | ||
|
|
4ad35f5b57 | ||
|
|
1c9f6612a3 | ||
|
|
88dd678bdc | ||
|
|
9c51be9ab6 | ||
|
|
128b15f18f | ||
|
|
dba9aa970e | ||
|
|
0ac0ff7f5c | ||
|
|
ae0afa02db | ||
|
|
3009a0f923 | ||
|
|
a09b007831 | ||
|
|
325dc0d0d0 | ||
|
|
71a065d3ca | ||
|
|
613f53491b | ||
|
|
19721c10ea | ||
|
|
bd87a8b6c6 | ||
|
|
46ef2fd8e2 | ||
|
|
d8c91fd39b | ||
|
|
fabd381051 | ||
|
|
a5758dc6ef | ||
|
|
9ff5b78aff | ||
|
|
f4655829e2 | ||
|
|
c82d256be4 | ||
|
|
a9039572d1 |
10
.env.example
10
.env.example
@@ -3,16 +3,18 @@ DISCORD_TOKEN= # Bot token from: https://discord.com/developers/
|
||||
|
||||
# Configuration
|
||||
DEFAULT_PREFIX= # Prefix used to run commands in Discord
|
||||
DEVELOPMENT= # (true/false) Enables developer mode
|
||||
DEVELOPMENT= # (true/false) Enables developer mode
|
||||
|
||||
# Docker
|
||||
POSTGRES_USER=USERNAME
|
||||
POSTGRES_PASSWORD=PASSWORD
|
||||
POSTGRES_DB=DB
|
||||
|
||||
# Redis
|
||||
REDIS_URL= # URL to redis database (if running everything within docker compose, use "redis")
|
||||
BULLMQ_URL # URL for redis database, but without redis:// and credentials
|
||||
# Redis (if running everything within docker compose, use "redis" for the host and leave the rest empty)
|
||||
REDIS_HOST= # URL to redis database
|
||||
REDIS_USER= # redis database user
|
||||
REDIS_PASSWORD= # redis database password
|
||||
REDIS_PORT= # redis database port
|
||||
|
||||
# Database URL (designed for Postgres, but designed on Prisma)
|
||||
DATABASE_URL= # "postgresql://USERNAME:PASSWORD@postgres:5432/DB?schema=ara&sslmode=prefer"
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
dist
|
||||
node_modules
|
||||
tsconfig.json
|
||||
pnpm-lock.yaml
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:20 AS base
|
||||
FROM node:22 AS base
|
||||
# PNPM
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
|
||||
5
nixpacks.toml
Normal file
5
nixpacks.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[phases.build]
|
||||
cmds = ["pnpm prisma generate", "..."]
|
||||
|
||||
[start]
|
||||
cmd = 'pnpm run start:migrate'
|
||||
32
package.json
32
package.json
@@ -31,33 +31,33 @@
|
||||
"homepage": "https://github.com/veganhacktivists/arabot#readme",
|
||||
"engines": {
|
||||
"node": ">=20",
|
||||
"pnpm": ">=8"
|
||||
"pnpm": ">=9"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^5.9.1",
|
||||
"@sapphire/discord.js-utilities": "^7.1.6",
|
||||
"@sapphire/framework": "^5.0.7",
|
||||
"@prisma/client": "^5.18.0",
|
||||
"@sapphire/discord.js-utilities": "^7.3.0",
|
||||
"@sapphire/framework": "^5.2.1",
|
||||
"@sapphire/plugin-logger": "^4.0.2",
|
||||
"@sapphire/plugin-scheduled-tasks": "^10.0.1",
|
||||
"@sapphire/plugin-subcommands": "^6.0.3",
|
||||
"@sapphire/stopwatch": "^1.5.2",
|
||||
"@sapphire/time-utilities": "^1.7.12",
|
||||
"@sapphire/ts-config": "^5.0.0",
|
||||
"@sapphire/utilities": "^3.15.3",
|
||||
"@types/node": "^20.11.16",
|
||||
"bullmq": "^5.1.8",
|
||||
"discord.js": "^14.14.1",
|
||||
"redis": "^4.6.12",
|
||||
"@sapphire/ts-config": "^5.0.1",
|
||||
"@sapphire/utilities": "^3.17.0",
|
||||
"bullmq": "^5.12.10",
|
||||
"discord.js": "^14.15.3",
|
||||
"ioredis": "^5.4.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3"
|
||||
"typescript": "~5.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
||||
"@typescript-eslint/parser": "^6.20.0",
|
||||
"@types/node": "^20.16.1",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"@typescript-eslint/parser": "^6.21.0",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"ioredis": "^5.3.2",
|
||||
"prettier": "3.2.4",
|
||||
"prisma": "^5.9.1"
|
||||
}
|
||||
"prisma": "^5.18.0"
|
||||
},
|
||||
"packageManager": "pnpm@9.12.2+sha512.22721b3a11f81661ae1ec68ce1a7b879425a1ca5b991c975b074ac220b187ce56c708fe5db69f4c962c989452eee76c82877f4ee80f474cebd61ee13461b6228"
|
||||
}
|
||||
|
||||
2471
pnpm-lock.yaml
generated
2471
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `channelId` to the `StatRole` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "StatRole" ADD COLUMN "channelId" TEXT NOT NULL;
|
||||
@@ -222,9 +222,10 @@ model Stat {
|
||||
}
|
||||
|
||||
model StatRole {
|
||||
stat Stat @relation(fields: [statId], references: [id])
|
||||
statId Int @id
|
||||
roleId String
|
||||
stat Stat @relation(fields: [statId], references: [id])
|
||||
statId Int @id
|
||||
roleId String
|
||||
channelId String
|
||||
}
|
||||
|
||||
model ParticipantStat {
|
||||
|
||||
@@ -359,7 +359,7 @@ export class PrivateCommand extends Subcommand {
|
||||
} else if (user.roles.cache.has(IDs.roles.staff.mediaCoordinator)) {
|
||||
name = 'media';
|
||||
id = IDs.roles.staff.mediaCoordinator;
|
||||
} else if (user.roles.cache.has(IDs.roles.staff.hrCoordinator)) {
|
||||
} else if (user.roles.cache.has(IDs.roles.staff.hrCoordinator)) {
|
||||
name = 'hr';
|
||||
id = IDs.roles.staff.hrCoordinator;
|
||||
} else {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import type { User, Guild, Message } from 'discord.js';
|
||||
import { updateUser } from '#utils/database/dbExistingUser';
|
||||
import { getBalance } from '#utils/database/economy';
|
||||
import { getBalance } from '#utils/database/fun/economy';
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
|
||||
export class BalanceCommand extends Command {
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import { Time } from '@sapphire/time-utilities';
|
||||
import type { User, Guild, GuildMember, Message } from 'discord.js';
|
||||
import { updateUser } from '#utils/database/dbExistingUser';
|
||||
import { daily, getLastDaily } from '#utils/database/economy';
|
||||
import { daily, getLastDaily } from '#utils/database/fun/economy';
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import type { User, Guild, Message } from 'discord.js';
|
||||
import { updateUser } from '#utils/database/dbExistingUser';
|
||||
import { getBalance, transfer } from '#utils/database/economy';
|
||||
import { getBalance, transfer } from '#utils/database/fun/economy';
|
||||
import { EmbedBuilder, TextChannel } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import { EmbedBuilder, GuildMember } from 'discord.js';
|
||||
import { N1984 } from '#utils/gifs';
|
||||
import { addFunLog, countTotal } from '#utils/database/fun';
|
||||
import { addFunLog, countTotal } from '#utils/database/fun/fun';
|
||||
|
||||
export class N1984Command extends Command {
|
||||
public constructor(context: Command.LoaderContext, options: Command.Options) {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import { EmbedBuilder, GuildMember } from 'discord.js';
|
||||
import { Cringe } from '#utils/gifs';
|
||||
import { addFunLog, countTotal } from '#utils/database/fun';
|
||||
import { addFunLog, countTotal } from '#utils/database/fun/fun';
|
||||
|
||||
export class CringeCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext, options: Command.Options) {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import { EmbedBuilder, GuildMember } from 'discord.js';
|
||||
import { Hugs } from '#utils/gifs';
|
||||
import { addFunLog, countTotal } from '#utils/database/fun';
|
||||
import { addFunLog, countTotal } from '#utils/database/fun/fun';
|
||||
|
||||
export class HugCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext, options: Command.Options) {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import { EmbedBuilder, GuildMember } from 'discord.js';
|
||||
import { Kill } from '#utils/gifs';
|
||||
import { addFunLog, countTotal } from '#utils/database/fun';
|
||||
import { addFunLog, countTotal } from '#utils/database/fun/fun';
|
||||
|
||||
export class KillCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext, options: Command.Options) {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import { EmbedBuilder, GuildMember } from 'discord.js';
|
||||
import { Poke } from '#utils/gifs';
|
||||
import { addFunLog, countTotal } from '#utils/database/fun';
|
||||
import { addFunLog, countTotal } from '#utils/database/fun/fun';
|
||||
|
||||
export class PokeCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext, options: Command.Options) {
|
||||
|
||||
@@ -21,9 +21,12 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import type { User, Message, Snowflake, TextChannel, Guild } from 'discord.js';
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
import { addBan, checkBan } from '#utils/database/ban';
|
||||
import { addBan, checkBan } from '#utils/database/moderation/ban';
|
||||
import { addEmptyUser, updateUser } from '#utils/database/dbExistingUser';
|
||||
import { checkTempBan, removeTempBan } from '#utils/database/tempBan';
|
||||
import {
|
||||
checkTempBan,
|
||||
removeTempBan,
|
||||
} from '#utils/database/moderation/tempBan';
|
||||
|
||||
export class BanCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext, options: Command.Options) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import { Duration, DurationFormatter } from '@sapphire/time-utilities';
|
||||
import type { User, Snowflake, TextChannel, Guild } from 'discord.js';
|
||||
import { EmbedBuilder, Message } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
import { addTempBan, checkTempBan } from '#utils/database/tempBan';
|
||||
import { addTempBan, checkTempBan } from '#utils/database/moderation/tempBan';
|
||||
import { addEmptyUser, updateUser } from '#utils/database/dbExistingUser';
|
||||
|
||||
export class TempBanCommand extends Command {
|
||||
|
||||
@@ -28,8 +28,11 @@ import type {
|
||||
} from 'discord.js';
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
import { removeBan, checkBan, addBan } from '#utils/database/ban';
|
||||
import { checkTempBan, removeTempBan } from '#utils/database/tempBan';
|
||||
import { removeBan, checkBan, addBan } from '#utils/database/moderation/ban';
|
||||
import {
|
||||
checkTempBan,
|
||||
removeTempBan,
|
||||
} from '#utils/database/moderation/tempBan';
|
||||
import { addEmptyUser, addExistingUser } from '#utils/database/dbExistingUser';
|
||||
|
||||
export class UnbanCommand extends Command {
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
updateUser,
|
||||
fetchRoles,
|
||||
} from '#utils/database/dbExistingUser';
|
||||
import { restrict, checkActive } from '#utils/database/restriction';
|
||||
import { restrict, checkActive } from '#utils/database/moderation/restriction';
|
||||
import { randint } from '#utils/maths';
|
||||
import { blockedRolesAfterRestricted } from '#utils/blockedRoles';
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import { ChannelType, EmbedBuilder } from 'discord.js';
|
||||
import type { Message, TextChannel, Guild, Snowflake } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
import { getRestrictions } from '#utils/database/restriction';
|
||||
import { getRestrictions } from '#utils/database/moderation/restriction';
|
||||
import { checkStaff } from '#utils/checker';
|
||||
|
||||
export class RestrictLogsCommand extends Command {
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
unRestrict,
|
||||
checkActive,
|
||||
unRestrictLegacy,
|
||||
} from '#utils/database/restriction';
|
||||
} from '#utils/database/moderation/restriction';
|
||||
|
||||
export class UnRestrictCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext, options: Command.Options) {
|
||||
|
||||
@@ -39,7 +39,7 @@ import {
|
||||
getNote,
|
||||
deactivateNote,
|
||||
deactivateAllNotes,
|
||||
} from '#utils/database/sus';
|
||||
} from '#utils/database/moderation/sus';
|
||||
import { checkStaff } from '#utils/checker';
|
||||
import IDs from '#utils/ids';
|
||||
import { createSusLogEmbed } from '#utils/embeds';
|
||||
@@ -219,26 +219,11 @@ export class SusCommand extends Subcommand {
|
||||
success: false,
|
||||
};
|
||||
|
||||
// Get GuildMember for user to add a sus note for
|
||||
let member = guild.members.cache.get(user.id);
|
||||
|
||||
// Checks if Member was not found in cache
|
||||
if (member === undefined) {
|
||||
// Fetches Member from API call to Discord
|
||||
member = await guild.members.fetch(user.id);
|
||||
if (member === undefined) {
|
||||
info.message = 'Error fetching user';
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the data to the database
|
||||
await addSusNoteDB(user.id, mod.id, note);
|
||||
|
||||
// Give the user the sus role they don't already have the sus note
|
||||
if (!member.roles.cache.has(IDs.roles.restrictions.sus)) {
|
||||
await member.roles.add(IDs.roles.restrictions.sus);
|
||||
}
|
||||
// Gives the sus role to the user
|
||||
await this.addSusRole(user, guild);
|
||||
|
||||
info.message = `Added the sus note for ${user}: ${note}`;
|
||||
info.success = true;
|
||||
@@ -278,6 +263,26 @@ export class SusCommand extends Subcommand {
|
||||
return info;
|
||||
}
|
||||
|
||||
private async addSusRole(user: User, guild: Guild) {
|
||||
// Get GuildMember for user to add a sus note for
|
||||
let member = guild.members.cache.get(user.id);
|
||||
|
||||
// Checks if Member was not found in cache
|
||||
if (member === undefined) {
|
||||
// Fetches Member from API call to Discord
|
||||
member = await guild.members.fetch(user.id).catch(() => undefined);
|
||||
}
|
||||
|
||||
if (member === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Give the user the sus role they don't already have the sus note
|
||||
if (!member.roles.cache.has(IDs.roles.restrictions.sus)) {
|
||||
await member.roles.add(IDs.roles.restrictions.sus);
|
||||
}
|
||||
}
|
||||
|
||||
public async listNote(interaction: Subcommand.ChatInputCommandInteraction) {
|
||||
// Get the arguments
|
||||
const user = interaction.options.getUser('user', true);
|
||||
|
||||
@@ -19,7 +19,11 @@
|
||||
|
||||
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import type { GuildMember, Message } from 'discord.js';
|
||||
import { addMute, removeMute, checkActive } from '#utils/database/vcMute';
|
||||
import {
|
||||
addMute,
|
||||
removeMute,
|
||||
checkActive,
|
||||
} from '#utils/database/moderation/vcMute';
|
||||
import { addExistingUser } from '#utils/database/dbExistingUser';
|
||||
|
||||
export class VCMuteCommand extends Command {
|
||||
|
||||
@@ -21,7 +21,10 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import { EmbedBuilder, TextChannel } from 'discord.js';
|
||||
import type { Message, Guild, User } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
import { deleteWarning, fetchWarning } from '#utils/database/warnings';
|
||||
import {
|
||||
deleteWarning,
|
||||
fetchWarning,
|
||||
} from '#utils/database/moderation/warnings';
|
||||
import { checkStaff } from '#utils/checker';
|
||||
|
||||
export class DeleteWarningCommand extends Command {
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
} from '@sapphire/framework';
|
||||
import type { User, Message, Snowflake, Guild, TextChannel } from 'discord.js';
|
||||
import { updateUser } from '#utils/database/dbExistingUser';
|
||||
import { addWarn } from '#utils/database/warnings';
|
||||
import { addWarn } from '#utils/database/moderation/warnings';
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Args, Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import { ChannelType, EmbedBuilder } from 'discord.js';
|
||||
import type { Message, Guild, User } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
import { fetchWarnings } from '#utils/database/warnings';
|
||||
import { fetchWarnings } from '#utils/database/moderation/warnings';
|
||||
import { checkStaff } from '#utils/checker';
|
||||
import { createWarningsEmbed } from '#utils/embeds';
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
import { Subcommand } from '@sapphire/plugin-subcommands';
|
||||
import { RegisterBehavior } from '@sapphire/framework';
|
||||
import type { Snowflake } from 'discord.js';
|
||||
import { ChannelType, PermissionsBitField, Snowflake } from 'discord.js';
|
||||
import { updateUser } from '#utils/database/dbExistingUser';
|
||||
import {
|
||||
addStatUser,
|
||||
@@ -66,7 +66,6 @@ export class OutreachCommand extends Subcommand {
|
||||
],
|
||||
},
|
||||
],
|
||||
preconditions: ['ModOnly'],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -200,15 +199,15 @@ export class OutreachCommand extends Subcommand {
|
||||
|
||||
if (mod === undefined) {
|
||||
await interaction.reply({
|
||||
content: 'Mod was not found!',
|
||||
content: 'Outreach Leader was not found!',
|
||||
ephemeral: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mod.roles.cache.has(IDs.roles.staff.outreachCoordinator)) {
|
||||
if (!mod.roles.cache.has(IDs.roles.staff.outreachLeader)) {
|
||||
await interaction.reply({
|
||||
content: 'You need to be an Outreach Coordinator to run this command!',
|
||||
content: 'You need to be an Outreach Leader to run this command!',
|
||||
ephemeral: true,
|
||||
});
|
||||
return;
|
||||
@@ -254,9 +253,9 @@ export class OutreachCommand extends Subcommand {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mod.roles.cache.has(IDs.roles.staff.outreachCoordinator)) {
|
||||
if (!mod.roles.cache.has(IDs.roles.staff.outreachLeader)) {
|
||||
await interaction.reply({
|
||||
content: 'You need to be an Outreach Coordinator to run this command!',
|
||||
content: 'You need to be an Outreach Leader to run this command!',
|
||||
ephemeral: true,
|
||||
});
|
||||
return;
|
||||
@@ -275,7 +274,8 @@ export class OutreachCommand extends Subcommand {
|
||||
|
||||
stat.forEach(({ role }) => {
|
||||
if (role !== null) {
|
||||
guild.roles.delete(role.roleId);
|
||||
guild.roles.delete(role.roleId); // Delete role
|
||||
guild.channels.delete(role.channelId); // Delete VC
|
||||
}
|
||||
});
|
||||
|
||||
@@ -388,14 +388,66 @@ export class OutreachCommand extends Subcommand {
|
||||
|
||||
await updateUser(leaderMember);
|
||||
|
||||
// Create role for group
|
||||
const role = await guild.roles.create({
|
||||
name: `Outreach Group ${groupNo}`,
|
||||
mentionable: true,
|
||||
});
|
||||
|
||||
await createStat(event.id, leader.id, role.id);
|
||||
// Create a voice channel for group
|
||||
const channel = await guild.channels.create({
|
||||
name: `Outreach Group ${groupNo}`,
|
||||
type: ChannelType.GuildVoice,
|
||||
parent: IDs.categories.activism,
|
||||
permissionOverwrites: [
|
||||
{
|
||||
id: guild.roles.everyone,
|
||||
deny: [
|
||||
PermissionsBitField.Flags.SendMessages,
|
||||
PermissionsBitField.Flags.Connect,
|
||||
PermissionsBitField.Flags.ViewChannel,
|
||||
],
|
||||
},
|
||||
{
|
||||
id: IDs.roles.vegan.activist,
|
||||
allow: [PermissionsBitField.Flags.ViewChannel],
|
||||
},
|
||||
{
|
||||
id: role.id, // Permissions for the specific group
|
||||
allow: [
|
||||
PermissionsBitField.Flags.SendMessages,
|
||||
PermissionsBitField.Flags.Connect,
|
||||
],
|
||||
},
|
||||
{
|
||||
id: IDs.roles.staff.outreachLeader,
|
||||
allow: [
|
||||
PermissionsBitField.Flags.SendMessages,
|
||||
PermissionsBitField.Flags.Connect,
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Create stats in database
|
||||
await createStat(event.id, leader.id, role.id, channel.id);
|
||||
|
||||
// Give group leader role
|
||||
await leaderMember.roles.add(role);
|
||||
|
||||
// Send message in VC with a welcome and reminder
|
||||
await channel.send(
|
||||
`Welcome ${role}, ${leaderMember} is going to be the leader of your group!\n\n` +
|
||||
'Remember to keep track of stats during activism with `/outreach group update` and' +
|
||||
'to have these questions in mind whilst doing activism:\n' +
|
||||
'- How many said would go vegan?\n' +
|
||||
'- How many seriously considered being vegan?\n' +
|
||||
'- How many people had anti-vegan viewpoints?\n' +
|
||||
'- How many thanked you for the conversation?\n' +
|
||||
'- How many said they would watch a vegan documentary?\n' +
|
||||
'- How many got educated on veganism or the animal industry?',
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
content: `Created a group with the leader being ${leader}`,
|
||||
});
|
||||
@@ -442,7 +494,7 @@ export class OutreachCommand extends Subcommand {
|
||||
|
||||
if (
|
||||
leader.id !== stat.stat.leaderId &&
|
||||
!leaderMember.roles.cache.has(IDs.roles.staff.outreachCoordinator)
|
||||
!leaderMember.roles.cache.has(IDs.roles.staff.outreachLeader)
|
||||
) {
|
||||
await interaction.editReply({
|
||||
content: `You are not the leader for ${group}`,
|
||||
|
||||
@@ -29,7 +29,7 @@ export class PlusCommand extends Command {
|
||||
name: 'plus',
|
||||
aliases: ['+'],
|
||||
description: 'Give/remove the plus role',
|
||||
preconditions: [['CoordinatorOnly', 'ModOnly']],
|
||||
preconditions: [['CoordinatorOnly', 'VerifierOnly', 'ModOnly']],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,6 +138,14 @@ export class PlusCommand extends Command {
|
||||
info.success = true;
|
||||
return info;
|
||||
}
|
||||
|
||||
// Checks if the user is vegan before giving the plus role
|
||||
// If not, stop from giving the plus role
|
||||
if (!member.roles.cache.has(IDs.roles.vegan.vegan)) {
|
||||
info.message = `Can't give ${user} the vegan role as they are not vegan!`;
|
||||
return info;
|
||||
}
|
||||
|
||||
// Add Plus role to the user
|
||||
await member.roles.add(plus);
|
||||
await roleAddLog(user.id, mod.id, plus);
|
||||
|
||||
@@ -146,8 +146,8 @@ export class TrustedCommand extends Command {
|
||||
.send(
|
||||
`You have been given the ${trusted.name} role by ${mod}!` +
|
||||
'\n\nThis role allows you to post attachments to the server and stream in VCs.' +
|
||||
"\nMake sure that you follow the rules, and don't post anything NSFW, anything objectifying animals and follow Discord's ToS." +
|
||||
`\nNot following these rules can result in the removal of the ${trusted.name} role.`,
|
||||
'\nMake sure that you follow the rules, especially by **not** posting anything **NSFW**, and **no animal products or consumption of animal products**.' +
|
||||
`\n\nNot following these rules will result in the **immediate removal** of the ${trusted.name} role.`,
|
||||
)
|
||||
.catch(() => {});
|
||||
info.success = true;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
import { Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import IDs from '#utils/ids';
|
||||
|
||||
export class InfoCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext, options: Command.Options) {
|
||||
@@ -94,7 +95,9 @@ export class InfoCommand extends Command {
|
||||
message =
|
||||
"If you want to have the vegan or activist role, you'll need to do a voice verification. " +
|
||||
"To do this, hop into the 'Verification' voice channel." +
|
||||
"\n\nIf there aren't any verifiers available, you'll be disconnected, and you can rejoin later.";
|
||||
"\n\nIf there aren't any verifiers available, you'll be disconnected, and you can rejoin later." +
|
||||
`\n\nAlternatively if you would like text verification, you can use \`/apply\` in <#${IDs.channels.nonVegan.vcText}> ` +
|
||||
'to be able fill out a Vegan Verification form through the Appy Bot.';
|
||||
break;
|
||||
case 'modMail':
|
||||
message =
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { Args, Command, RegisterBehavior } from '@sapphire/framework';
|
||||
import type { User, Guild, Message } from 'discord.js';
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
import { getRank, xpToNextLevel } from '#utils/database/xp';
|
||||
import { getRank, xpToNextLevel } from '#utils/database/fun/xp';
|
||||
|
||||
export class RankCommand extends Command {
|
||||
public constructor(context: Command.LoaderContext, options: Command.Options) {
|
||||
|
||||
25
src/index.ts
25
src/index.ts
@@ -25,8 +25,11 @@ import { LogLevel, SapphireClient, container } from '@sapphire/framework';
|
||||
import '@sapphire/plugin-scheduled-tasks/register';
|
||||
import '@sapphire/plugin-logger/register';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { createClient } from 'redis';
|
||||
import type { RedisClientType } from 'redis';
|
||||
import { Redis } from 'ioredis';
|
||||
|
||||
const REDIS_PORT = process.env.REDIS_PORT
|
||||
? parseInt(process.env.REDIS_PORT)
|
||||
: undefined;
|
||||
|
||||
// Setting up the Sapphire client
|
||||
const client = new SapphireClient({
|
||||
@@ -50,7 +53,10 @@ const client = new SapphireClient({
|
||||
tasks: {
|
||||
bull: {
|
||||
connection: {
|
||||
host: process.env.BULLMQ_URL,
|
||||
host: process.env.REDIS_HOST,
|
||||
username: process.env.REDIS_USER,
|
||||
password: process.env.REDIS_PASSWORD,
|
||||
port: REDIS_PORT,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -63,11 +69,14 @@ const main = async () => {
|
||||
client.logger.info('Logging in');
|
||||
|
||||
// Create databases
|
||||
container.database = await new PrismaClient();
|
||||
container.redis = createClient({
|
||||
url: process.env.REDIS_URL,
|
||||
container.database = new PrismaClient();
|
||||
container.redis = new Redis({
|
||||
host: process.env.REDIS_HOST,
|
||||
username: process.env.REDIS_USER,
|
||||
password: process.env.REDIS_PASSWORD,
|
||||
port: REDIS_PORT,
|
||||
db: 1,
|
||||
});
|
||||
await container.redis.connect();
|
||||
|
||||
// Log the bot in to Discord
|
||||
await client.login(token);
|
||||
@@ -83,7 +92,7 @@ const main = async () => {
|
||||
declare module '@sapphire/pieces' {
|
||||
interface Container {
|
||||
database: PrismaClient;
|
||||
redis: RedisClientType;
|
||||
redis: Redis;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,8 @@ export class WelcomeButtonHandler extends InteractionHandler {
|
||||
await general.send(
|
||||
`${member} Welcome to ARA! :D Please check <#${IDs.channels.information.roles}> ` +
|
||||
`and remember to follow the <#${IDs.channels.information.conduct}> and to respect ongoing discussions and debates.` +
|
||||
"\n\nIf you would like to be verified as a vegan, join the 'Verification' voice channel.",
|
||||
`\n\nIf you are vegan, you can join the 'Verification' voice channel, or use \`/apply\` with the Appy bot in <#${IDs.channels.nonVegan.vcText}>, ` +
|
||||
'to be verified and gain access to more channels.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { Listener } from '@sapphire/framework';
|
||||
import type { GuildBan } from 'discord.js';
|
||||
import { AuditLogEvent, EmbedBuilder, TextChannel } from 'discord.js';
|
||||
import { addBan, checkBan } from '#utils/database/ban';
|
||||
import { addBan, checkBan } from '#utils/database/moderation/ban';
|
||||
import IDs from '#utils/ids';
|
||||
import { addEmptyUser, addExistingUser } from '#utils/database/dbExistingUser';
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
import { Listener } from '@sapphire/framework';
|
||||
import type { GuildMember } from 'discord.js';
|
||||
import { checkBan, getBanReason } from '#utils/database/ban';
|
||||
import { checkTempBan } from '#utils/database/tempBan';
|
||||
import { checkBan, getBanReason } from '#utils/database/moderation/ban';
|
||||
import { checkTempBan } from '#utils/database/moderation/tempBan';
|
||||
|
||||
export class BanJoinListener extends Listener {
|
||||
public constructor(
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import { Listener } from '@sapphire/framework';
|
||||
import type { GuildBan } from 'discord.js';
|
||||
import { AuditLogEvent, EmbedBuilder, TextChannel } from 'discord.js';
|
||||
import { addBan, checkBan, removeBan } from '#utils/database/ban';
|
||||
import { addBan, checkBan, removeBan } from '#utils/database/moderation/ban';
|
||||
import IDs from '#utils/ids';
|
||||
import { addEmptyUser, addExistingUser } from '#utils/database/dbExistingUser';
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
import { Listener } from '@sapphire/framework';
|
||||
import type { Message } from 'discord.js';
|
||||
import { getLastCount, addCount } from '#utils/database/counting';
|
||||
import { getLastCount, addCount } from '#utils/database/fun/counting';
|
||||
import IDs from '#utils/ids';
|
||||
|
||||
export class XpListener extends Listener {
|
||||
|
||||
@@ -22,14 +22,17 @@ import { ChannelType } from 'discord.js';
|
||||
import type { GuildChannel, EmbedBuilder } from 'discord.js';
|
||||
import { setTimeout } from 'timers/promises';
|
||||
import IDs from '#utils/ids';
|
||||
import { checkActive, getRestrictions } from '#utils/database/restriction';
|
||||
import { findNotes } from '#utils/database/sus';
|
||||
import {
|
||||
checkActive,
|
||||
getRestrictions,
|
||||
} from '#utils/database/moderation/restriction';
|
||||
import { findNotes } from '#utils/database/moderation/sus';
|
||||
import {
|
||||
createRestrictLogEmbed,
|
||||
createSusLogEmbed,
|
||||
createWarningsEmbed,
|
||||
} from '#utils/embeds';
|
||||
import { fetchWarnings } from '#utils/database/warnings';
|
||||
import { fetchWarnings } from '#utils/database/moderation/warnings';
|
||||
|
||||
export class ModMailCreateListener extends Listener {
|
||||
public constructor(
|
||||
|
||||
@@ -28,7 +28,10 @@ import type {
|
||||
import { ChannelType } from 'discord.js';
|
||||
import { fetchRoles, getLeaveRoles } from '#utils/database/dbExistingUser';
|
||||
import { blockTime } from '#utils/database/verification';
|
||||
import { checkActive, getSection } from '#utils/database/restriction';
|
||||
import {
|
||||
checkActive,
|
||||
getSection,
|
||||
} from '#utils/database/moderation/restriction';
|
||||
import { blockedRoles, blockedRolesAfterRestricted } from '#utils/blockedRoles';
|
||||
import IDs from '#utils/ids';
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
import { Listener } from '@sapphire/framework';
|
||||
import type { VoiceState } from 'discord.js';
|
||||
import { checkActive, removeMute } from '#utils/database/vcMute';
|
||||
import { checkActive, removeMute } from '#utils/database/moderation/vcMute';
|
||||
|
||||
export class VCMuteListener extends Listener {
|
||||
public constructor(
|
||||
|
||||
@@ -50,7 +50,7 @@ import {
|
||||
startVerification,
|
||||
finishVerification,
|
||||
} from '#utils/database/verification';
|
||||
import { findNotes } from '#utils/database/sus';
|
||||
import { findNotes } from '#utils/database/moderation/sus';
|
||||
import { addExistingUser } from '#utils/database/dbExistingUser';
|
||||
import { rolesToString } from '#utils/formatter';
|
||||
import IDs from '#utils/ids';
|
||||
|
||||
@@ -148,7 +148,10 @@ export class VerificationLeaveVCListener extends Listener {
|
||||
listTextChannels.forEach((c) => {
|
||||
const textChannel = c as TextChannel;
|
||||
// Checks if the channel topic has the user's snowflake
|
||||
if (textChannel.topic!.includes(userSnowflake!)) {
|
||||
if (
|
||||
textChannel.topic !== null &&
|
||||
textChannel.topic.includes(userSnowflake!)
|
||||
) {
|
||||
textChannel.delete();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -80,7 +80,10 @@ export class VerificationReady extends Listener {
|
||||
const textChannel = c as TextChannel;
|
||||
// Checks if the channel topic has the user's snowflake
|
||||
emptyVC.forEach((snowflake) => {
|
||||
if (textChannel.topic!.includes(snowflake)) {
|
||||
if (
|
||||
textChannel.topic !== null &&
|
||||
textChannel.topic.includes(snowflake)
|
||||
) {
|
||||
textChannel.delete();
|
||||
}
|
||||
});
|
||||
|
||||
88
src/listeners/verification/trusted.ts
Normal file
88
src/listeners/verification/trusted.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
/*
|
||||
Animal Rights Advocates Discord Bot
|
||||
Copyright (C) 2024 Anthony Berg
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Listener } from '@sapphire/framework';
|
||||
import { GuildMember } from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
import { noModHistory, userPreviouslyHadRole } from '#utils/database/memberMod';
|
||||
|
||||
/**
|
||||
* Gives the trusted role to users who have levelled up to level 5
|
||||
* and has not gotten any other warnings/restrictions prior.
|
||||
*/
|
||||
export class TrustedListener extends Listener {
|
||||
public constructor(
|
||||
context: Listener.LoaderContext,
|
||||
options: Listener.Options,
|
||||
) {
|
||||
super(context, {
|
||||
...options,
|
||||
event: 'xpLevelUp',
|
||||
});
|
||||
}
|
||||
|
||||
public async run(member: GuildMember, level: number) {
|
||||
// Checks if the member has gotten level 7
|
||||
// Has been nefred. Should take around 1.5 hours to get the trusted role now
|
||||
if (level !== 7) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks if the user has been previously moderated
|
||||
const noModerationHistory = await noModHistory(member.id);
|
||||
if (!noModerationHistory) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { guild } = member;
|
||||
const trusted = guild.roles.cache.get(IDs.roles.trusted);
|
||||
|
||||
if (trusted === undefined) {
|
||||
this.container.logger.error(
|
||||
'TrustedXP Listener: the Trusted role could not be found in the guild.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks if the member has previously had the trusted role given/removed
|
||||
const previouslyHadRole = await userPreviouslyHadRole(
|
||||
member.id,
|
||||
trusted.id,
|
||||
);
|
||||
if (previouslyHadRole) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks if the user already has the trusted role
|
||||
if (member.roles.cache.has(trusted.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Gives the trusted role to the member
|
||||
await member.roles.add(trusted);
|
||||
|
||||
// Send a DM to inform the member that they have been given the trusted role
|
||||
await member.user.send(
|
||||
`Hi, you have been given the ${trusted.name} as you have been interacting in ARA for a long enough time!` +
|
||||
'\n\nThis role allows you to post attachments to the server and stream in VCs.' +
|
||||
'\nMake sure that you follow the rules, especially by **not** posting anything **NSFW**, and **no animal products or consumption of animal products**.' +
|
||||
`\n\nNot following these rules will result in the **immediate removal** of the ${trusted.name} role.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
import { Listener } from '@sapphire/framework';
|
||||
import type { Message } from 'discord.js';
|
||||
import { addXp, checkCanAddXp } from '#utils/database/xp';
|
||||
import { addXp, checkCanAddXp } from '#utils/database/fun/xp';
|
||||
import { randint } from '#utils/maths';
|
||||
|
||||
export class XpListener extends Listener {
|
||||
@@ -46,6 +46,12 @@ export class XpListener extends Listener {
|
||||
|
||||
const xp = randint(15, 25);
|
||||
|
||||
await addXp(user.id, xp);
|
||||
const level = await addXp(user.id, xp);
|
||||
|
||||
// Emits that a user has leveled up
|
||||
if (level !== null) {
|
||||
this.container.logger.info('User is levelling up!');
|
||||
this.container.client.emit('xpLevelUp', message.member, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
58
src/preconditions/OutreachLeaderOnly.ts
Normal file
58
src/preconditions/OutreachLeaderOnly.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
/*
|
||||
Animal Rights Advocates Discord Bot
|
||||
Copyright (C) 2022 Anthony Berg
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { AllFlowsPrecondition } from '@sapphire/framework';
|
||||
import type {
|
||||
CommandInteraction,
|
||||
ContextMenuCommandInteraction,
|
||||
Message,
|
||||
GuildMember,
|
||||
} from 'discord.js';
|
||||
import IDs from '#utils/ids';
|
||||
|
||||
export class OutreachLeaderOnlyPrecondition extends AllFlowsPrecondition {
|
||||
public override async messageRun(message: Message) {
|
||||
// for message command
|
||||
return this.checkCoordinator(message.member!);
|
||||
}
|
||||
|
||||
public override async chatInputRun(interaction: CommandInteraction) {
|
||||
// for slash command
|
||||
return this.checkCoordinator(interaction.member! as GuildMember);
|
||||
}
|
||||
|
||||
public override async contextMenuRun(
|
||||
interaction: ContextMenuCommandInteraction,
|
||||
) {
|
||||
// for context menu command
|
||||
return this.checkCoordinator(interaction.member! as GuildMember);
|
||||
}
|
||||
|
||||
private async checkCoordinator(user: GuildMember) {
|
||||
return user.roles.cache.has(IDs.roles.staff.outreachLeader)
|
||||
? this.ok()
|
||||
: this.error({ message: 'Only outreach leaders can run this command!' });
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@sapphire/framework' {
|
||||
interface Preconditions {
|
||||
OutreachLeaderOnly: never;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,9 @@ export class VerifyReminder extends ScheduledTask {
|
||||
await channel.send(
|
||||
"If you want to have the vegan or activist role, you'll need to do a voice verification. " +
|
||||
"To do this, hop into the 'Verification' voice channel." +
|
||||
"\n\nIf there aren't any verifiers available, you'll be disconnected, and you can rejoin later.",
|
||||
"\n\nIf there aren't any verifiers available, you'll be disconnected, and you can rejoin later." +
|
||||
`\nAlternatively if you would like text verification, you can use \`/apply\` in <#${IDs.channels.nonVegan.vcText}> ` +
|
||||
'to be able fill out a Vegan Verification form through the Appy Bot.',
|
||||
);
|
||||
|
||||
// Reset the total message counter to 0
|
||||
|
||||
@@ -20,8 +20,11 @@
|
||||
import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks';
|
||||
import IDs from '#utils/ids';
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
import { checkBan } from '#utils/database/ban';
|
||||
import { checkTempBan, removeTempBan } from '#utils/database/tempBan';
|
||||
import { checkBan } from '#utils/database/moderation/ban';
|
||||
import {
|
||||
checkTempBan,
|
||||
removeTempBan,
|
||||
} from '#utils/database/moderation/tempBan';
|
||||
|
||||
export class TempBan extends ScheduledTask {
|
||||
public constructor(
|
||||
|
||||
@@ -36,7 +36,7 @@ export async function addXp(userId: Snowflake, xp: number) {
|
||||
}
|
||||
}
|
||||
|
||||
await container.database.xp.upsert({
|
||||
const info = await container.database.xp.upsert({
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
@@ -63,6 +63,12 @@ export async function addXp(userId: Snowflake, xp: number) {
|
||||
xpForNextLevel: xp,
|
||||
},
|
||||
});
|
||||
|
||||
if (level === 1) {
|
||||
return info.level;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkCanAddXp(userId: Snowflake) {
|
||||
55
src/utils/database/memberMod.ts
Normal file
55
src/utils/database/memberMod.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
/*
|
||||
Animal Rights Advocates Discord Bot
|
||||
Copyright (C) 2024 Anthony Berg
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Snowflake } from 'discord.js';
|
||||
import { countWarnings } from '#utils/database/moderation/warnings';
|
||||
import { countRestrictions } from '#utils/database/moderation/restriction';
|
||||
import { container } from '@sapphire/framework';
|
||||
|
||||
/**
|
||||
* Checks if the user has
|
||||
* @param userId Discord Snowflake of the user to check
|
||||
* @return Boolean true if no prior moderation action
|
||||
*/
|
||||
export async function noModHistory(userId: Snowflake) {
|
||||
const warnCount = await countWarnings(userId);
|
||||
const restrictCount = await countRestrictions(userId);
|
||||
|
||||
return warnCount === 0 && restrictCount === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user has previously had a role given or taken away by a moderator.
|
||||
* @param userId Discord Snowflake of the user to check
|
||||
* @param roleId Snowflake of the role being checked for the user
|
||||
* @return Boolean true if the user has had a moderator give/remove the specified role
|
||||
*/
|
||||
export async function userPreviouslyHadRole(
|
||||
userId: Snowflake,
|
||||
roleId: Snowflake,
|
||||
) {
|
||||
const count = await container.database.roleLog.count({
|
||||
where: {
|
||||
userId,
|
||||
roleId,
|
||||
},
|
||||
});
|
||||
|
||||
return count !== 0;
|
||||
}
|
||||
@@ -114,6 +114,19 @@ export async function getSection(userId: Snowflake) {
|
||||
return restriction.section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of restrictions a user has.
|
||||
* @param userId Discord Snowflake of the user to check
|
||||
* @return number The amount of restrictions the user has
|
||||
*/
|
||||
export async function countRestrictions(userId: Snowflake) {
|
||||
return container.database.restrict.count({
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// This is only for restrictions created with the old bot
|
||||
export async function unRestrictLegacy(
|
||||
userId: Snowflake,
|
||||
@@ -61,3 +61,16 @@ export async function deleteWarning(warningId: number) {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of warnings a user has.
|
||||
* @param userId Discord Snowflake of the user to check
|
||||
* @return number The amount of warnings the user has
|
||||
*/
|
||||
export async function countWarnings(userId: Snowflake) {
|
||||
return container.database.warning.count({
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -85,6 +85,7 @@ export async function createStat(
|
||||
eventId: number,
|
||||
leaderId: Snowflake,
|
||||
roleId: Snowflake,
|
||||
channelId: Snowflake,
|
||||
) {
|
||||
await container.database.stat.create({
|
||||
data: {
|
||||
@@ -110,6 +111,7 @@ export async function createStat(
|
||||
role: {
|
||||
create: {
|
||||
roleId,
|
||||
channelId,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -60,6 +60,7 @@ const devIDs = {
|
||||
outreachCoordinator: '999431675140382807',
|
||||
mediaCoordinator: '1204801056404676618',
|
||||
hrCoordinator: '1204795893480431657',
|
||||
outreachLeader: '999431675123597409',
|
||||
restricted: '999431675123597407',
|
||||
moderator: '999431675123597408',
|
||||
trialModerator: '999431675123597404',
|
||||
@@ -99,6 +100,7 @@ const devIDs = {
|
||||
},
|
||||
nonVegan: {
|
||||
general: '999431677325615189',
|
||||
vcText: '999431677535338567',
|
||||
},
|
||||
vegan: {
|
||||
general: '999431677535338575',
|
||||
@@ -132,6 +134,7 @@ const devIDs = {
|
||||
staff: '999431676058927253',
|
||||
modMail: '1095453371411996762',
|
||||
verification: '999431677006860409',
|
||||
activism: '999431677795389549',
|
||||
diversity: '999431679053660185',
|
||||
private: '999431679527628818',
|
||||
restricted: '999431679812845654',
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
*/
|
||||
import type { Guild, User } from 'discord.js';
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
import type { SusNotes } from '#utils/database/sus';
|
||||
import { RestrictionLogs } from '#utils/database/restriction';
|
||||
import { Warnings } from '#utils/database/warnings';
|
||||
import type { SusNotes } from '#utils/database/moderation/sus';
|
||||
import { RestrictionLogs } from '#utils/database/moderation/restriction';
|
||||
import { Warnings } from '#utils/database/moderation/warnings';
|
||||
|
||||
export function createSusLogEmbed(notes: SusNotes, user: User, guild: Guild) {
|
||||
const embed = new EmbedBuilder()
|
||||
|
||||
@@ -62,6 +62,7 @@ let IDs = {
|
||||
outreachCoordinator: '954804769476730890',
|
||||
mediaCoordinator: '1203778509449723914',
|
||||
hrCoordinator: '1203802120180989993',
|
||||
outreachLeader: '730915698544607232',
|
||||
restricted: '851624392928264222',
|
||||
moderator: '826157475815489598',
|
||||
trialModerator: '982074555596152904',
|
||||
@@ -101,6 +102,7 @@ let IDs = {
|
||||
},
|
||||
nonVegan: {
|
||||
general: '798967615636504657',
|
||||
vcText: '808191982169096232',
|
||||
},
|
||||
vegan: {
|
||||
general: '787738272616808509',
|
||||
@@ -134,6 +136,7 @@ let IDs = {
|
||||
staff: '768685283583328257',
|
||||
modMail: '867077297664426006',
|
||||
verification: '797505409073676299',
|
||||
activism: '873918877019545640',
|
||||
diversity: '933078380394459146',
|
||||
private: '992581296901599302',
|
||||
restricted: '809765577236283472',
|
||||
|
||||
Reference in New Issue
Block a user