add admin powers

This commit is contained in:
2025-06-27 14:31:20 +02:00
parent a4199b45d1
commit c960ae49bf
7 changed files with 92 additions and 17 deletions

View File

@@ -2,34 +2,47 @@
## Commands ## Commands
### About commands
All of these command need a prefix. By default this is `!` All of these command need a prefix. By default this is `!`
Arguments like `[this]` are optional. Arguments like `[this]` are optional.
Arguments like `{this}` are required. Arguments like `{this}` are required.
Commands and items can be disabled and enabled by admins with the [`enable` and `disable` commands](#administrative-commands).
Not all Commands can be disabled, the `DISABLEABLE` field shows if they can or can't. Items can always be disabled.
Admins are defined by the streamer and can use special administrative command on the bot.
Admins don't need to have moderator status in the channel.
The chatterbot and streamer always have admin status and cannot be stripped of admin powers.
Only the streamer and chatterbot have the power to add and remove admins.
### Fun commands ### Fun commands
COMMAND|FUNCTION|USER|ALIASES COMMAND|FUNCTION|USER|ALIASES|DISABLEABLE
-|-|-|- -|-|-|-|-
`ping`|Testing command|anyone|`ping` `ping`|Testing command|anyone|`ping`|:white_check_mark:
`yabai`|Random number|anyone|`yabai` `goon` `yabai`|Random number|anyone|`yabai` `goon`|:white_check_mark:
`seiso`|Random number|anyone|`seiso` `seiso`|Random number|anyone|`seiso`|:white_check_mark:
### Item commands ### Item commands
COMMAND|FUNCTION|USER|ALIASES COMMAND|FUNCTION|USER|ALIASES|DISABLEABLE
-|-|-|- -|-|-|-|-
`iteminfo {item}`|Get item function and aliases|anyone|`iteminfo` `itemhelp` `info` `iteminfo {item}`|Get item function and aliases|anyone|`iteminfo` `itemhelp` `info`|:white_check_mark:
`inventory [target]`|Get inventory contents of target or self|anyone|`inventory` `inv` `inventory [target]`|Get inventory contents of target or self|anyone|`inventory` `inv`|:white_check_mark:
`give {target} {item} {amount}`|Give targeted user amount of items|anyone|`give` `give {target} {item} {amount}`|Give targeted user amount of items|anyone|`give`|:white_check_mark:
`use {item} ...`|Use item. More info at [The items section](#items)|anyone|`use` `use {item} ...`|Use item. More info at [The items section](#items)|anyone|`use`|:white_check_mark:
`admingive {target} {item} {amount}`|Give targeted user amount of new items|admins|`admingive` `admingive {target} {item} {amount}`|Give targeted user amount of new items|admins|`admingive`|:x:
### Administrative commands ### Administrative commands
COMMAND|FUNCTION|USER|ALIASES COMMAND|FUNCTION|USER|ALIASES|DISABLEABLE
-|-|-|- -|-|-|-|-
`vulnchatters`|Get amount of chatters vulnerable to explosives|anyone|`vulnchatters` `vulnc` `vulnchatters`|Get amount of chatters vulnerable to explosives|anyone|`vulnchatters` `vulnc`|:white_check_mark:
`getadmins`|Get a list of every admin in the channel|anyone|`getadmins`|:x:
`addadmin {target}`|Adds an admin|streamer/botchatter|`addadmin`|:x:
`removeadmin {target}`|Removes an admin|streamer/botchatter|`removeadmin`|:x:
## Items ## Items

16
bot/commands/addadmin.ts Normal file
View File

@@ -0,0 +1,16 @@
import { Command, sendMessage } from ".";
import { addAdmin } from "../lib/admins";
import parseCommandArgs from "../lib/parseCommandArgs";
import { User } from "../user";
import { unbannableUsers } from "..";
export default new Command('addadmin', ['addadmin'], [], async msg => {
if (!unbannableUsers.includes(msg.chatterId)) return;
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());
if (!target) { await sendMessage(`Chatter ${args[0]} doesn't exist`, msg.messageId); return; };
const data = await addAdmin(target.id);
if (data === 1) await sendMessage(`${target.displayName} is now an admin`, msg.messageId);
else await sendMessage(`${target.displayName} is already an admin`, msg.messageId);
}, false);

View File

@@ -1,12 +1,12 @@
import { Command, sendMessage } from "."; import { Command, sendMessage } from ".";
import { unbannableUsers } from "..";
import { getUserRecord } from "../db/dbUser"; import { getUserRecord } from "../db/dbUser";
import items, { changeItemCount } from "../items"; import items, { changeItemCount } from "../items";
import { isAdmin } from "../lib/admins";
import parseCommandArgs from "../lib/parseCommandArgs"; import parseCommandArgs from "../lib/parseCommandArgs";
import { User } from "../user"; import { User } from "../user";
export default new Command('admingive', ['admingive'], [], async msg => { export default new Command('admingive', ['admingive'], [], async msg => {
if (!unbannableUsers.includes(msg.chatterId)) { await sendMessage('nah', msg.messageId); return; }; if (!await isAdmin(msg.chatterId)) return;
const args = parseCommandArgs(msg.messageText); const args = parseCommandArgs(msg.messageText);
if (!args[0]) { await sendMessage('Please specify a user', msg.messageId); return; }; if (!args[0]) { await sendMessage('Please specify a user', msg.messageId); return; };
const target = await User.initUsername(args[0].toLowerCase()); const target = await User.initUsername(args[0].toLowerCase());

13
bot/commands/getadmins.ts Normal file
View File

@@ -0,0 +1,13 @@
import { Command, sendMessage } from ".";
import { getAdmins } from "../lib/admins";
import { User } from "../user";
export default new Command('getadmins', ['getadmins'], [], async msg => {
const admins = await getAdmins()
const adminnames: string[] = [];
for (const id of admins) {
const admin = await User.initUserId(id);
adminnames.push(admin?.displayName!);
};
await sendMessage(`Current admins: ${adminnames.join(', ')}`, msg.messageId);
}, false);

View File

@@ -0,0 +1,17 @@
import { Command, sendMessage } from ".";
import { unbannableUsers } from "..";
import { removeAdmin } from "../lib/admins";
import parseCommandArgs from "../lib/parseCommandArgs";
import { User } from "../user";
export default new Command('removeadmin', ['removeadmin'], [], async msg => {
if (!unbannableUsers.includes(msg.chatterId)) return;
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());
if (!target) { await sendMessage(`Chatter ${args[0]} doesn't exist`, msg.messageId); return; };
if (unbannableUsers.includes(target.id)) { await sendMessage(`Can't remove admin ${target.displayName} as they are managed by the bot program`, msg.messageId); return; };
const data = await removeAdmin(target.id);
if (data === 1) await sendMessage(`${target.displayName} is no longer an admin`, msg.messageId);
else await sendMessage(`${target.displayName} isn't an admin`, msg.messageId);
}, false);

View File

@@ -3,6 +3,7 @@ import { ApiClient } from "@twurple/api";
import { EventSubHttpListener, ReverseProxyAdapter } from "@twurple/eventsub-http"; import { EventSubHttpListener, ReverseProxyAdapter } from "@twurple/eventsub-http";
import { commandintents } from "./commands"; import { commandintents } from "./commands";
import { itemintents } from "./items"; import { itemintents } from "./items";
import { addAdmin } from "./lib/admins";
const CHATTERBASEINTENTS = ["user:read:chat", "user:write:chat", "user:bot"]; const CHATTERBASEINTENTS = ["user:read:chat", "user:write:chat", "user:bot"];
const STREAMERBASEINTENTS = ["user:read:chat", "moderation:read", "channel:manage:moderators"]; const STREAMERBASEINTENTS = ["user:read:chat", "moderation:read", "channel:manage:moderators"];
@@ -40,5 +41,6 @@ export const eventSub = new EventSubHttpListener({
export const commandPrefix = process.env.COMMAND_PREFIX ?? "!"; export const commandPrefix = process.env.COMMAND_PREFIX ?? "!";
export const unbannableUsers = [chatterId, streamerId]; export const unbannableUsers = [chatterId, streamerId];
unbannableUsers.forEach(async id => await addAdmin(id));
await import("./events"); await import("./events");

14
bot/lib/admins.ts Normal file
View File

@@ -0,0 +1,14 @@
import { redis } from "bun";
export async function getAdmins() {
return await redis.smembers('admins');
};
export async function isAdmin(userid: string) {
return await redis.sismember('admins', userid);
};
export async function addAdmin(userid: string) {
return await redis.sadd('admins', userid);
};
export async function removeAdmin(userid: string) {
return await redis.srem('admins', userid);
};