This commit is contained in:
parent
c4247bf2a6
commit
99ebb9a578
@ -19,7 +19,16 @@ export default [
|
|||||||
eslint.configs.recommended,
|
eslint.configs.recommended,
|
||||||
tseslint.configs.recommended,
|
tseslint.configs.recommended,
|
||||||
{
|
{
|
||||||
files: ["./src/**/*.{ts,js}"]
|
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();
|
const client = new PrismaClient();
|
||||||
|
|
||||||
|
@ -167,4 +167,16 @@ describe("Match: REGEX", () => {
|
|||||||
runFilterTest(filter, testCases);
|
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 { Client, GatewayIntentBits } from "discord.js";
|
||||||
import EventHandler from "@bot/handlers/events";
|
import EventHandler from "@bot/handlers/events";
|
||||||
import InteractionHandler from "@bot/handlers/interactions";
|
import InteractionHandler from "@bot/handlers/interactions";
|
||||||
import { triggerTask } from "@bot/task";
|
|
||||||
|
|
||||||
export default class DiscordBot extends Client {
|
export default class DiscordBot extends Client {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { RESTPostAPIApplicationCommandsJSONBody, SlashCommandBuilder } from "discord.js";
|
import { RESTPostAPIApplicationCommandsJSONBody, SlashCommandBuilder, ToAPIApplicationCommandOptions } from "discord.js";
|
||||||
import DiscordBot from "@bot/bot";
|
import DiscordBot from "@bot/bot";
|
||||||
|
|
||||||
export default class Interaction {
|
export default class Interaction {
|
||||||
readonly client: DiscordBot;
|
readonly client: DiscordBot;
|
||||||
name!: string;
|
name!: string;
|
||||||
description: string = "No description";
|
description: string = "No description";
|
||||||
options: any[] = [];
|
options: ToAPIApplicationCommandOptions[] = [];
|
||||||
dmPermission!: boolean;
|
dmPermission!: boolean;
|
||||||
|
|
||||||
constructor(client: DiscordBot) {
|
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";
|
import { Filter, MatchingAlgorithms } from "../../generated/prisma";
|
||||||
|
|
||||||
function splitWords(filterValue: string): string[] {
|
function splitWords(filterValue: string): string[] {
|
||||||
@ -60,7 +60,16 @@ export const regex = (filter: Filter, input: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const fuzzy = (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) => {
|
export const mapAlgorithmToFunction = (filter: Filter, input: string) => {
|
||||||
|
@ -18,7 +18,8 @@ export default class EventHandler extends Collection<string, Event> {
|
|||||||
const modules = getAllFiles(eventsDirectory);
|
const modules = getAllFiles(eventsDirectory);
|
||||||
|
|
||||||
for (const module of modules) {
|
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);
|
const event: Event = new eventClass(this.client);
|
||||||
this.set(event.name, event);
|
this.set(event.name, event);
|
||||||
|
|
||||||
|
@ -18,7 +18,8 @@ export default class InteractionHandler extends Collection<string, Interaction>
|
|||||||
const modules = getAllFiles(interactionsDirectory);
|
const modules = getAllFiles(interactionsDirectory);
|
||||||
|
|
||||||
for (const module of modules) {
|
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);
|
const interaction: Interaction = new interactionClass(this.client);
|
||||||
this.set(interaction.name, interaction);
|
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 interactions = this.map(inter => inter.toJSON())
|
||||||
const rest = new REST({ version: "10" }).setToken(process.env.BOT_TOKEN!);
|
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(
|
rest.put(
|
||||||
Routes.applicationGuildCommands(process.env.CLIENT_ID!, guild.id),
|
Routes.applicationGuildCommands(process.env.CLIENT_ID!, guild.id),
|
||||||
{ body: interactions }
|
{ body: interactions }
|
||||||
|
@ -29,10 +29,13 @@ const processGuild = async (guild: Guild, client: Client) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getParsedUrl = async (url: string) => {
|
const getParsedUrl = async (url: string) => {
|
||||||
const parser = new RssParser();
|
try {
|
||||||
|
return new RssParser().parseURL(url)
|
||||||
try { return parser.parseURL(url) }
|
}
|
||||||
catch (error) { return undefined }
|
catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const processFeed = async (feed: ExpandedFeed, client: Client) => {
|
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)) {
|
for (const channelId of feed.channels.map(channel => channel.channel_id)) {
|
||||||
const channel = client.channels.cache.get(channelId);
|
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`);
|
console.log(`Processing ${items.length} items`);
|
||||||
|
|
||||||
for (let i = items.length; i--;) {
|
for (let i = items.length; i--;) {
|
||||||
|
@ -1,22 +1,29 @@
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { join } from "path";
|
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 getAllFiles = (directoryPath: string, existingResult?: string[]) => {
|
||||||
const fileNames = fs.readdirSync(directoryPath);
|
const fileNames = fs.readdirSync(directoryPath);
|
||||||
|
const result: string[] = existingResult ?? [];
|
||||||
let result: string[] = existingResult ?? [];
|
|
||||||
|
|
||||||
for (const fileName of fileNames) {
|
for (const fileName of fileNames) {
|
||||||
if (!(fileName.endsWith(".ts") || fileName.endsWith(".js"))) continue;
|
|
||||||
|
|
||||||
const fullPath = join(directoryPath, fileName);
|
const fullPath = join(directoryPath, fileName);
|
||||||
|
const stat = fs.statSync(fullPath);
|
||||||
|
|
||||||
fs.statSync(fullPath).isDirectory()
|
if (stat.isDirectory()) {
|
||||||
? result = getAllFiles(fullPath, result)
|
getAllFiles(fullPath, result);
|
||||||
: result.push(fullPath);
|
} else if (fileName.endsWith(".ts") || fileName.endsWith(".js")) {
|
||||||
|
result.push(fullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default getAllFiles;
|
export default getAllFiles;
|
@ -9,7 +9,7 @@ import "datatables.net-select-dt"
|
|||||||
import prisma from "../../../../../generated/prisma";
|
import prisma from "../../../../../generated/prisma";
|
||||||
|
|
||||||
declare let guildId: string;
|
declare let guildId: string;
|
||||||
declare let channels: Array<any>;
|
declare let channels: Array<TextChannel>;
|
||||||
|
|
||||||
// #region DataTable
|
// #region DataTable
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ const columnDefs: ConfigColumnDefs[] = [
|
|||||||
orderable: false,
|
orderable: false,
|
||||||
searchable: false,
|
searchable: false,
|
||||||
className: "size-px whitespace-nowrap",
|
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;
|
if (!row.message_style || type !== "display") return null;
|
||||||
|
|
||||||
const wrapper = $("<div>").addClass("flex px-6 py-4");
|
const wrapper = $("<div>").addClass("flex px-6 py-4");
|
||||||
@ -284,14 +284,23 @@ const onTableSelectChange = () => {
|
|||||||
$(".rows-selected-count-js").text(selectedRowsCount);
|
$(".rows-selected-count-js").text(selectedRowsCount);
|
||||||
|
|
||||||
const $elem = $(".rows-selected-count-js.zero-empty-js");
|
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() {
|
$("#selectAllBox").on("change", function() {
|
||||||
const dt: Api = (table as any).dataTable;
|
const dt: Api = (table as any).dataTable;
|
||||||
(this as HTMLInputElement).checked
|
|
||||||
? dt.rows().select()
|
if ((this as HTMLInputElement).checked) {
|
||||||
: dt.rows().deselect();
|
dt.rows().select();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt.rows().deselect();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#deleteRowsBtn").on("click", async () => {
|
$("#deleteRowsBtn").on("click", async () => {
|
||||||
@ -353,9 +362,12 @@ const openEditModal = async (id: number | undefined) => {
|
|||||||
$("#editForm").removeClass("submitted");
|
$("#editForm").removeClass("submitted");
|
||||||
editModal.open();
|
editModal.open();
|
||||||
|
|
||||||
id === undefined
|
if (id === undefined) {
|
||||||
? clearEditModalData()
|
clearEditModalData();
|
||||||
: loadEditModalData(id);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadEditModalData(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).on("click", ".open-edit-modal-js", async event => {
|
$(document).on("click", ".open-edit-modal-js", async event => {
|
||||||
@ -380,6 +392,7 @@ window.addEventListener("preline:ready", () => {
|
|||||||
interface ExpandedFeed extends prisma.Feed {
|
interface ExpandedFeed extends prisma.Feed {
|
||||||
channels: prisma.Channel[];
|
channels: prisma.Channel[];
|
||||||
filters: prisma.Feed[];
|
filters: prisma.Feed[];
|
||||||
|
message_style: prisma.MessageStyle | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearEditModalData = () => {
|
const clearEditModalData = () => {
|
||||||
@ -601,7 +614,7 @@ window.addEventListener("preline:ready", () => {
|
|||||||
styleSelect = new HSSelect(styleEl, styleSelectOptions);
|
styleSelect = new HSSelect(styleEl, styleSelectOptions);
|
||||||
|
|
||||||
// Add options to the channel select
|
// Add options to the channel select
|
||||||
channels.forEach((channel: TextChannel) => {
|
channels.forEach(channel => {
|
||||||
channelSelect.addOption({
|
channelSelect.addOption({
|
||||||
title: channel.name,
|
title: channel.name,
|
||||||
val: channel.id,
|
val: channel.id,
|
||||||
|
@ -212,16 +212,26 @@ const onTableSelectChange = () => {
|
|||||||
$(".rows-selected-count-js").text(selectedRowsCount);
|
$(".rows-selected-count-js").text(selectedRowsCount);
|
||||||
|
|
||||||
const $elem = $(".rows-selected-count-js.zero-empty-js");
|
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() {
|
$("#selectAllBox").on("change", function() {
|
||||||
const dt: Api = (table as any).dataTable;
|
const dt: Api = (table as any).dataTable;
|
||||||
(this as HTMLInputElement).checked
|
|
||||||
? dt.rows().select()
|
if ((this as HTMLInputElement).checked) {
|
||||||
: dt.rows().deselect();
|
dt.rows().select();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt.rows().deselect();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$("#deleteRowsBtn").on("click", async () => {
|
$("#deleteRowsBtn").on("click", async () => {
|
||||||
const dt: Api = (table as any).dataTable;
|
const dt: Api = (table as any).dataTable;
|
||||||
const rowsData = dt.rows({ selected: true }).data().toArray();
|
const rowsData = dt.rows({ selected: true }).data().toArray();
|
||||||
@ -279,9 +289,12 @@ const openEditModal = async (id: number | undefined) => {
|
|||||||
$("#editForm").removeClass("submitted");
|
$("#editForm").removeClass("submitted");
|
||||||
editModal.open();
|
editModal.open();
|
||||||
|
|
||||||
id === undefined
|
if (id === undefined) {
|
||||||
? clearEditModalData()
|
clearEditModalData();
|
||||||
: loadEditModalData(id);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadEditModalData(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).on("click", ".open-edit-modal-js", async event => {
|
$(document).on("click", ".open-edit-modal-js", async event => {
|
||||||
|
@ -304,16 +304,26 @@ const onTableSelectChange = () => {
|
|||||||
$(".rows-selected-count-js").text(selectedRowsCount);
|
$(".rows-selected-count-js").text(selectedRowsCount);
|
||||||
|
|
||||||
const $elem = $(".rows-selected-count-js.zero-empty-js");
|
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() {
|
$("#selectAllBox").on("change", function() {
|
||||||
const dt: Api = (table as any).dataTable;
|
const dt: Api = (table as any).dataTable;
|
||||||
(this as HTMLInputElement).checked
|
|
||||||
? dt.rows().select()
|
if ((this as HTMLInputElement).checked) {
|
||||||
: dt.rows().deselect();
|
dt.rows().select();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt.rows().deselect();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$("#deleteRowsBtn").on("click", async () => {
|
$("#deleteRowsBtn").on("click", async () => {
|
||||||
const dt: Api = (table as any).dataTable;
|
const dt: Api = (table as any).dataTable;
|
||||||
const rowsData = dt.rows({ selected: true }).data().toArray();
|
const rowsData = dt.rows({ selected: true }).data().toArray();
|
||||||
@ -373,9 +383,12 @@ const openEditModal = async (id: number | undefined) => {
|
|||||||
$("#editForm").removeClass("submitted");
|
$("#editForm").removeClass("submitted");
|
||||||
editModal.open();
|
editModal.open();
|
||||||
|
|
||||||
id === undefined
|
if (id === undefined) {
|
||||||
? clearEditModalData()
|
clearEditModalData();
|
||||||
: loadEditModalData(id);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadEditModalData(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).on("click", ".open-edit-modal-js", async event => {
|
$(document).on("click", ".open-edit-modal-js", async event => {
|
||||||
|
@ -7,7 +7,7 @@ export const logger = winston.createLogger({
|
|||||||
format: combine(
|
format: combine(
|
||||||
timestamp({ format: timestampFormat }),
|
timestamp({ format: timestampFormat }),
|
||||||
json(),
|
json(),
|
||||||
printf(({ timestamp, level, message, ...data }) => {
|
printf(({ _timestamp, level, message, ...data }) => {
|
||||||
const response = { level, message, data };
|
const response = { level, message, data };
|
||||||
return JSON.stringify(response);
|
return JSON.stringify(response);
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user