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";
|
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 { get_user } from "../db";
|
||||||
import { BotError } from "./common/error";
|
import { BotError } from "./common/error";
|
||||||
import config from "../config.json";
|
import config from "../config.json";
|
||||||
|
import { has_role } from "../util";
|
||||||
|
|
||||||
import say from "./say";
|
import say from "./say";
|
||||||
import roll from "./roll";
|
import roll from "./roll";
|
||||||
@@ -16,6 +17,10 @@ import items from "./items";
|
|||||||
import create_item from "./create_item";
|
import create_item from "./create_item";
|
||||||
import store from "./store";
|
import store from "./store";
|
||||||
import change_item_balance from "./change_item_balance";
|
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 {
|
export interface CommandData {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -27,10 +32,10 @@ export interface CommandData {
|
|||||||
autocomplete?: (interaction: AutocompleteInteraction) => Promise<any>;
|
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 {
|
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) {
|
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();
|
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 });
|
return await store.findOne({ name: item });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ export async function create_item(store_item: StoreItem) {
|
|||||||
|
|
||||||
//assume name cannot be edited
|
//assume name cannot be edited
|
||||||
export async function edit_item(store_item: StoreItem) {
|
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) {
|
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"));
|
(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";
|
import type { UpdateResult } from "mongodb";
|
||||||
|
|
||||||
export function did_update(result: UpdateResult): boolean {
|
export function did_update(result: UpdateResult): boolean {
|
||||||
return result.modifiedCount > 0;
|
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