From a7bda5bd27e1d4d578dce9cc690675246f661a9b Mon Sep 17 00:00:00 2001 From: Simplyalex99 Date: Thu, 19 Jun 2025 21:19:08 -0400 Subject: [PATCH 1/2] add: new channels --- src/constants/channels.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/constants/channels.ts b/src/constants/channels.ts index a55c99d4..bde6e428 100644 --- a/src/constants/channels.ts +++ b/src/constants/channels.ts @@ -4,7 +4,13 @@ import { guildId, isProd } from "../helpers/env.js"; const LOCAL_CHANNELS: Record = { helpReact: "926931785219207301", helpThreadsReact: "950790460857794620", + helpReactNative: "1166062952084942940", + helpStyling: "1166062952084942940", helpJs: "950790460857794620", + helpBackend: "1166062952084942940", + generalReact: "1166062952084942940", + jobsAdvice: "1166062952084942940", + generalTech: "1166062952084942940", random: "926931785219207301", gaming: "926931785219207301", thanks: "926931785219207301", @@ -25,7 +31,13 @@ const LOCAL_CHANNELS: Record = { const PRODUCTION_CHANNELS = { helpReact: "103696749012467712", helpThreadsReact: "902647189120118794", + helpReactNative: "469170673533583361", + helpStyling: "105765765117935616", helpJs: "565213527673929729", + helpBackend: "145170347921113088", + generalReact: "102860784329052160", + jobsAdvice: "287623405946011648", + generalTech: "547620660482932737", random: "103325358643752960", gaming: "509219336175747082", thanks: "798567961468076072", From de86ea477a90d23153bd1854981acf94d342bd4c Mon Sep 17 00:00:00 2001 From: Simplyalex99 Date: Thu, 19 Jun 2025 21:19:17 -0400 Subject: [PATCH 2/2] feat: job scanner --- src/features/job-scanner.ts | 77 +++++++++++++++++++++++++++++++++++++ src/index.ts | 14 ++++++- 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/features/job-scanner.ts diff --git a/src/features/job-scanner.ts b/src/features/job-scanner.ts new file mode 100644 index 00000000..951861fd --- /dev/null +++ b/src/features/job-scanner.ts @@ -0,0 +1,77 @@ +import type { ChannelHandlers } from "../types/index.js"; +import { EmbedType } from "discord.js"; + +import { CHANNELS } from "../constants/channels.js"; +import { EMBED_COLOR } from "./commands.js"; + +const jobKeywords = [ + "looking for work", + "seeking opportunities", + "available for hire", + "open to work", + "freelance available", + "seeking a role", + "looking for projects", + "hire me", + "job opportunities", + "job offer", + "job opportunity", + "contact me", + "actively seeking", + "available for freelance", + "remote position", + "dm me", + "reach out", + "ready to join", + "new opportunity", + "open position", + "seeking remote", + "available now", + "remote role", + "remote opportunity", + "full-time", + "job opportunities", + "opportunities available", + "new opportunity", + "open for", + "we’re hiring", + "we are hiring", +]; + +const currencyKeywords = ["₹", "€", "$"]; +const hasCodeBlockWithDollarSign = (content: string): boolean => { + const codeBlockRegex = /```[\s\S]*?\$[\s\S]*?```/g; + return codeBlockRegex.test(content); +}; + +export const jobScanner: ChannelHandlers = { + handleMessage: async ({ msg }) => { + if (msg.author.bot) return; + + const content = msg.content.toLowerCase(); + const ignoreDollar = hasCodeBlockWithDollarSign(content); + const hasCurrencyKeyword = + !ignoreDollar && + currencyKeywords.some((keyword) => content.includes(keyword)); + + const keywordRegex = new RegExp(`\\b(${jobKeywords.join("|")})\\b`, "i"); + const containsJobKeyword = keywordRegex.test(content); + if (!containsJobKeyword && !hasCurrencyKeyword) return; + + const warningMsg = `Oops <@${msg.author.id}>! This message looks more like a job/collaboration/advice post. Mind sharing that in <#${CHANNELS.jobsLog}> or <#${CHANNELS.lookingForGroup}> or <#${CHANNELS.jobsAdvice}> instead? If this was a mistake, please try again and ask your question. Appreciate you helping us keep channels on-topic.`; + const sentMsg = await msg.reply({ + embeds: [ + { + title: "Oops! Wrong Channel, Maybe?", + type: EmbedType.Rich, + description: warningMsg, + color: EMBED_COLOR, + }, + ], + }); + await msg.delete().catch(console.error); + setTimeout(() => { + sentMsg.delete().catch(console.error); + }, 300_000); + }, +}; diff --git a/src/index.ts b/src/index.ts index 3290b38c..5a556afa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -41,6 +41,7 @@ import { import { recommendBookCommand } from "./features/book-list.js"; import { mdnSearch } from "./features/mdn.js"; import "./server.js"; +import { jobScanner } from "./features/job-scanner.js"; export const bot = new Client({ intents: [ @@ -205,7 +206,18 @@ addHandler( ], promotionThread, ); - +addHandler( + [ + CHANNELS.helpReact, + CHANNELS.helpJs, + CHANNELS.helpReactNative, + CHANNELS.helpStyling, + CHANNELS.helpBackend, + CHANNELS.generalReact, + CHANNELS.generalTech, + ], + jobScanner, +); const threadChannels = [CHANNELS.helpJs, CHANNELS.helpThreadsReact]; addHandler(threadChannels, autothread);