buy, use, delete, edit item
This commit is contained in:
41
commands/buy.ts
Normal file
41
commands/buy.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import type { StoreItem, User } from "../db";
|
||||
import { get_item, add_item_to_user, sub_balance } from "../db";
|
||||
import { BotError } from "./common/error";
|
||||
import { item_name_autocomplete } from "./common/autocompletes";
|
||||
import { has_role } from "../util";
|
||||
import config from "../config.json";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction, user: User) {
|
||||
const options = interaction.options;
|
||||
const name: string = (await options.get("name")).value as string;
|
||||
const quantity: number = (await options.get("quantity")).value as number;
|
||||
if (quantity <= 0) throw new BotError("Can't buy 0 or less of an item. Nice try");
|
||||
const item = await get_item(name);
|
||||
if (!item) throw new BotError("Item does not exist");
|
||||
if (item.roles_required.length > 0) {
|
||||
for (const role_id of item.roles_required) {
|
||||
if (!has_role(interaction, role_id)) throw new BotError("Missing one of the required roles to buy this item");
|
||||
}
|
||||
}
|
||||
const total_cost = item.price * quantity;
|
||||
if (!(await sub_balance(user.user, total_cost))) throw new BotError("Not enough balance to buy this item");
|
||||
await add_item_to_user(user.user, item.name, quantity);
|
||||
return await interaction.editReply(`Bought ${quantity} of \`${name}\` for ${total_cost} ${ total_cost === 1 ? config.currency : config.currency_plural }`);
|
||||
}
|
||||
|
||||
const data: CommandData = {
|
||||
name: "buy",
|
||||
description: "Buy an item from the store",
|
||||
registered_only: true,
|
||||
ephemeral: false,
|
||||
admin_only: false,
|
||||
run,
|
||||
autocomplete: item_name_autocomplete, //autocompletes for the "name" option
|
||||
};
|
||||
|
||||
export default data;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//also: edit_item, delete_item, store, buy, use_item, (admin: /take_item, /add_item)
|
||||
//also: edit_item
|
||||
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
|
||||
|
||||
28
commands/delete_item.ts
Normal file
28
commands/delete_item.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import { delete_item, get_item } from "../db";
|
||||
import { BotError } from "./common/error";
|
||||
import { item_name_autocomplete } from "./common/autocompletes";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction) {
|
||||
await interaction.deferReply();
|
||||
const options = interaction.options;
|
||||
const name: string = (await options.get("name")).value as string;
|
||||
if (!(await get_item(name))) throw new BotError("No item with that name exists to delete");
|
||||
await delete_item(name);
|
||||
return await interaction.editReply(`Deleted item \`${name}\``);
|
||||
}
|
||||
|
||||
const data: CommandData = {
|
||||
name: "delete_item",
|
||||
description: "Delete item from the store and all users",
|
||||
registered_only: false,
|
||||
ephemeral: false,
|
||||
admin_only: true,
|
||||
run,
|
||||
autocomplete: item_name_autocomplete, //autocompletes for the "name" option
|
||||
};
|
||||
|
||||
export default data;
|
||||
|
||||
47
commands/edit_item.ts
Normal file
47
commands/edit_item.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import type { Items, StoreItem, User } from "../db";
|
||||
import { edit_item, get_item } from "../db";
|
||||
import { BotError } from "./common/error";
|
||||
import { item_name_autocomplete } from "./common/autocompletes";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction) {
|
||||
await interaction.deferReply();
|
||||
const options = interaction.options;
|
||||
const name: string = (await options.get("name")).value as string;
|
||||
const delete_existing_roles: boolean = (await options.get("delete_existing_roles")).value as boolean;
|
||||
const item = await get_item(name);
|
||||
if (!item) throw new BotError("No item of that name exists");
|
||||
const price: number = ((await options.get("price"))?.value ?? item.price) as number;
|
||||
const description: string = ((await options.get("description"))?.value ?? item.description) as string;
|
||||
const usable: boolean = ((await options.get("usable"))?.value ?? item.usable) as boolean;
|
||||
//to add multiple roles, people will have to use /edit_item, I guess? augh
|
||||
const required_role = (await options.get("required_role"))?.role;
|
||||
if (price < 0) throw new BotError("Price cannot be negative");
|
||||
//name and description char limits (based on discord embed field name/value limits)
|
||||
if (description.length > 900) throw new BotError("Item description cannot be more than 1024 characters"); //true limit is 1024 but we want some margin for other info
|
||||
const existing = delete_existing_roles ? [] : item.roles_required;
|
||||
const store_item: StoreItem = {
|
||||
name,
|
||||
price,
|
||||
description,
|
||||
roles_required: required_role ? [...existing, required_role.id] : existing,
|
||||
usable,
|
||||
};
|
||||
await edit_item(store_item);
|
||||
return await interaction.editReply("Item edited");
|
||||
}
|
||||
|
||||
const data: CommandData = {
|
||||
name: "edit_item",
|
||||
description: "Edit item",
|
||||
registered_only: false,
|
||||
ephemeral: false,
|
||||
admin_only: true,
|
||||
run,
|
||||
autocomplete: item_name_autocomplete, //autocompletes for the "name" option
|
||||
};
|
||||
|
||||
export default data;
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { User } from "../db";
|
||||
import { get_user } from "../db";
|
||||
import { BotError } from "./common/error";
|
||||
import config from "../config.json";
|
||||
import { has_role } from "../util";
|
||||
|
||||
import say from "./say";
|
||||
import roll from "./roll";
|
||||
@@ -16,6 +17,10 @@ import items from "./items";
|
||||
import create_item from "./create_item";
|
||||
import store from "./store";
|
||||
import change_item_balance from "./change_item_balance";
|
||||
import buy from "./buy";
|
||||
import use_item from "./use_item";
|
||||
import delete_item from "./delete_item";
|
||||
import edit_item from "./edit_item";
|
||||
|
||||
export interface CommandData {
|
||||
name: string;
|
||||
@@ -27,10 +32,10 @@ export interface CommandData {
|
||||
autocomplete?: (interaction: AutocompleteInteraction) => Promise<any>;
|
||||
};
|
||||
|
||||
const commands: CommandData[] = [say, roll, register_user, bal, change_bal, transfer, items, create_item, store, change_item_balance];
|
||||
const commands: CommandData[] = [say, roll, register_user, bal, change_bal, transfer, items, create_item, store, change_item_balance, buy, use_item, delete_item, edit_item];
|
||||
|
||||
function is_admin(interaction: ChatInputCommandInteraction): boolean {
|
||||
return (interaction.member as GuildMember).roles.cache.some((r) => r.id === config.admin_role);
|
||||
return has_role(interaction, config.admin_role);
|
||||
}
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction, found: CommandData, name: string) {
|
||||
|
||||
34
commands/use_item.ts
Normal file
34
commands/use_item.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import type { StoreItem, User } from "../db";
|
||||
import { get_item, sub_item_to_user } from "../db";
|
||||
import { BotError } from "./common/error";
|
||||
import { item_name_autocomplete } from "./common/autocompletes";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction, user: User) {
|
||||
const options = interaction.options;
|
||||
const name: string = (await options.get("name")).value as string;
|
||||
const quantity: number = (await options.get("quantity")).value as number;
|
||||
if (quantity <= 0) throw new BotError("Can't use 0 or less of an item");
|
||||
const item = await get_item(name);
|
||||
if (!item) throw new BotError("Item does not exist");
|
||||
if (!item.usable) throw new BotError("That item is not usable");
|
||||
if (!(await sub_item_to_user(user.user, name, quantity))) throw new BotError("You did not have enough of that item to use");
|
||||
return await interaction.editReply(`Used ${quantity} of \`${name}\``);
|
||||
}
|
||||
|
||||
const data: CommandData = {
|
||||
name: "use_item",
|
||||
description: "Use an item (subtracts from your items)",
|
||||
registered_only: true,
|
||||
ephemeral: false,
|
||||
admin_only: false,
|
||||
run,
|
||||
autocomplete: item_name_autocomplete, //autocompletes for the "name" option
|
||||
};
|
||||
|
||||
export default data;
|
||||
|
||||
|
||||
|
||||
4
db.ts
4
db.ts
@@ -124,7 +124,7 @@ export async function get_all_items(): Promise<StoreItem[]> {
|
||||
return await (await store.find()).toArray();
|
||||
}
|
||||
|
||||
export async function get_item(item: string): Promise<StoreItem[]> {
|
||||
export async function get_item(item: string): Promise<StoreItem> {
|
||||
return await store.findOne({ name: item });
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ export async function create_item(store_item: StoreItem) {
|
||||
|
||||
//assume name cannot be edited
|
||||
export async function edit_item(store_item: StoreItem) {
|
||||
return await store.updateOne({ name: store_item.name }, store_item);
|
||||
return await store.replaceOne({ name: store_item.name }, store_item);
|
||||
}
|
||||
|
||||
export async function delete_item(item: string) {
|
||||
|
||||
94
register.ts
94
register.ts
@@ -203,6 +203,100 @@ const commands = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "buy",
|
||||
description: "Buy an item from the store",
|
||||
options: [
|
||||
{
|
||||
type: 3,
|
||||
name: "name",
|
||||
description: "Name of the item",
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
},
|
||||
{
|
||||
type: 4,
|
||||
name: "quantity",
|
||||
description: "Amount of the item to buy",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "use_item",
|
||||
description: "Use an item (subtracts from your items)",
|
||||
options: [
|
||||
{
|
||||
type: 3,
|
||||
name: "name",
|
||||
description: "Name of the item",
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
},
|
||||
{
|
||||
type: 4,
|
||||
name: "quantity",
|
||||
description: "Amount of the item to use",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "delete_item",
|
||||
description: "Delete item from the store and all users (admin only)",
|
||||
options: [
|
||||
{
|
||||
type: 3,
|
||||
name: "name",
|
||||
description: "Name of the item",
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "edit_item",
|
||||
description: "Create item (admin only)",
|
||||
options: [
|
||||
{
|
||||
type: 3,
|
||||
name: "name",
|
||||
description: "Name of the item",
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
},
|
||||
{
|
||||
type: 5,
|
||||
name: "delete_existing_roles",
|
||||
description: "If true, deletes existing required roles as requirements",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 4,
|
||||
name: "price",
|
||||
description: "Price of the item",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
type: 3,
|
||||
name: "description",
|
||||
description: "Description of the item",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
type: 5,
|
||||
name: "usable",
|
||||
description: "Whether it can be /use'd",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
type: 8,
|
||||
name: "required_role",
|
||||
description: "Roles that are required to buy this item.",
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
(new REST().setToken(process.env.DISCORD_TOKEN)).put(Routes.applicationCommands(process.env.CLIENT_ID), { body: commands }).then(() => console.log("Finished reloading slash commands"));
|
||||
|
||||
4
util.ts
4
util.ts
@@ -1,6 +1,10 @@
|
||||
import type { ChatInputCommandInteraction, GuildMember } from "discord.js";
|
||||
import type { UpdateResult } from "mongodb";
|
||||
|
||||
export function did_update(result: UpdateResult): boolean {
|
||||
return result.modifiedCount > 0;
|
||||
}
|
||||
|
||||
export function has_role(interaction: ChatInputCommandInteraction, role_id: string): boolean {
|
||||
return (interaction.member as GuildMember).roles.cache.some((r) => r.id === role_id);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user