Compare commits

...

6 Commits

Author SHA1 Message Date
c088d7c4a5 Added new commands. getGroupStats and registerGroup.
All checks were successful
Main / build-and-push-docker-image (20.x) (push) Successful in 3m3s
2025-12-16 15:25:02 -05:00
66fb9cef85 Remove cache exchange 2025-12-16 15:24:34 -05:00
789803da59 Update imports and group info extraction from context. 2025-12-16 15:24:16 -05:00
8d8b7f4c3a Added new query 2025-12-16 15:23:24 -05:00
0177aae79a Update file name 2025-12-16 15:23:12 -05:00
8076b984f5 Update groupID type for mutations. 2025-12-16 15:23:04 -05:00
14 changed files with 201 additions and 30 deletions

View File

@@ -2,7 +2,7 @@ import { Composer } from "grammy";
import type { Context } from "#root/bot/context.js";
import { logHandle } from "#root/bot/helpers/logging.js";
import { urql } from "#root/main.js";
import increment from "#root/lib/graphql/mutations/incrimentMutation.js";
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
const composer = new Composer<Context>();

View File

@@ -4,7 +4,7 @@ import { logHandle } from "#root/bot/helpers/logging.js";
import metaLinkCheck from "#root/lib/metaLinkCheck.js";
import twitterLinkCheck from "#root/lib/twitterLinkCheck.js";
import { urql } from "#root/main.js";
import increment from "#root/lib/graphql/mutations/incrimentMutation.js";
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
import incrementGroup from "#root/lib/graphql/mutations/incrementGroupMutation.js";
@@ -22,9 +22,9 @@ feature.on("message::url", logHandle("embed-check"), async (ctx: Context) => {
await urql.mutation(increment, { trigger: true, mutationKey });
if (ctx.chat && ctx.msg) {
const groupName = ctx.chat?.title;
const groupID = ctx.chat?.id;
const groupUsername = ctx.chat?.username;
const groupName = ctx.chat?.title || "";
const groupID = ctx.chat?.id.toString() || "";
const groupUsername = ctx.chat?.username || "";
let deletedLinks = 0;
const username = ctx.msg.from?.username;

View File

@@ -0,0 +1,96 @@
import { Composer } from "grammy";
import type { Context } from "#root/bot/context.js";
import { logHandle } from "#root/bot/helpers/logging.js";
import { urql } from "#root/main.js";
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
import getGroupStats from "#root/lib/graphql/queries/getGroupStatsQuery.js";
const composer = new Composer<Context>();
const feature = composer.chatType(["group", "supergroup"]);
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
/**
* What triggers this feature and adds to the log when it has been triggered.
* The trigger is the command "/groupStats"
*/
feature.hears(
/^\/groupStats/,
logHandle("groups-stats-command"),
async (ctx: Context) => {
await urql.mutation(increment, { trigger: true, mutationKey });
// Checks if the context includes a message property.
if (ctx.msg && ctx.chat && ctx.msg.from) {
// Doesn't respond to regular users in groups. This is to prevent users spamming the command.
const chatMember = await ctx.getChatMember(ctx.msg.from.id);
if (!["creator", "administrator"].includes(chatMember.status)) {
return;
}
// Stringify the groupID
const groupID = ctx.chat?.id.toString() || "";
// Query to get group stats.
await urql
.query(getGroupStats, {
groupID
})
.toPromise()
.then(async res => {
// Replies to the message.
if (ctx.msg) {
// Check if the group has a document in the database and respond accordingly.
if (res.data.getGroupStats !== null) {
const { name, username, linksDeleted } = res.data.getGroupStats;
await ctx.reply(
`Your group is registered in the database as "${name}" ${
username.length
? `with a username of ${name}`
: `without a public username`
}\\.\n\nThe bot has successfully deleted ${linksDeleted} links from your group\\.`,
{
parse_mode: "MarkdownV2",
reply_parameters: { message_id: ctx.msg.message_id }
}
);
return await ctx.reply(
`If you need to update this information you can use the \\/registerGroup command\\.`,
{
parse_mode: "MarkdownV2",
reply_parameters: { message_id: ctx.msg.message_id }
}
);
}
// Default response //
await ctx.reply(
`Your group was not found in the database\\. You can use the \\/registerGroup command to add your group to the database\\.`,
{
parse_mode: "MarkdownV2",
reply_parameters: { message_id: ctx.msg.message_id }
}
);
return await ctx.reply(
`This is optional\\. If the bot ever removes a link in your group then the group information will be added to the database and tracked from then on\\.`,
{
parse_mode: "MarkdownV2",
reply_parameters: { message_id: ctx.msg.message_id }
}
);
}
return await urql
.mutation(increment, { command: true, mutationKey })
.toPromise();
});
}
}
);
export { composer as getGroupStats };

View File

@@ -2,7 +2,7 @@ import { Composer } from "grammy";
import type { Context } from "#root/bot/context.js";
import { logHandle } from "#root/bot/helpers/logging.js";
import { urql } from "#root/main.js";
import increment from "#root/lib/graphql/mutations/incrimentMutation.js";
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
const composer = new Composer<Context>();

View File

@@ -3,7 +3,7 @@ import type { Context } from "#root/bot/context.js";
import { logHandle } from "#root/bot/helpers/logging.js";
import { metaRegex } from "#root/lib/metaLinkCheck.js";
import { urql } from "#root/main.js";
import increment from "#root/lib/graphql/mutations/incrimentMutation.js";
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
import incrementGroup from "#root/lib/graphql/mutations/incrementGroupMutation.js";
@@ -32,16 +32,16 @@ feature.hears(
.mutation(increment, { link: true, mutationKey })
.toPromise()
.then(async () => {
if (ctx.msg) {
if (ctx.msg && ctx.chat) {
// Replies to the user informing them of the action.
await ctx.reply(
`@${username} Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
{ parse_mode: "MarkdownV2" }
);
const groupName = ctx.chat?.title;
const groupID = ctx.chat?.id;
const groupUsername = ctx.chat?.username;
const groupName = ctx.chat?.title || "";
const groupID = ctx.chat?.id.toString() || "";
const groupUsername = ctx.chat?.username || "";
return await urql
.mutation(addGroup, {

View File

@@ -0,0 +1,65 @@
import { Composer } from "grammy";
import type { Context } from "#root/bot/context.js";
import { logHandle } from "#root/bot/helpers/logging.js";
import { urql } from "#root/main.js";
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
const composer = new Composer<Context>();
const feature = composer.chatType(["group", "supergroup"]);
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
/**
* What triggers this feature and adds to the log when it has been triggered.
* The trigger is the command "/registerGroup"
*/
feature.hears(
/^\/registerGroup/,
logHandle("register-group-command"),
async (ctx: Context) => {
await urql.mutation(increment, { trigger: true, mutationKey });
// Checks if the context includes a message property.
if (ctx.msg && ctx.chat && ctx.msg.from) {
// Doesn't respond to regular users in groups. This is to prevent users spamming the command.
const chatMember = await ctx.getChatMember(ctx.msg.from.id);
if (!["creator", "administrator"].includes(chatMember.status)) {
return;
}
const groupName = ctx.chat?.title || "";
const groupID = ctx.chat?.id.toString() || ""; // Stringify the groupID
const groupUsername = ctx.chat?.username || "";
// Add or update the group
await urql
.mutation(addGroup, {
groupID,
groupName,
groupUsername,
mutationKey
})
.toPromise()
.then(async () => {
await urql
.mutation(increment, { command: true, mutationKey })
.toPromise();
if (ctx.msg) {
// Replies to the message.
return await ctx.reply(
`Your group has been successfully added to the database\\.`,
{
parse_mode: "MarkdownV2",
reply_parameters: { message_id: ctx.msg.message_id }
}
);
}
});
}
}
);
export { composer as registerGroup };

View File

@@ -3,7 +3,7 @@ import type { Context } from "#root/bot/context.js";
import { logHandle } from "#root/bot/helpers/logging.js";
import { twitterRegex } from "#root/lib/twitterLinkCheck.js";
import { urql } from "#root/main.js";
import increment from "#root/lib/graphql/mutations/incrimentMutation.js";
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
import incrementGroup from "#root/lib/graphql/mutations/incrementGroupMutation.js";
@@ -32,16 +32,16 @@ feature.hears(
.mutation(increment, { link: true, mutationKey })
.toPromise()
.then(async () => {
if (ctx.msg) {
if (ctx.msg && ctx.chat) {
// Replies to the user informing them of the action.
await ctx.reply(
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
{ parse_mode: "MarkdownV2" }
);
const groupName = ctx.chat?.title;
const groupID = ctx.chat?.id;
const groupUsername = ctx.chat?.username;
const groupName = ctx.chat?.title || "";
const groupID = ctx.chat?.id.toString() || "";
const groupUsername = ctx.chat?.username || "";
return await urql
.mutation(addGroup, {

View File

@@ -2,7 +2,7 @@ import { Composer } from "grammy";
import type { Context } from "#root/bot/context.js";
import { logHandle } from "#root/bot/helpers/logging.js";
import { urql } from "#root/main.js";
import increment from "#root/lib/graphql/mutations/incrimentMutation.js";
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
const composer = new Composer<Context>();

View File

@@ -18,6 +18,8 @@ import { metaBlacklist } from "./features/metaBlacklist.js";
import { botInfoCommand } from "./features/botInfoCommand.js";
import { helpCommand } from "./features/helpCommand.js";
import { embedCheck } from "./features/embedCheck.js";
import { registerGroup } from "./features/registerBotCommand.js";
import { getGroupStats } from "./features/getGroupStatsCommand.js";
interface Dependencies {
config: Config;
@@ -70,6 +72,8 @@ export function createBot(
// Commands
protectedBot.use(botInfoCommand);
protectedBot.use(helpCommand);
protectedBot.use(registerGroup);
protectedBot.use(getGroupStats);
// Blacklist Feature
protectedBot.use(twitterBlacklist);

View File

@@ -2,8 +2,8 @@ import { gql } from "@urql/core";
const addGroup = gql`
mutation addGroup(
$groupID: BigInt
$groupName: String
$groupID: String!
$groupName: String!
$groupUsername: String
$mutationKey: String
) {
@@ -13,12 +13,8 @@ const addGroup = gql`
groupUsername: $groupUsername
mutationKey: $mutationKey
) {
telegramID
name
username
linksDeleted
createdAt
updatedAt
}
}
`;

View File

@@ -2,8 +2,8 @@ import { gql } from "@urql/core";
const incrementGroup = gql`
mutation incrementGroup(
$groupID: BigInt
$linksDeleted: Int
$groupID: String!
$linksDeleted: Int!
$mutationKey: String
) {
incrementGroup(
@@ -11,12 +11,9 @@ const incrementGroup = gql`
linksDeleted: $linksDeleted
mutationKey: $mutationKey
) {
telegramID
name
username
linksDeleted
createdAt
updatedAt
}
}
`;

View File

@@ -0,0 +1,13 @@
import { gql } from "@urql/core";
const getGroupStats = gql`
query getGroupStats($groupID: String!) {
getGroupStats(groupID: $groupID) {
name
username
linksDeleted
}
}
`;
export default getGroupStats;

View File

@@ -8,7 +8,7 @@ import { config } from "#root/config.js";
import { logger } from "#root/logger.js";
import { createServer, createServerManager } from "#root/server/index.js";
import { run } from "@grammyjs/runner";
import { Client, cacheExchange, fetchExchange } from "@urql/core";
import { Client, fetchExchange } from "@urql/core";
async function startPolling(config: PollingConfig) {
const bot = createBot(config.botToken, {
@@ -116,7 +116,7 @@ function onShutdown(cleanUp: () => Promise<void>) {
export const urql = new Client({
url: process.env.GRAPHQL_URL || "",
exchanges: [cacheExchange, fetchExchange],
exchanges: [fetchExchange],
fetchOptions: {
headers: {
"x-api-key": process.env?.GRAPHQL_API_TOKEN || ""