Compare commits

..

9 Commits

Author SHA1 Message Date
34dbc8d232 fix string value error
Some checks are pending
Main / build-and-push-docker-image (20.x) (push) Waiting to run
Daily Cron (Make New DailyStats Document) / cron (push) Successful in 1s
2025-12-18 21:46:08 -05:00
5415c0c1f3 FORCE THIS SHIT TO RUN
Some checks are pending
Main / build-and-push-docker-image (20.x) (push) Waiting to run
Daily Cron (Make New DailyStats Document) / cron (push) Successful in 1s
2025-12-18 21:44:37 -05:00
49218131f3 FIXED!
Some checks are pending
Main / build-and-push-docker-image (20.x) (push) Waiting to run
2025-12-18 21:42:56 -05:00
0bbffd1b2a fixed?!
Some checks are pending
Main / build-and-push-docker-image (20.x) (push) Waiting to run
2025-12-18 21:40:40 -05:00
bfcfb8008a fiiiiiiiiiiix
Some checks are pending
Main / build-and-push-docker-image (20.x) (push) Waiting to run
2025-12-18 21:31:17 -05:00
67c5bf86ed fiiiiix
Some checks are pending
Main / build-and-push-docker-image (20.x) (push) Waiting to run
2025-12-18 21:30:37 -05:00
9890331139 fix cron?
Some checks are pending
Main / build-and-push-docker-image (20.x) (push) Waiting to run
2025-12-18 21:28:17 -05:00
2ed31b8930 fix gitignore
All checks were successful
Main / build-and-push-docker-image (20.x) (push) Successful in 4m46s
Daily Cron (Make New DailyStats Document) / cron (push) Successful in 1s
2025-12-18 17:34:24 -05:00
9529e892f4 Fix cron?
Some checks are pending
Main / build-and-push-docker-image (20.x) (push) Waiting to run
2025-12-18 13:03:36 -05:00
15 changed files with 1954 additions and 1788 deletions

View File

@@ -1,8 +1,9 @@
name: Daily Cron (Make New DailyStats Document) name: Daily Cron (Make New DailyStats Document)
on: on:
push:
branches: [main]
schedule: schedule:
- cron: "0 5 * * *" - cron: "0 0 * * *"
jobs: jobs:
cron: cron:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
@@ -16,4 +17,4 @@ jobs:
--url 'https://bot-stats.lucids-cove.duckdns.org/api/graphql' \ --url 'https://bot-stats.lucids-cove.duckdns.org/api/graphql' \
--header 'x-api-key: ${{ secrets.NEXT_PUBLIC_API_TOKEN }}' \ --header 'x-api-key: ${{ secrets.NEXT_PUBLIC_API_TOKEN }}' \
--header 'Content-Type: application/json' \ --header 'Content-Type: application/json' \
--data '{ "query": "mutation Cron { cronJob ( mutationKey: \"${{ secrets.GRAPHQL_MUTATION_KEY }}\" ) { commandResponses createdAt linksDeleted timesTriggered updatedAt } }" }' \ --data '{ "query": "mutation Cron { cronJob ( mutationKey: \"${{ secrets.GRAPHQL_MUTATION_KEY }}\" ) { commandResponses createdAt linksDeleted timesTriggered updatedAt } }" }' \

View File

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

View File

