Compare commits

..

3 commits

Author SHA1 Message Date
RenovateBot 4aa3d28bd0 Update dependency typeorm to v0.3.20
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2024-01-29 17:51:15 +00:00
Ethan Lane 56f0d105be Create button event to gain the server access role (#398)
All checks were successful
continuous-integration/drone/push Build is passing
# Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

- Add the ability for button event interactions to be created
- Added a button event interaction which gives a user the role which is specified in the config `verification.role`
- Added a command to generate a button to activate the verify button event

#232

## Type of change

Please delete options that are not relevant.

- [x] New feature (non-breaking change which adds functionality)

# How Has This Been Tested?

Please describe the tests that you ran to verify the changes. Provide instructions so we can reproduce. Please also list any relevant details to your test configuration.

# Checklist

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that provde my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream modules

Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/vylbot-app/pulls/398
Reviewed-by: VylpesTester <tester@vylpes.com>
Co-authored-by: Ethan Lane <ethan@vylpes.com>
Co-committed-by: Ethan Lane <ethan@vylpes.com>
2024-01-26 20:59:05 +00:00
RenovateBot f0ab3b9080 Update dependency np to v9 (#380)
All checks were successful
continuous-integration/drone/push Build is passing
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [np](https://github.com/sindresorhus/np) | devDependencies | major | [`^8.0.4` -> `^9.0.0`](https://renovatebot.com/diffs/npm/np/8.0.4/9.2.0) |

---

### Release Notes

<details>
<summary>sindresorhus/np (np)</summary>

### [`v9.2.0`](https://github.com/sindresorhus/np/releases/tag/v9.2.0)

[Compare Source](https://github.com/sindresorhus/np/compare/v9.1.0...v9.2.0)

-   Fix yarn npm publish for scoped packages  [`8d3a984`](https://github.com/sindresorhus/np/commit/8d3a984)
-   Fix broken revert code after publish failure  [`819ed29`](https://github.com/sindresorhus/np/commit/819ed29)

### [`v9.1.0`](https://github.com/sindresorhus/np/releases/tag/v9.1.0)

[Compare Source](https://github.com/sindresorhus/np/compare/v9.0.0...v9.1.0)

-   Add Yarn Berry support ([#&#8203;723](https://github.com/sindresorhus/np/issues/723))  [`0d9522b`](https://github.com/sindresorhus/np/commit/0d9522b)

### [`v9.0.0`](https://github.com/sindresorhus/np/releases/tag/v9.0.0)

[Compare Source](https://github.com/sindresorhus/np/compare/v8.0.4...v9.0.0)

##### Breaking

-   Require Node.js 18 and npm 9  [`6c2e00e`](https://github.com/sindresorhus/np/commit/6c2e00e)

##### Improvements

-   Group unpublished files in folders ([#&#8203;716](https://github.com/sindresorhus/np/issues/716))  [`c31c2bc`](https://github.com/sindresorhus/np/commit/c31c2bc)
-   improve messages related to new files and dependencies ([#&#8203;702](https://github.com/sindresorhus/np/issues/702))  [`ad7b09e`](https://github.com/sindresorhus/np/commit/ad7b09e)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4wLjAiLCJ1cGRhdGVkSW5WZXIiOiIzNy4wLjAiLCJ0YXJnZXRCcmFuY2giOiJkZXZlbG9wIn0=-->

Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/vylbot-app/pulls/380
Reviewed-by: Vylpes <ethan@vylpes.com>
Co-authored-by: Renovate Bot <renovate@vylpes.com>
Co-committed-by: Renovate Bot <renovate@vylpes.com>
2024-01-22 17:25:55 +00:00
13 changed files with 490 additions and 342 deletions

View file

@ -38,14 +38,14 @@
"mysql": "^2.18.1",
"random-bunny": "^2.0.5",
"ts-jest": "^29.0.0",
"typeorm": "0.3.19"
"typeorm": "0.3.20"
},
"resolutions": {
"**/semver": "^7.5.2"
},
"devDependencies": {
"@types/node": "^20.0.0",
"np": "^8.0.4",
"np": "^9.0.0",
"typescript": "^5.0.0"
}
}

View file

@ -0,0 +1,42 @@
import { ButtonInteraction, CacheType } from "discord.js";
import { ButtonEvent } from "../type/buttonEvent";
import SettingsHelper from "../helpers/SettingsHelper";
export default class Verify extends ButtonEvent {
public override async execute(interaction: ButtonInteraction<CacheType>) {
if (!interaction.guildId || !interaction.guild) return;
const roleName = await SettingsHelper.GetSetting("verification.role", interaction.guildId);
if (!roleName) return;
const role = interaction.guild.roles.cache.find(x => x.name == roleName);
if (!role) {
await interaction.reply({
content: `Unable to find the role, ${roleName}`,
ephemeral: true,
});
return;
}
const member = interaction.guild.members.cache.find(x => x.id == interaction.user.id);
if (!member || !member.manageable) {
await interaction.reply({
content: "Unable to give role to user",
ephemeral: true,
});
return;
}
await member.roles.add(role);
await interaction.reply({
content: "Given role",
ephemeral: true,
});
}
}

View file

@ -9,10 +9,13 @@ import { Command } from "../type/command";
import { Events } from "./events";
import { Util } from "./util";
import AppDataSource from "../database/dataSources/appDataSource";
import ButtonEventItem from "../contracts/ButtonEventItem";
import { ButtonEvent } from "../type/buttonEvent";
export class CoreClient extends Client {
private static _commandItems: ICommandItem[];
private static _eventItems: IEventItem[];
private static _buttonEvents: ButtonEventItem[];
private _events: Events;
private _util: Util;
@ -25,12 +28,17 @@ export class CoreClient extends Client {
return this._eventItems;
}
public static get buttonEvents(): ButtonEventItem[] {
return this._buttonEvents;
}
constructor(intents: number[], partials: Partials[]) {
super({ intents: intents, partials: partials });
dotenv.config();
CoreClient._commandItems = [];
CoreClient._eventItems = [];
CoreClient._buttonEvents = [];
this._events = new Events();
this._util = new Util();
@ -73,4 +81,13 @@ export class CoreClient extends Client {
CoreClient._eventItems.push(item);
}
public static RegisterButtonEvent(buttonId: string, event: ButtonEvent) {
const item: ButtonEventItem = {
ButtonId: buttonId,
Event: event,
};
CoreClient._buttonEvents.push(item);
}
}

View file

@ -1,40 +1,18 @@
import { Interaction } from "discord.js";
import ICommandItem from "../contracts/ICommandItem";
import SettingsHelper from "../helpers/SettingsHelper";
import { CoreClient } from "./client";
import ChatInputCommand from "./interactionCreate/chatInputCommand";
import Button from "./interactionCreate/button";
export class Events {
public async onInteractionCreate(interaction: Interaction) {
if (!interaction.isChatInputCommand()) return;
if (!interaction.guildId) return;
const disabledCommandsString = await SettingsHelper.GetSetting("commands.disabled", interaction.guildId);
const disabledCommands = disabledCommandsString?.split(",");
const disabledCommandsMessage = await SettingsHelper.GetSetting("commands.disabled.message", interaction.guildId);
if (disabledCommands?.find(x => x == interaction.commandName)) {
await interaction.reply(disabledCommandsMessage || "This command is disabled.");
return;
if (interaction.isChatInputCommand()) {
ChatInputCommand.onChatInput(interaction);
}
const item = CoreClient.commandItems.find(x => x.Name == interaction.commandName && !x.ServerId);
const itemForServer = CoreClient.commandItems.find(x => x.Name == interaction.commandName && x.ServerId == interaction.guildId);
let itemToUse: ICommandItem;
if (!itemForServer) {
if (!item) {
await interaction.reply('Command not found');
return;
}
itemToUse = item;
} else {
itemToUse = itemForServer;
if (interaction.isButton()) {
Button.onButtonClicked(interaction);
}
itemToUse.Command.execute(interaction);
}
// Emit when bot is logged in and ready to use

View file

@ -0,0 +1,17 @@
import { ButtonInteraction } from "discord.js";
import { CoreClient } from "../client";
export default class Button {
public static async onButtonClicked(interaction: ButtonInteraction) {
if (!interaction.isButton) return;
const item = CoreClient.buttonEvents.find(x => x.ButtonId == interaction.customId.split(" ")[0]);
if (!item) {
await interaction.reply("Event not found.");
return;
}
item.Event.execute(interaction);
}
}

View file

@ -0,0 +1,27 @@
import { Interaction } from "discord.js";
import { CoreClient } from "../client";
import ICommandItem from "../../contracts/ICommandItem";
export default class ChatInputCommand {
public static async onChatInput(interaction: Interaction) {
if (!interaction.isChatInputCommand()) return;
const item = CoreClient.commandItems.find(x => x.Name == interaction.commandName && !x.ServerId);
const itemForServer = CoreClient.commandItems.find(x => x.Name == interaction.commandName && x.ServerId == interaction.guildId);
let itemToUse: ICommandItem;
if (!itemForServer) {
if (!item) {
await interaction.reply("Command not found.");
return;
}
itemToUse = item;
} else {
itemToUse = itemForServer;
}
itemToUse.Command.execute(interaction);
}
}

View file

@ -1,7 +1,8 @@
import { CommandInteraction, EmbedBuilder, PermissionsBitField, SlashCommandBuilder } from "discord.js";
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, EmbedBuilder, PermissionsBitField, SlashCommandBuilder } from "discord.js";
import { existsSync, readFileSync } from "fs";
import EmbedColours from "../constants/EmbedColours";
import { Command } from "../type/command";
import SettingsHelper from "../helpers/SettingsHelper";
interface IRules {
title?: string;
@ -14,13 +15,36 @@ export default class Rules extends Command {
constructor() {
super();
super.CommandBuilder = new SlashCommandBuilder()
.setName("rules")
.setDescription("Send the rules embeds for this server")
.setDefaultMemberPermissions(PermissionsBitField.Flags.Administrator);
this.CommandBuilder = new SlashCommandBuilder()
.setName('rules')
.setDescription("Rules-related commands")
.setDefaultMemberPermissions(PermissionsBitField.Flags.Administrator)
.addSubcommand(x =>
x
.setName('embeds')
.setDescription('Send the rules embeds for this server'))
.addSubcommand(x =>
x
.setName('access')
.setDescription('Send the server verification embed button'));
}
public override async execute(interaction: CommandInteraction) {
if (!interaction.isChatInputCommand()) return;
switch (interaction.options.getSubcommand()) {
case "embeds":
await this.SendEmbeds(interaction);
break;
case "access":
await this.SendAccessButton(interaction);
break;
default:
await interaction.reply("Subcommand doesn't exist.");
}
}
private async SendEmbeds(interaction: CommandInteraction) {
if (!interaction.guildId) return;
if (!existsSync(`${process.cwd()}/data/rules/${interaction.guildId}.json`)) {
@ -71,4 +95,27 @@ export default class Rules extends Command {
await interaction.reply({ embeds: [ successEmbed ], ephemeral: true });
}
private async SendAccessButton(interaction: CommandInteraction) {
if (!interaction.guildId) return;
const buttonLabel = await SettingsHelper.GetSetting("rules.access.label", interaction.guildId);
const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents([
new ButtonBuilder()
.setCustomId('verify')
.setStyle(ButtonStyle.Primary)
.setLabel(buttonLabel || "Verify")
]);
await interaction.channel?.send({
components: [ row ]
});
await interaction.reply({
content: "Success",
ephemeral: true,
});
}
}

View file

@ -31,6 +31,7 @@ export default class DefaultValues {
// Rules (Command)
this.values.push({ Key: "rules.file", Value: "data/rules/rules" });
this.values.push({ Key: "rules.access.label", Value: "Verify" });
// Channels
this.values.push({ Key: "channels.logs.message", Value: "message-logs" });

View file

@ -0,0 +1,8 @@
import { ButtonEvent } from "../type/buttonEvent";
interface ButtonEventItem {
ButtonId: string,
Event: ButtonEvent,
}
export default ButtonEventItem;

View file

@ -37,6 +37,9 @@ import MessageDelete from "./events/MessageEvents/MessageDelete";
import MessageUpdate from "./events/MessageEvents/MessageUpdate";
import MessageCreate from "./events/MessageEvents/MessageCreate";
// Button Event Imports
import Verify from "./buttonEvents/verify";
export default class Registry {
public static RegisterCommands() {
CoreClient.RegisterCommand("about", new About());
@ -84,4 +87,8 @@ export default class Registry {
CoreClient.RegisterEvent(EventType.MessageUpdate, MessageUpdate);
CoreClient.RegisterEvent(EventType.MessageCreate, MessageCreate);
}
public static RegisterButtonEvents() {
CoreClient.RegisterButtonEvent("verify", new Verify());
}
}

5
src/type/buttonEvent.ts Normal file
View file

@ -0,0 +1,5 @@
import { ButtonInteraction } from "discord.js";
export abstract class ButtonEvent {
abstract execute(interaction: ButtonInteraction): Promise<void>;
}

View file

@ -37,5 +37,6 @@ const client = new CoreClient([
registry.RegisterCommands();
registry.RegisterEvents();
registry.RegisterButtonEvents();
client.start();

612
yarn.lock

File diff suppressed because it is too large Load diff