Compare commits

..

8 Commits

Author SHA1 Message Date
1baf37ae41 upgrade dependencies
All checks were successful
Main / build-and-push-docker-image (20.x) (push) Successful in 4m34s
Daily Cron (Make New DailyStats Document) / cron (push) Successful in 2s
2026-01-27 11:47:42 -05:00
efa258fdde Update stats description
All checks were successful
Main / build-and-push-docker-image (20.x) (push) Successful in 4m49s
2026-01-27 10:11:00 -05:00
cab2eaa22c Update bot tagline.
All checks were successful
Main / build-and-push-docker-image (20.x) (push) Successful in 5m4s
Daily Cron (Make New DailyStats Document) / cron (push) Successful in 3s
2026-01-26 23:00:27 -05:00
49a74cf4df Updated the increment mutation to take a number instead of a boolean. For instances when more than 1 group is detected. Like when parsing embeds and captions.
All checks were successful
Main / build-and-push-docker-image (20.x) (push) Successful in 5m1s
2026-01-26 21:28:41 -05:00
e0a99cc455 added command list to site
All checks were successful
Main / build-and-push-docker-image (20.x) (push) Successful in 5m11s
2026-01-26 20:38:55 -05:00
1214b7e98a Update commands description. 2026-01-26 19:35:39 -05:00
369b3bf133 Added api route to retrieve bot commands list. 2026-01-26 18:15:50 -05:00
d15eab2421 Added command list. 2026-01-26 15:24:27 -05:00
10 changed files with 1725 additions and 1927 deletions

View File

@@ -12,23 +12,23 @@
"prisma-update": "yarn prisma db push"
},
"dependencies": {
"@chakra-ui/charts": "^3.30.0",
"@chakra-ui/react": "^3.30.0",
"@chakra-ui/charts": "^3.31.0",
"@chakra-ui/react": "^3.31.0",
"@emotion/react": "^11.14.0",
"@escape.tech/graphql-armor": "^3.2.0",
"@prisma/client": "^6.19.0",
"@prisma/extension-accelerate": "^2.0.2",
"@prisma/client": "^6.19.2",
"@prisma/extension-accelerate": "^3.0.1",
"@urql/next": "^2.0.0",
"dotenv": "^17.2.3",
"graphql": "^16.12.0",
"graphql-scalars": "^1.25.0",
"graphql-yoga": "^5.18.0",
"next": "16.1.1",
"next": "16.1.5",
"next-themes": "^0.4.6",
"react": "19.2.3",
"react-dom": "19.2.3",
"react": "19.2.4",
"react-dom": "19.2.4",
"react-icons": "^5.5.0",
"recharts": "^3.6.0",
"recharts": "^3.7.0",
"rxjs": "^7.8.2",
"urql": "^5.0.1"
},
@@ -36,23 +36,24 @@
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@iconify/react": "^6.0.2",
"@types/node": "^24.10.4",
"@types/react": "^19.2.7",
"@types/node": "^25.0.10",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@typescript-eslint/eslint-plugin": "^8.51.0",
"@typescript-eslint/parser": "^8.51.0",
"@typescript-eslint/eslint-plugin": "^8.54.0",
"@typescript-eslint/parser": "^8.54.0",
"baseline-browser-mapping": "^2.9.18",
"eslint": "^9.39.2",
"eslint-config-next": "16.1.1",
"eslint-config-next": "16.1.5",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1",
"prettier": "3.7.4",
"prisma": "^6.19.0",
"prettier": "3.8.1",
"prisma": "^6.19.2",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.51.0"
"typescript-eslint": "^8.54.0"
},
"packageManager": "yarn@4.12.0"
}

View File

