fix #3, now tracking cheers and cheerEvents in database, minor tweaks to existing code

This commit is contained in:
2025-08-24 20:20:52 +02:00
parent 97a6a599a8
commit 594d154cab
13 changed files with 108 additions and 15 deletions

View File

@@ -5,6 +5,7 @@ import User from "user";
import { timeout } from "lib/timeout";
import { createTimeoutRecord } from "db/dbTimeouts";
import { parseCheerArgs } from "lib/parseCommandArgs";
import { createCheerEventRecord } from "db/dbCheerEvents";
const ITEMNAME = 'silverbullet';
@@ -19,6 +20,7 @@ export default new Cheer('execute', 6666, async (msg, user) => {
if (result.status) await Promise.all([
sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`),
createTimeoutRecord(user, target, ITEMNAME),
createCheerEventRecord(user, ITEMNAME)
]);
else {
await handleNoTarget(msg, user, ITEMNAME);

View File

@@ -4,11 +4,12 @@ import { timeout } from "lib/timeout";
import User from "user";
import { getUserRecord } from "db/dbUser";
import { createTimeoutRecord } from "db/dbTimeouts";
import { createCheerEventRecord } from "db/dbCheerEvents";
import { Cheer, handleNoTarget } from "cheers";
const ITEMNAME = 'grenade';
export default new Cheer(ITEMNAME, 99, async (msg, user) => {
export default new Cheer('grenade', 99, async (msg, user) => {
const targets = await redis.keys(`user:*:vulnerable`);
if (targets.length === 0) { await sendMessage('No vulnerable chatters to blow up!', msg.messageId); await handleNoTarget(msg, user, ITEMNAME); return; };
const selection = targets[Math.floor(Math.random() * targets.length)]!;
@@ -20,6 +21,7 @@ export default new Cheer(ITEMNAME, 99, async (msg, user) => {
timeout(target!, `You got hit by ${user.displayName}'s grenade!`, 60),
redis.del(selection),
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s grenade wybuh`),
createTimeoutRecord(user, target!, ITEMNAME)
createTimeoutRecord(user, target!, ITEMNAME),
createCheerEventRecord(user, ITEMNAME)
]);
});

View File

@@ -4,6 +4,7 @@ import { getUserRecord } from "db/dbUser";
import User from "user";
import { timeout } from "lib/timeout";
import { createTimeoutRecord } from "db/dbTimeouts";
import { createCheerEventRecord } from "db/dbCheerEvents";
import { parseCheerArgs } from "lib/parseCommandArgs";
const ITEMNAME = 'blaster';
@@ -18,7 +19,8 @@ export default new Cheer('timeout', 100, async (msg, user) => {
const result = await timeout(target, `You got blasted by ${user.displayName}!`, 60);
if (result.status) await Promise.all([
sendMessage(`GOTTEM ${target.displayName} got BLASTED by ${user.displayName} GOTTEM`),
createTimeoutRecord(user, target, ITEMNAME)
createTimeoutRecord(user, target, ITEMNAME),
createCheerEventRecord(user, ITEMNAME)
]);
else {
await handleNoTarget(msg, user, ITEMNAME);

View File

@@ -4,6 +4,7 @@ import { getUserRecord } from "db/dbUser";
import User from "user";
import { timeout } from "lib/timeout";
import { createTimeoutRecord } from "db/dbTimeouts";
import { createCheerEventRecord } from "db/dbCheerEvents";
import { getTNTTargets } from "items/tnt";
import { redis } from "bun";
@@ -22,6 +23,7 @@ export default new Cheer('tnt', 1000, async (msg, user) => {
redis.del(`user:${targetid}:vulnerable`),
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s TNT wybuh`),
createTimeoutRecord(user, target!, ITEMNAME),
createCheerEventRecord(user, ITEMNAME)
]);
}));

View File

