This commit is contained in:
parent
c4247bf2a6
commit
99ebb9a578
@ -4,22 +4,31 @@ import eslint from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: [
|
||||
"./dist/**/*",
|
||||
"./src/**/generated/**/*",
|
||||
"./generated/**/*",
|
||||
"esbuild.mjs",
|
||||
"jest.config.js",
|
||||
"postcss.config.js",
|
||||
"tailwind.config.js",
|
||||
]
|
||||
},
|
||||
...tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
{
|
||||
files: ["./src/**/*.{ts,js}"]
|
||||
}
|
||||
)
|
||||
ignores: [
|
||||
"./dist/**/*",
|
||||
"./src/**/generated/**/*",
|
||||
"./generated/**/*",
|
||||
"esbuild.mjs",
|
||||
"jest.config.js",
|
||||
"postcss.config.js",
|
||||
"tailwind.config.js",
|
||||
]
|
||||
},
|
||||
...tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
{
|
||||
files: ["./src/**/*.{ts,js}"],
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error", {
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_"
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off"
|
||||
}
|
||||
}
|
||||
)
|
||||
];
|
@ -1,4 +1,4 @@
|
||||
import Prisma, { PrismaClient } from "../generated/prisma";
|
||||
import { PrismaClient } from "../generated/prisma";
|
||||
|
||||
const client = new PrismaClient();
|
||||
|
||||
|
@ -167,4 +167,16 @@ describe("Match: REGEX", () => {
|
||||
runFilterTest(filter, testCases);
|
||||
});
|
||||
|
||||
describe("Match: FUZZY", () => { });
|
||||
describe("Match: FUZZY", () => {
|
||||
const filter: prisma.Filter = {
|
||||
...templateFilter,
|
||||
name: "",
|
||||
value: String.raw``,
|
||||
matching_algorithm: MatchingAlgorithms.REGEX,
|
||||
is_insensitive: true
|
||||
};
|
||||
|
||||
const testCases: FilterTestCase[] = [];
|
||||
|
||||
runFilterTest(filter, testCases);
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Client, GatewayIntentBits } from "discord.js";
|
||||
import EventHandler from "@bot/handlers/events";
|
||||
import InteractionHandler from "@bot/handlers/interactions";
|
||||
import { triggerTask } from "@bot/task";
|
||||
|
||||
export default class DiscordBot extends Client {
|
||||
constructor() {
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { RESTPostAPIApplicationCommandsJSONBody, SlashCommandBuilder } from "discord.js";
|
||||
import { RESTPostAPIApplicationCommandsJSONBody, SlashCommandBuilder, ToAPIApplicationCommandOptions } from "discord.js";
|
||||
import DiscordBot from "@bot/bot";
|
||||
|
||||
export default class Interaction {
|
||||
readonly client: DiscordBot;
|
||||
name!: string;
|
||||
description: string = "No description";
|
||||
options: any[] = [];
|
||||
options: ToAPIApplicationCommandOptions[] = [];
|
||||
dmPermission!: boolean;
|
||||
|
||||
constructor(client: DiscordBot) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import fuzz from "fuzzball"; // todo: implement for fuzzy match
|
||||
import fuzz from "fuzzball";
|
||||
import { Filter, MatchingAlgorithms } from "../../generated/prisma";
|
||||
|
||||
function splitWords(filterValue: string): string[] {
|
||||
@ -60,7 +60,16 @@ export const regex = (filter: Filter, input: string) => {
|
||||
};
|
||||
|
||||
export const fuzzy = (filter: Filter, input: string) => {
|
||||
throw new Error("'fuzzy' filter not implemented");
|
||||
let filterValue = filter.value.replace(/[^\w\s]/g, "");
|
||||
let inputValue = input.replace(/[^\w\s]/g, "");
|
||||
|
||||
if (filter.is_insensitive) {
|
||||
filterValue = filterValue.toLowerCase();
|
||||
inputValue = inputValue.toLowerCase();
|
||||
}
|
||||
|
||||
const ratio = fuzz.partial_ratio(filterValue, inputValue);
|
||||
return ratio > 90;
|
||||
};
|
||||
|
||||
export const mapAlgorithmToFunction = (filter: Filter, input: string) => {
|
||||
|
@ -18,7 +18,8 @@ export default class EventHandler extends Collection<string, Event> {
|
||||
const modules = getAllFiles(eventsDirectory);
|
||||
|
||||
for (const module of modules) {
|
||||
const eventClass = ((r) => r.default || r)(require(module));
|
||||
const imported = await import(module);
|
||||
const eventClass = imported.default || imported;
|
||||
const event: Event = new eventClass(this.client);
|
||||
this.set(event.name, event);
|
||||
|
||||
|
@ -18,7 +18,8 @@ export default class InteractionHandler extends Collection<string, Interaction>
|
||||
const modules = getAllFiles(interactionsDirectory);
|
||||
|
||||
for (const module of modules) {
|
||||
const interactionClass = ((r) => r.default || r)(require(module))
|
||||
const imported = await import(module);
|
||||
const interactionClass = imported.default || imported;
|
||||
const interaction: Interaction = new interactionClass(this.client);
|
||||
this.set(interaction.name, interaction);
|
||||
}
|
||||
@ -28,7 +29,7 @@ export default class InteractionHandler extends Collection<string, Interaction>
|
||||
const interactions = this.map(inter => inter.toJSON())
|
||||
const rest = new REST({ version: "10" }).setToken(process.env.BOT_TOKEN!);
|
||||
|
||||
for (const [_, guild] of this.client.guilds.cache) {
|
||||
for (const guild of this.client.guilds.cache.values()) {
|
||||
rest.put(
|
||||
Routes.applicationGuildCommands(process.env.CLIENT_ID!, guild.id),
|
||||
{ body: interactions }
|
||||
|
@ -29,10 +29,13 @@ const processGuild = async (guild: Guild, client: Client) => {
|
||||
};
|
||||
|
||||
const getParsedUrl = async (url: string) => {
|
||||
const parser = new RssParser();
|
||||
|
||||
try { return parser.parseURL(url) }
|
||||
catch (error) { return undefined }
|
||||
try {
|
||||
return new RssParser().parseURL(url)
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return undefined
|
||||
}
|
||||
};
|
||||
|
||||
const processFeed = async (feed: ExpandedFeed, client: Client) => {
|
||||
@ -43,11 +46,11 @@ const processFeed = async (feed: ExpandedFeed, client: Client) => {
|
||||
|
||||
for (const channelId of feed.channels.map(channel => channel.channel_id)) {
|
||||
const channel = client.channels.cache.get(channelId);
|
||||
if (channel) await processItems(parsed.items, feed, channel, client);
|
||||
if (channel) await processItems(parsed.items, feed, channel);
|
||||
}
|
||||
};
|
||||
|
||||
const processItems = async (items: RssParser.Item[], feed: ExpandedFeed, channel: DiscordChannel, client: Client) => {
|
||||
const processItems = async (items: RssParser.Item[], feed: ExpandedFeed, channel: DiscordChannel) => {
|
||||
console.log(`Processing ${items.length} items`);
|
||||
|
||||
for (let i = items.length; i--;) {
|
||||
|
@ -1,22 +1,29 @@
|
||||
import fs from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
/**
|
||||
* Recursively gets all .ts or .js files in a directory and its subdirectories.
|
||||
* @param directoryPath - The directory to start from.
|
||||
* @param existingResult - Optional array to accumulate results.
|
||||
* @returns A list of full paths to .ts or .js files.
|
||||
*/
|
||||
const getAllFiles = (directoryPath: string, existingResult?: string[]) => {
|
||||
const fileNames = fs.readdirSync(directoryPath);
|
||||
|
||||
let result: string[] = existingResult ?? [];
|
||||
const result: string[] = existingResult ?? [];
|
||||
|
||||
for (const fileName of fileNames) {
|
||||
if (!(fileName.endsWith(".ts") || fileName.endsWith(".js"))) continue;
|
||||
|
||||
const fullPath = join(directoryPath, fileName);
|
||||
const stat = fs.statSync(fullPath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
getAllFiles(fullPath, result);
|
||||
} else if (fileName.endsWith(".ts") || fileName.endsWith(".js")) {
|
||||
result.push(fullPath);
|
||||
}
|
||||
|
||||
fs.statSync(fullPath).isDirectory()
|
||||
? result = getAllFiles(fullPath, result)
|
||||
: result.push(fullPath);
|
||||
}
|
||||
|
||||
return result
|
||||
return result;
|
||||
};
|
||||
|
||||
export default getAllFiles;
|
@ -9,7 +9,7 @@ import "datatables.net-select-dt"
|
||||
import prisma from "../../../../../generated/prisma";
|
||||
|
||||
declare let guildId: string;
|
||||
declare let channels: Array<any>;
|
||||
declare let channels: Array<TextChannel>;
|
||||
|
||||
// #region DataTable
|
||||
|
||||
@ -174,7 +174,7 @@ const columnDefs: ConfigColumnDefs[] = [
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
className: "size-px whitespace-nowrap",
|
||||
render: (_data: unknown, type: string, row: any) => {
|
||||
render: (_data: unknown, type: string, row: ExpandedFeed) => {
|
||||
if (!row.message_style || type !== "display") return null;
|
||||
|
||||
const wrapper = $("<div>").addClass("flex px-6 py-4");
|
||||
@ -284,14 +284,23 @@ const onTableSelectChange = () => {
|
||||
$(".rows-selected-count-js").text(selectedRowsCount);
|
||||
|
||||
const $elem = $(".rows-selected-count-js.zero-empty-js");
|
||||
selectedRowsCount === 0 ? $elem.hide() : $elem.show();
|
||||
if (selectedRowsCount === 0) {
|
||||
$elem.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$elem.show();
|
||||
};
|
||||
|
||||
$("#selectAllBox").on("change", function() {
|
||||
const dt: Api = (table as any).dataTable;
|
||||
(this as HTMLInputElement).checked
|
||||
? dt.rows().select()
|
||||
: dt.rows().deselect();
|
||||
|
||||
if ((this as HTMLInputElement).checked) {
|
||||
dt.rows().select();
|
||||
return;
|
||||
}
|
||||
|
||||
dt.rows().deselect();
|
||||
});
|
||||
|
||||
$("#deleteRowsBtn").on("click", async () => {
|
||||
@ -353,9 +362,12 @@ const openEditModal = async (id: number | undefined) => {
|
||||
$("#editForm").removeClass("submitted");
|
||||
editModal.open();
|
||||
|
||||
id === undefined
|
||||
? clearEditModalData()
|
||||
: loadEditModalData(id);
|
||||
if (id === undefined) {
|
||||
clearEditModalData();
|
||||
return;
|
||||
}
|
||||
|
||||
loadEditModalData(id);
|
||||
};
|
||||
|
||||
$(document).on("click", ".open-edit-modal-js", async event => {
|
||||
@ -380,6 +392,7 @@ window.addEventListener("preline:ready", () => {
|
||||
interface ExpandedFeed extends prisma.Feed {
|
||||
channels: prisma.Channel[];
|
||||
filters: prisma.Feed[];
|
||||
message_style: prisma.MessageStyle | undefined;
|
||||
}
|
||||
|
||||
const clearEditModalData = () => {
|
||||
@ -601,7 +614,7 @@ window.addEventListener("preline:ready", () => {
|
||||
styleSelect = new HSSelect(styleEl, styleSelectOptions);
|
||||
|
||||
// Add options to the channel select
|
||||
channels.forEach((channel: TextChannel) => {
|
||||
channels.forEach(channel => {
|
||||
channelSelect.addOption({
|
||||
title: channel.name,
|
||||
val: channel.id,
|
||||
|
@ -212,16 +212,26 @@ const onTableSelectChange = () => {
|
||||
$(".rows-selected-count-js").text(selectedRowsCount);
|
||||
|
||||
const $elem = $(".rows-selected-count-js.zero-empty-js");
|
||||
selectedRowsCount === 0 ? $elem.hide() : $elem.show();
|
||||
if (selectedRowsCount === 0) {
|
||||
$elem.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$elem.show();
|
||||
};
|
||||
|
||||
$("#selectAllBox").on("change", function() {
|
||||
const dt: Api = (table as any).dataTable;
|
||||
(this as HTMLInputElement).checked
|
||||
? dt.rows().select()
|
||||
: dt.rows().deselect();
|
||||
|
||||
if ((this as HTMLInputElement).checked) {
|
||||
dt.rows().select();
|
||||
return;
|
||||
}
|
||||
|
||||
dt.rows().deselect();
|
||||
});
|
||||
|
||||
|
||||
$("#deleteRowsBtn").on("click", async () => {
|
||||
const dt: Api = (table as any).dataTable;
|
||||
const rowsData = dt.rows({ selected: true }).data().toArray();
|
||||
@ -279,9 +289,12 @@ const openEditModal = async (id: number | undefined) => {
|
||||
$("#editForm").removeClass("submitted");
|
||||
editModal.open();
|
||||
|
||||
id === undefined
|
||||
? clearEditModalData()
|
||||
: loadEditModalData(id);
|
||||
if (id === undefined) {
|
||||
clearEditModalData();
|
||||
return;
|
||||
}
|
||||
|
||||
loadEditModalData(id);
|
||||
};
|
||||
|
||||
$(document).on("click", ".open-edit-modal-js", async event => {
|
||||
|
@ -304,16 +304,26 @@ const onTableSelectChange = () => {
|
||||
$(".rows-selected-count-js").text(selectedRowsCount);
|
||||
|
||||
const $elem = $(".rows-selected-count-js.zero-empty-js");
|
||||
selectedRowsCount === 0 ? $elem.hide() : $elem.show();
|
||||
if (selectedRowsCount === 0) {
|
||||
$elem.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$elem.show();
|
||||
};
|
||||
|
||||
$("#selectAllBox").on("change", function() {
|
||||
const dt: Api = (table as any).dataTable;
|
||||
(this as HTMLInputElement).checked
|
||||
? dt.rows().select()
|
||||
: dt.rows().deselect();
|
||||
|
||||
if ((this as HTMLInputElement).checked) {
|
||||
dt.rows().select();
|
||||
return;
|
||||
}
|
||||
|
||||
dt.rows().deselect();
|
||||
});
|
||||
|
||||
|
||||
$("#deleteRowsBtn").on("click", async () => {
|
||||
const dt: Api = (table as any).dataTable;
|
||||
const rowsData = dt.rows({ selected: true }).data().toArray();
|
||||
@ -373,9 +383,12 @@ const openEditModal = async (id: number | undefined) => {
|
||||
$("#editForm").removeClass("submitted");
|
||||
editModal.open();
|
||||
|
||||
id === undefined
|
||||
? clearEditModalData()
|
||||
: loadEditModalData(id);
|
||||
if (id === undefined) {
|
||||
clearEditModalData();
|
||||
return;
|
||||
}
|
||||
|
||||
loadEditModalData(id);
|
||||
};
|
||||
|
||||
$(document).on("click", ".open-edit-modal-js", async event => {
|
||||
|
@ -7,7 +7,7 @@ export const logger = winston.createLogger({
|
||||
format: combine(
|
||||
timestamp({ format: timestampFormat }),
|
||||
json(),
|
||||
printf(({ timestamp, level, message, ...data }) => {
|
||||
printf(({ _timestamp, level, message, ...data }) => {
|
||||
const response = { level, message, data };
|
||||
return JSON.stringify(response);
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user