@@ -0,0 +1,57 @@
import { JSX } from "react";
import { Checkmark, Heading, Table, VStack } from "@chakra-ui/react";
import botCommands from "@/data/botCommands";
const CommandsListTable = (): JSX.Element => {
return (
<VStack gap={6} w={{ base: "90%", md: "100%" }}>
<Heading as="h3" fontSize="3xl">
{"Bot Commands"}
</Heading>
<Table.Root maxW="fit-content" interactive showColumnBorder>
<Table.Caption>
{"The bot will only respond to admins and moderators within groups."}
</Table.Caption>
<Table.Header>
<Table.Row bg="cyan.emphasized">
<Table.ColumnHeader> {"Command"}</Table.ColumnHeader>
<Table.ColumnHeader> {"Description"}</Table.ColumnHeader>
<Table.ColumnHeader> {"Private"}</Table.ColumnHeader>
<Table.ColumnHeader> {"Group"}</Table.ColumnHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{botCommands.map((commandObj, index) => {
const { command, description, groups } = commandObj;
return (
<Table.Row
key={`${index}-${command}`}
bg="cyan.muted"
_hover={{ bg: "purple.emphasized" }}
>
<Table.Cell>{command}</Table.Cell>
<Table.Cell>{description.replaceAll("\\", "")}</Table.Cell>
<Table.Cell>
{groups ? (
<Checkmark colorPalette="purple" checked />
) : (
<Checkmark colorPalette="purple" indeterminate />
)}
</Table.Cell>
<Table.Cell>
{commandObj.private ? (
<Checkmark colorPalette="purple" checked />
) : (
<Checkmark colorPalette="purple" indeterminate />
)}
</Table.Cell>
</Table.Row>
);
})}
</Table.Body>
</Table.Root>
</VStack>
);
};
export default CommandsListTable;

View File