@@ -3,7 +3,7 @@ import { addInvuln } from "lib/invuln";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";
export default new Command('addinvuln', ['addinvuln'], 'streamer', async msg => {
export default new Command('addinvuln', ['addinvuln'], 'admin', async msg => {
const args = parseCommandArgs(msg.messageText);
if (!args[0]) { await sendMessage('Please specify a target', msg.messageId); return; };
const target = await User.initUsername(args[0].toLowerCase());

View File

@@ -4,7 +4,7 @@ import { removeInvuln } from "lib/invuln";
import parseCommandArgs from "lib/parseCommandArgs";
import User from "user";
export default new Command('removeinvuln', ['removeinvuln'], 'streamer', async msg => {
export default new Command('removeinvuln', ['removeinvuln'], 'admin', async msg => {
const args = parseCommandArgs(msg.messageText);
if (!args[0]) { await sendMessage('Please specify a target', msg.messageId); return; };
const target = await User.initUsername(args[0].toLowerCase());

View File

@@ -34,11 +34,26 @@ export type timeoutRecord = {
created: string;
};
export type cheerEventRecord = {
id?: string;
user: string;
cheer: string;
created: string;
};
export type cheerRecord = {
id?: string;
user?: string;
amount: number;
};
interface TypedPocketBase extends PocketBase {
collection(idOrName: 'auth'): RecordService<authRecord>;
collection(idOrName: 'users'): RecordService<userRecord>;
collection(idOrName: 'usedItems'): RecordService<usedItemRecord>;
collection(idOrName: 'timeouts'): RecordService<timeoutRecord>;
collection(idOrName: 'cheerEvents'): RecordService<cheerEventRecord>;
collection(idOrName: 'cheers'): RecordService<cheerRecord>;
};
export default new PocketBase(pocketbaseurl).autoCancellation(false) as TypedPocketBase;

26
src/db/dbCheerEvents.ts Normal file
View File

@@ -0,0 +1,26 @@
import pocketbase from "db/connection";
import User from "user";
import logger from "lib/logger";
const pb = pocketbase.collection('cheerEvents');
export async function createCheerEventRecord(user: User, cheer: string): Promise<void> {
try {
await pb.create({ user: user.id, cheer });
} catch (e) {
logger.err(`Failed to create cheerEvent record in database: user: ${user.id}, cheer: ${cheer}`);
logger.err(e as string);
};
};
export async function getCheerEvents(user: User, monthData?: string) {
try {
const monthquery = monthData ? ` && created~"${monthData}"` : '';
const data = await pb.getFullList({
filter: `user="${user.id}"${monthquery}`
});
return data;
} catch (e) {
logger.err(`Failed to get cheerEvents for user: ${user.id}, month: ${monthData}`);
logger.err(e as string);
};
};

26
src/db/dbCheers.ts Normal file
View File

@@ -0,0 +1,26 @@
import pocketbase from "db/connection";
import User from "user";
import logger from "lib/logger";
const pb = pocketbase.collection('cheers');
export async function createCheerRecord(user: User, amount: number): Promise<void> {
try {
await pb.create({ user: user.id, amount })
} catch (e) {
logger.err(`Failed to create cheer record in database: user: ${user.id}, amount: ${amount}`);
logger.err(e as string);
};
};
export async function getCheers(user: User, monthData?: string) {
try {
const monthquery = monthData ? ` && created~"${monthData}"` : '';
const data = await pb.getFullList({
filter: `user="${user.id}"${monthquery}`
});
return data;
} catch (e) {
logger.err(`Failed to get cheers for user: ${user.id}, month: ${monthData}`);
logger.err(e as string);
};
};

View File

@@ -8,6 +8,8 @@ import cheers from "cheers";
import logger from "lib/logger";
import { addMessageToChatWidget } from "web/chatWidget/message";
import { isInvuln, setTemporaryInvuln } from "lib/invuln";
import { getUserRecord } from "db/dbUser";
import { createCheerRecord } from "db/dbCheers";
logger.info(`Loaded the following commands: ${commands.keys().toArray().join(', ')}`);
@@ -65,6 +67,11 @@ async function handleChatMessage(msg: EventSubChannelChatMessageEvent, user: Use
};
export async function handleCheer(msg: EventSubChannelChatMessageEvent, bits: number, user: User) {
if (msg.isCheer) {
await getUserRecord(user); // ensure they exist in the database
await createCheerRecord(user, bits);
}; // If this is not triggered it's because of the testcheer command. these fake bits should not be added to the database
const selection = cheers.get(bits);
if (!selection) return;

View File

@@ -1,3 +1,4 @@
import { getCheerEvents } from "db/dbCheerEvents";
import { getTimeoutsAsTarget, getTimeoutsAsUser } from "db/dbTimeouts";
import { getItemsUsed } from "db/dbUsedItems";
import type { inventory } from "items";
@@ -33,12 +34,22 @@ export async function getTimeoutStats(target: User, thismonth: boolean) {
export async function getItemStats(target: User, thismonth: boolean) {
const monthdata = thismonth ? new Date().toISOString().slice(0, 7) : undefined;
const data = await getItemsUsed(target, monthdata);
if (!data) return;
const [items, cheers] = await Promise.all([
getItemsUsed(target, monthdata),
getCheerEvents(target, monthdata)
]);
if (!items || !cheers) return;
const returnObj: inventory = {
grenade: data.filter(use => use.item === 'grenade').length,
tnt: data.filter(use => use.item === 'tnt').length
const returnObj: inventory = {};
for (const item of items) {
if (!returnObj[item.item]) returnObj[item.item] = 0;
returnObj[item.item]! += 1;
};
for (const cheer of cheers) {
if (!returnObj[cheer.cheer]) returnObj[cheer.cheer] = 0;
returnObj[cheer.cheer]! += 1
};
return returnObj;

View File

@@ -14,7 +14,7 @@ export async function addInvuln(userid: string) {
export async function removeInvuln(userid: string) {
return await redis.del(`user:${userid}:invulnerable`);
};
export async function setTemporaryInvuln(userid: string) {
export async function setTemporaryInvuln(userid: string, duration = 600) {
await redis.set(`user:${userid}:invulnerable`, '1');
await redis.expire(`user:${userid}:invulnerable`, 600);
await redis.expire(`user:${userid}:invulnerable`, duration);
};