@@ -1,57 +0,0 @@
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 ? ( groups >= 0 ? (
<SingleStatComponent <SingleStatComponent
loading={loading} loading={loading}
title="Groups Helped" title="Groups Bot Helped"
error={error} error={error}
stat={groups} stat={groups}
/> />
@@ -55,13 +55,13 @@ const StatsList = ({
/> />
<SingleStatComponent <SingleStatComponent
loading={loading} loading={loading}
title="Commands Responses" title="Commands Responded To"
error={error} error={error}
stat={commands} stat={commands}
/> />
<SingleStatComponent <SingleStatComponent
loading={loading} loading={loading}
title="Triggers" title="Times Triggered"
error={error} error={error}
stat={triggers} stat={triggers}
/> />

View File

@@ -13,7 +13,7 @@ const TimedTriggeredChart = ({
return ( return (
<VStack gap={6} w="100%"> <VStack gap={6} w="100%">
<Heading as="h4" fontSize="2xl">{`Times Bot Was Triggered`}</Heading> <Heading as="h4" fontSize="2xl">{`Times Bot Was Triggered`}</Heading>
<LineChartComponent data={lineChartData} label="Triggers" /> <LineChartComponent data={lineChartData} label="Times Triggered" />
</VStack> </VStack>
); );
}; };

View File

@@ -1,37 +0,0 @@
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

@@ -34,9 +34,9 @@ export default function RootLayout({
return [client, ssr]; return [client, ssr];
}, []); }, []);
const title = "Anti Nazi-Sites Bot Stats"; const title = "Nazi Site Patrol Stats";
const description = const description =
"A website to display various stats for the Anti Nazi-Sites bot for Telegram. Developed and maintained by Werewolf Kid Creations."; "A website to display various stats for the Nazi Site Patrol bot for Telegram. Developed and maintained by Werewolf Kid Creations.";
const url = "https://bot-stats.werewolfkid.monster"; const url = "https://bot-stats.werewolfkid.monster";
const img = "/images/SPD-arrows.svg"; const img = "/images/SPD-arrows.svg";
const domain = "werewolfkid.monster"; const domain = "werewolfkid.monster";

View File

@@ -23,7 +23,6 @@ import GetTotalGroupsQuery from "@/graphql/queries/getTotalGroups";
import GetTotalStatsQuery from "@/graphql/queries/getTotalStats"; import GetTotalStatsQuery from "@/graphql/queries/getTotalStats";
import GetTodaysStatsQuery from "@/graphql/queries/getTodaysStats"; import GetTodaysStatsQuery from "@/graphql/queries/getTodaysStats";
import GetStatsRange from "@/graphql/queries/getStatsRange"; import GetStatsRange from "@/graphql/queries/getStatsRange";
import CommandsListTable from "./CommandsListTable";
export default function Home() { export default function Home() {
// * Total Groups * // // * Total Groups * //
@@ -94,14 +93,7 @@ export default function Home() {
return ( return (
<Fragment> <Fragment>
<VStack <VStack bg="cyan.950" minH="100vh" h="100%" py="5vh" minW="fit-content">
bg="cyan.950"
minH="100dvh"
h="100%"
py="5dvh"
minW="fit-content"
textAlign="center"
>
<VStack w={{ base: "100%", md: "90%" }} gap={10} minW="fit-content"> <VStack w={{ base: "100%", md: "90%" }} gap={10} minW="fit-content">
<VStack w="80%" gap={10}> <VStack w="80%" gap={10}>
<Icon h="7.5rem" color="whiteAlpha"> <Icon h="7.5rem" color="whiteAlpha">
@@ -122,12 +114,8 @@ export default function Home() {
</svg> </svg>
</Icon> </Icon>
<VStack gap={4} maxW="34rem"> <VStack gap={4} maxW="34rem">
<Heading <Heading as="h1" fontSize="5xl">
as="h1" {"Anti Nazi Sites Bot Stats"}
fontSize="5xl"
lineHeight={{ base: "3rem", md: "" }}
>
{"Anti Nazi-Sites Bot Stats"}
</Heading> </Heading>
<Heading <Heading
as="h2" as="h2"
@@ -136,7 +124,7 @@ export default function Home() {
textAlign="center" textAlign="center"
> >
{ {
"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." "A telegram bot that removes links and embeds to sites that align with the Fascist Right political agenda."
} }
</Heading> </Heading>
</VStack> </VStack>
@@ -153,7 +141,6 @@ export default function Home() {
</Text> </Text>
</VStack> </VStack>
</VStack> </VStack>
<CommandsListTable />
<VStack gap={10} w="100%"> <VStack gap={10} w="100%">
{totalGroups ? ( {totalGroups ? (
<StatsList <StatsList
@@ -196,7 +183,7 @@ export default function Home() {
/> />
)} )}
</VStack> </VStack>
<VStack w="95%" gap="5dvh"> <VStack w="95%" gap="5vh">
<VStack gap={1}> <VStack gap={1}>
<Heading as="h1" fontSize="3xl">{`30 Day Stats`}</Heading> <Heading as="h1" fontSize="3xl">{`30 Day Stats`}</Heading>
<Text textAlign="center" fontSize="sm" color="whiteAlpha.800"> <Text textAlign="center" fontSize="sm" color="whiteAlpha.800">
@@ -242,21 +229,13 @@ export default function Home() {
rgb(147, 40, 142) rgb(147, 40, 142)
)`} )`}
w="100%" w="100%"
py="5dvh" py="5vh"
textAlign="center" textAlign="center"
> >
<VStack <VStack
color="white" color="white"
textShadow={` textShadow="0px 0px 5px black;"
2px 2px 0 #000, WebkitTextStroke="0.3px black;"
2px -2px 0 #000,
-2px 2px 0 #000,
-2px -2px 0 #000,
2px 0px 0 #000,
0px 2px 0 #000,
-2px 0px 0 #000,
0px -2px 0 #000
`}
gap={6} gap={6}
w="100%" w="100%"
> >
@@ -265,19 +244,17 @@ export default function Home() {
minW="fit-content" minW="fit-content"
w={{ base: "100%", sm: "auto" }} w={{ base: "100%", sm: "auto" }}
bg="blackAlpha.600" bg="blackAlpha.600"
maxW={{ base: "", sm: "62dvw" }} maxW={{ base: "", sm: "62vw" }}
px={2} px={2}
> >
{ {"Down with fascism! Fuck MAGA! Fuck Trump! Fuck Nazis!"}
"Down with fascism! Fuck MAGA! Fuck Trump! Fuck Nazis! Abolish ICE!"
}
</Text> </Text>
<Text <Text
fontSize="3xl" fontSize="3xl"
minW="fit-content" minW="fit-content"
w={{ base: "100%", sm: "auto" }} w={{ base: "100%", sm: "auto" }}
bg="blackAlpha.600" bg="blackAlpha.600"
maxW={{ base: "", sm: "62dvw" }} maxW={{ base: "", sm: "62vw" }}
px={2} px={2}
> >
{ {

View File

@@ -11,7 +11,7 @@ import {
import { LineChartArr } from "@/types/LineChartStats"; import { LineChartArr } from "@/types/LineChartStats";
interface LineChartComponentProps { interface LineChartComponentProps {
label: "Triggers" | "Links Deleted" | "Command Responses"; label: "Times Triggered" | "Links Deleted" | "Command Responses";
data: LineChartArr; data: LineChartArr;
} }
@@ -25,7 +25,7 @@ const LineChartComponent = ({
}); });
return ( return (
<Chart.Root maxH="xs" chart={chart} maxW="100dvw"> <Chart.Root maxH="xs" chart={chart} maxW="100vw">
<LineChart data={chart.data}> <LineChart data={chart.data}>
<CartesianGrid stroke={chart.color("border")} vertical={false} /> <CartesianGrid stroke={chart.color("border")} vertical={false} />
<XAxis <XAxis

View File

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

View File

@@ -13,7 +13,7 @@ const typeDefs = /* GraphQL */ `
} }
type Mutation { type Mutation {
init(mutationKey: String): String! init(mutationKey: String): String!
cronJob(mutationKey: String): TotalStats cronJob(mutationKey: String): TotalStats!
addGroup( addGroup(
groupID: String! groupID: String!
groupName: String! groupName: String!
@@ -26,7 +26,7 @@ const typeDefs = /* GraphQL */ `
mutationKey: String mutationKey: String
): Groups! ): Groups!
increment( increment(
link: Int link: Boolean
command: Boolean command: Boolean
trigger: Boolean trigger: Boolean
mutationKey: String mutationKey: String

View File

@@ -15,7 +15,7 @@ const lineChartArr = (dailyStatsArr: DailyStats): LineChartArr => {
day, day,
"Links Deleted": linksDeleted, "Links Deleted": linksDeleted,
"Command Responses": commandResponses, "Command Responses": commandResponses,
Triggers: timesTriggered "Times Triggered": timesTriggered
}; };
lineChartArr.push(lineChartItem); lineChartArr.push(lineChartItem);

View File

@@ -2,7 +2,7 @@ export interface LineChartItem {
day: number; day: number;
"Links Deleted": number; "Links Deleted": number;
"Command Responses": number; "Command Responses": number;
Triggers: number; "Times Triggered": number;
} }
export type LineChartArr = LineChartItem[]; export type LineChartArr = LineChartItem[];

3467
yarn.lock

File diff suppressed because it is too large Load Diff