@@ -41,7 +41,7 @@ const StatsList = ({
groups >= 0 ? (
<SingleStatComponent
loading={loading}
title="Groups Bot"
title="Groups Helped"
error={error}
stat={groups}
/>

37
src/app/api/bot/route.ts Normal file
View File

@@ -0,0 +1,37 @@
import { headers } from "next/headers";
import botCommands from "@/data/botCommands";
const environment = process.env.NODE_ENV || "development";
const isValidApiKey = (apiKey: string): boolean => {
const envApiKey =
process.env.API_TOKEN || process.env.NEXT_PUBLIC_API_TOKEN || "";
return apiKey === envApiKey;
};
export async function GET(/*request: Request*/) {
const headersList = await headers();
const apiKey = headersList.get("x-api-key");
if (environment === "production") {
if (!apiKey || apiKey == null) {
return new Response("No API Key provided", {
status: 401,
headers: headersList
});
}
if (apiKey !== null && !(await isValidApiKey(apiKey))) {
return new Response("Invalid API Key", {
status: 403,
headers: headersList
});
}
}
return Response.json(botCommands, {
status: 200,
headers: headersList
});
}

View File

@@ -23,6 +23,7 @@ import GetTotalGroupsQuery from "@/graphql/queries/getTotalGroups";
import GetTotalStatsQuery from "@/graphql/queries/getTotalStats";
import GetTodaysStatsQuery from "@/graphql/queries/getTodaysStats";
import GetStatsRange from "@/graphql/queries/getStatsRange";
import CommandsListTable from "./CommandsListTable";
export default function Home() {
// * Total Groups * //
@@ -95,9 +96,9 @@ export default function Home() {
<Fragment>
<VStack
bg="cyan.950"
minH="100vh"
minH="100dvh"
h="100%"
py="5vh"
py="5dvh"
minW="fit-content"
textAlign="center"
>
@@ -135,7 +136,7 @@ export default function Home() {
textAlign="center"
>
{
"A telegram bot that removes links and embeds to sites that align with the Fascist Right political agenda."
"A Telegram bot that deletes links and embeds to sites that align with the Fascist Right political agenda or are otherwise a safety/privacy risk."
}
</Heading>
</VStack>
@@ -152,6 +153,7 @@ export default function Home() {
</Text>
</VStack>
</VStack>
<CommandsListTable />
<VStack gap={10} w="100%">
{totalGroups ? (
<StatsList
@@ -194,7 +196,7 @@ export default function Home() {
/>
)}
</VStack>
<VStack w="95%" gap="5vh">
<VStack w="95%" gap="5dvh">
<VStack gap={1}>
<Heading as="h1" fontSize="3xl">{`30 Day Stats`}</Heading>
<Text textAlign="center" fontSize="sm" color="whiteAlpha.800">
@@ -240,7 +242,7 @@ export default function Home() {
rgb(147, 40, 142)
)`}
w="100%"
py="5vh"
py="5dvh"
textAlign="center"
>
<VStack
@@ -263,17 +265,19 @@ export default function Home() {
minW="fit-content"
w={{ base: "100%", sm: "auto" }}
bg="blackAlpha.600"
maxW={{ base: "", sm: "62vw" }}
maxW={{ base: "", sm: "62dvw" }}
px={2}
>
{"Down with fascism! Fuck MAGA! Fuck Trump! Fuck Nazis!"}
{
"Down with fascism! Fuck MAGA! Fuck Trump! Fuck Nazis! Abolish ICE!"
}
</Text>
<Text
fontSize="3xl"
minW="fit-content"
w={{ base: "100%", sm: "auto" }}
bg="blackAlpha.600"
maxW={{ base: "", sm: "62vw" }}
maxW={{ base: "", sm: "62dvw" }}
px={2}
>
{

View File

@@ -25,7 +25,7 @@ const LineChartComponent = ({
});
return (
<Chart.Root maxH="xs" chart={chart} maxW="100vw">
<Chart.Root maxH="xs" chart={chart} maxW="100dvw">
<LineChart data={chart.data}>
<CartesianGrid stroke={chart.color("border")} vertical={false} />
<XAxis

56
src/data/botCommands.ts Normal file
View File

@@ -0,0 +1,56 @@
// * Commands *
interface Commands {
command: String;
description: String;
groups: boolean;
private: boolean;
}
const botInfo: Commands = {
command: "/botInfo",
description:
"Lists information about the bot such as: creator, reason for my creation, purpose and goal, etc",
groups: true,
private: true
};
const getGroupStats: Commands = {
command: "/groupStats",
description:
"Displays the number of times the bot has deleted links in your group for the lifetime of the bot",
groups: true,
private: false
};
const help: Commands = {
command: "/help",
description:
"Lists information about how to setup the bot and the list of available commands",
groups: true,
private: true
};
const registerGroup: Commands = {
command: "/registerGroup",
description: `Will add your group to the database, if your group doesn't exist already\\. This is used to calculate the "total groups" count on the bot stats website`,
groups: true,
private: true
};
const botStatsSite: Commands = {
command: "/botStats",
description: "Provides the bot stats website link as an embed",
groups: true,
private: true
};
const commands: Commands[] = [
botInfo,
getGroupStats,
help,
registerGroup,
botStatsSite
];
export default commands;

View File

@@ -243,7 +243,7 @@ export const resolvers = {
increment: async (
_parent: unknown,
data: {
link: boolean;
link: number;
command: boolean;
trigger: boolean;
mutationKey?: string;
@@ -282,7 +282,7 @@ export const resolvers = {
return await prisma.dailyStats.update({
where: { createdAt: latestDailyStats.createdAt },
data: {
linksDeleted: { increment: link ? 1 : 0 },
linksDeleted: { increment: link ? link : 0 },
commandResponses: { increment: command ? 1 : 0 },
timesTriggered: { increment: trigger ? 1 : 0 }
}

View File

@@ -26,7 +26,7 @@ const typeDefs = /* GraphQL */ `
mutationKey: String
): Groups!
increment(
link: Boolean
link: Int
command: Boolean
trigger: Boolean
mutationKey: String

3437
yarn.lock

File diff suppressed because it is too large Load Diff