updates to concierge bot to support adding services and routes
This commit is contained in:
@@ -12,22 +12,19 @@ DOTENV_PUBLIC_KEY_DEVELOPMENT="02572da3d4f3a844588a944214c0e142a5a01deaa6551456a
|
||||
DOTENV_PUBLIC_KEY="02292a330aa041b5f7efc51504e0c208accba67a6877a217ab43cbb59c3c0c3e66"
|
||||
|
||||
# .env
|
||||
DEBUG="encrypted:BMnswwe5JnAjCOEIHrmuuuOmcSKep3PBL9i1EPP+6/luAaY5Ad696SA6G1xvXV1xSf7CaIemi9y06hBVUD2mL0F1ZWYXB6LAtjQeGzG6/HnWdatUszmLg6eEkXQa5fHC+MkgnII="
|
||||
PORT="encrypted:BJxm0HAN4oxgITjzqsung1vfXRfUaHOUac1NPGeQFoKpSrGPmbvfD4fkIREyO+qsD68f+Swp0yCYiB6Z7crRepAxn9qQLK0UGAuI+JHMhRP0PuK/a3FyCMe+9L+XIaMs82SnrFc="
|
||||
NODE_ENV="encrypted:BKJvsZtYfKMgKzFSA6vBXj2insCZcUZrFUIYdcfd4ze5nG4qpgiOKpiBQQ6EAsrda03/wqV8xfOGfHExVx68+35+tjazC+0Qr/+YBebBvn9MGruLDYB4BeOA8H8Cl1EwW7MCULLoMn1aaS8d"
|
||||
LOG_LEVEL="encrypted:BD5xrc2gWbqC7kLwh9Nu9AeJh0+23WMARX878CEpASauF4o4udsLS4qYT1y9ayVHPvWD5Nj+yWhXhDO7/LU+MmtFH9lNS9lnJrZJcMIkTTGh8l854PdXC91RXFHx9xRvVORRcLYt"
|
||||
BASE_URL="encrypted:BMHCtunmFrbJgkqEHsYvbulEUkBFfB7HU1eL1Aldm4qKB7ao445FZ4v/tfwjh2P1lG+BLnJkYM3syubLmVwdtJO9JvGlYdQC+TFCtFYiQQAMjK+2pyQljt/NvhlVioHfe/k7jjSNR3IhWEeRmzyPrCHTcUo77tuLkHvGQXFbSQ=="
|
||||
EVE_CLIENT_ID="encrypted:BPZqIsv1pNA1W88QK+D4Tn2jJy6Ek/5YZT377LrG8R+zFUk/MIFQ9byCgDMIzsfjAyLwaHpiDggVKLYL7+REgsJ0+Qp8u9jWjOCFtP/Z+HqOnJi5H6ZtWCoWKVOHbMsYyjUD1u6w09hqkWDUSS859UWrno8SnA4O1gNThpawuiID"
|
||||
EVE_CLIENT_SECRET="encrypted:BCPsdV2aOikGdRsIZrEm+wlYo5c5/XlpCNJYWXDy+I8jYgtHsgCFeRSe7cyjOnMMxs/Wnu54xcBIzu+eOekSe6vzFBTN4DmJKc4TAROmuppUxpyAlhi+ZH6QJXNCix4kHftXVhgolaf8EfpeQYfVSjJAmJVWCF0483KoDdtX0IU1zOkq7as1EzHA6QWP"
|
||||
EVE_CALLBACK_URL="encrypted:BLWHVLxXGWYPmX/FAN0GBRq7mne/fjJRql8r0EZuHPrcNzOe9CxnplYlJrnUac6MpicWp81EDc5SKIfkKlDfMOAxQvHlAWQukEN7T4XMOr2LROdtoJPV/mg634foH670ZnIp0SoMrS2jziYCYIP15GjLlBc3uMD1G2lT/L+oYaI9chz4Gi7eJ8Uu04KMK5zTPw=="
|
||||
ESI_USER_AGENT="encrypted:BDSR40896Vx8+5v1VLL+Y1g7AofntT3Hky13zAM/8bO5OizB17WuJS6AGK18FiTKs76ZT7FJd8IOf++OvcPuLLlHAcq4r8W69v1fgK74Y0cpMw3eGd9+iapHGZKQJnTfKWhW33HSl+J1GqNRXCgGfzGN2BdCjDn4t4l/l5C/oSJega3f0zwt5xcLU/cH4meXpHx6CJF4FP0r3QYYY5eWvIPe+kETA4PlSmKcXivnWQA3qLk4P51/q+w="
|
||||
DISCORD_APP_ID="encrypted:BO6M18yRDBLEnb9sVWZM4KJyI6HXPEt6h+g3eJhkAPAiiiZqtftXdJ5kRWH4tbZSnyREiTyKwCZmu/79UEuEKrNM/t0IvVGcYRevkmIkQbcv7pmNdFGULWIuDiXwp7DI65o1Y7Lc+SyTZtF0w6xPn6k+fg=="
|
||||
DISCORD_APP_SECRET="encrypted:BCECawQcSwdBhWZD7u7fTir3vnISlzboluoP7HM4vIcor8HLq5FniVSrrahEi6FQ9/D7GnE1accQFHw5v05DMYGDC6Pk8MteVvNDBsb26D+9ysW+lPMS475mRapiAX5uxsyful61ndlexcbqffYdCbQz3sCCZ0V9T1qL6OmfUDcZ"
|
||||
DISCORD_PUBLIC_KEY="encrypted:BHiB0kNDdo7jkzGpLNLG7cZhM/x6kHR2xoo9Qq6/UptSCRdTbRIIreUh91nNzs34HKJHuIShS47F1gUF/4AgFawfvosNFWGLysQRw8/BO1jPQ7xkXkOPFvFRjtn8ofAKkLequwcq/tLTJdUnXk32pghLCnLFf+JLYkwZdIiqWNlPEm+DTa2d8GJe9j+ix6fOlI9FWsRo+cY0UPpDKXZ7KgU="
|
||||
DISCORD_BOT_TOKEN="encrypted:BI+BUi9br2kQ3dkmpLA+ZJG6m0ggwWJuBfsSEFOcaXctqOV9h3obbjbFf37UrKMXk4DdGobFCHWFc2gwygKwIyYV9mt6TSTNT3R3RbxV0wVwJHn66Ln7+Of9RaXQSr3rmLwMrKm23RiBuILTeqNaYdgrj2BJfNvCH4ld73jjglbfM0nrnuNZV3bi3IOiEfDizsLTy9nnVGHyd5hjDoE+LBbN6HH7QxI="
|
||||
DISCORD_TEST_GUILD_ID="encrypted:BOtjgCwLkmVwj1T5nqFpiIuf5p4HdRxk0En8PyVPjPR4ICeUCD44brUtcOZveysfadU+UVH0TfWUNmdozmEl1XDs045jaJa4tcQodrEqvUUyW0P0ZvKoRNQsVV/ZnBYcxtSLqPB2OBGKZlQuDy2M50gSPw=="
|
||||
JANICE_KEY="encrypted:BLHC4JqLJ3gjIXK7voNFQV89houZhR/d+3WT6hZZWaADlrTFTcmNl6bB0xd/yCjTUQ4w1SKl5IXptlidICaJpEHqc0vSTVZ7WHzI3QpZvTeUAYPQ6OF1yYKKv5ddwFDDDDTkQkAC+Kv3WMlEaHA05CVMybceQeqgCVal9/+xTTSG"
|
||||
PERPLEXITY_API_KEY="encrypted:BHagAU/l8HMkXMvgQOaz76bIv+kjPBpseTbJf9mRBbJWfGmq5zvI0kQL5OciiCSOIC9E+INPpWC5TrtACTkthrBxwQtq27bEw3QumnvLNn2S9jK/Y50u3iy9j7YL3LcsDd2SmnWSklmADPZP55TbdGOxRJO8EsI4WxYoppL/XLtT6Lwp7FjHpYX8ge7z7ROGhGANB+zf"
|
||||
STAR_KITTEN_KV_DB_PATH="encrypted:BBCp6CWMlFZoHM6aWTTJxV8RFpOoSYSwzH7VkHllQgkarnr+pitwAshI4K8JvYGfGLZOmiZshMRrQ1QsK5AbN4tij+rTnRO3yuq1kX5Nbdu1/77FeBZpaA7TXVG1Bj2QovWzdgongEUlew4lJGbv"
|
||||
SCOPES=encrypted:BDDahsMJtV00qzcrwCfdt4eaLikrMUQXzBU+n82EKWZDzvxPY7G6tifGQC9M3GEIpDCZQSBc5gkjiTspWg/taGRA4CxEAvmYVmiskGZ8t1ZE0RjQ24ulPzfg/R0aFfXZIsB4HTgk85PinRzT2RuxSwfzmz4bwQ1yGGVQRs46Oy5m5hS7LvnBV7jPuWIqixSkawL5n+5hrREFN3Lfpw==
|
||||
CONCIERGE_DB_PATH="encrypted:BNRvsmopAUFW1qFGJr1UuV0A7+/tZeVD6jhxt2JzZsfkiB8YKFoEOJuJU6k+3NYzIzDMCKdwvTa611u4dEVlWbQQ8yyHTra1YtU5JgZYd+SsPFlA02APnPgy8NN8oMhiCFkdYb1JSq8jDjkLTYbvwwenwJP99Q=="
|
||||
DISCORD_BOT_TOKEN="MTQ2MTc3OTk5NjE1NzY3NzY5OQ.GZmKnU.IXzBntbckjKADq-v7Osy-SxaMWsgnCCjFRKm34"
|
||||
DEBUG="true"
|
||||
PORT="3002"
|
||||
NODE_ENV="development"
|
||||
LOG_LEVEL="debug"
|
||||
BASE_URL="https://conciergefreight.space"
|
||||
EVE_CLIENT_ID="ec4eb1bbade045589ec32611f12919dd"
|
||||
EVE_CLIENT_SECRET="eat_KF93HYNqLHk3CJ8KijYQJVCcjfjs8EnV_WGG9J"
|
||||
EVE_CALLBACK_URL="https://dev.conciergefreight.space/auth/callback"
|
||||
ESI_USER_AGENT="Concierge Freight DEV/0.0.1 (concierge-freight-dev@f302.me; +https://git.f302.me/jb/star-kitten)"
|
||||
JANICE_KEY="DUyi5Q3Dod48IoswUBkEfNRs8Qf3cwNN"
|
||||
PERPLEXITY_API_KEY="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"
|
||||
STAR_KITTEN_KV_DB_PATH="data/dev-kv.db"
|
||||
SCOPES=["esi-contracts.read_corporation_contracts.v1","publicData"]
|
||||
CONCIERGE_DB_PATH="data/concierge-dev.db"
|
||||
ADMIN_USER_ID="106614950662791168"
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
DOTENV_PUBLIC_KEY_PRODUCTION="02f0469506f6722d8fcc179c199ff159ca32f082000c8e7a1465891adb50a4c031"
|
||||
|
||||
# .env.production
|
||||
DEBUG="encrypted:BJ05zNQ0KPsEKFER9ZlvQxEFJgc5rbw0k4j65AIPgyy/kZkV7prGEyaCtXZLmCUsqtM0NyMMEl7bbLcLeBmr2AbaR0+U7yBIqQnUi46uIV27vZO9fdfCC6Z4SiFaHUXfgl6s1S/Z"
|
||||
PORT="encrypted:BLPq+hz1+WPsCKxKEKFsK+EBvlf4iBwxfsjPN+FFSV078Bk+p8ihS2i5GrXd5JTIW9NJBeT4ZhnL5GXbKY5/iwoj7MmQe9WIYJ+SKBeZXXUyxGGfsE+Hd9u5XWRdbfYJQ8QCnI4="
|
||||
NODE_ENV="encrypted:BE+VACL1v6wLsm3Se5A+xajeH7a6LJ9gj1cdm5R+y6IlG92/p20XU9IBdWqJ00FnMB0cPZfPx2odnSq+TzcqOSYMCWFcgD4nC7suefU08EKa8A2YGxjO2WxkQo/EC7dQO+eIGlWzdimDS98="
|
||||
LOG_LEVEL="encrypted:BNXP0WNyTPrhszuDNaRsE9jFc51VtuUqfCs/EnCaP9iRvXmbekmsQzfbrNPSmHw9HBHWjPbzJUgFfebXgR2qd65L173luLUPOHu0wF5T0zaBc6zt9VdkQbJhdaDWN3FnHkWc4oM="
|
||||
BASE_URL="encrypted:BGY3awxPETBuzUz1uP+jJq4u9J9xumGjRGLtccdza6lDPCl7DNf3Tv/GjbfJPH1aXkqvOfGSs6Mj6X2Sv5cNfwJYpP67HoQuNn94g93JjkGesRpkgvLv8pOAB1RaS6F3SkGHosdGOex+wyYeVf5rNhY1vZA7B3SX"
|
||||
DISCORD_APP_ID="encrypted:BBV+j87Z6p/suAQ4HRdC4VOGyGNUhltobM3yaRLOC7SF0/XBw4bMx/OOpXE5qqfQdeyAhTpkEEzwH1BzaIiAZFJouMSyKYN/Gw1rbkB9LEzN9Yz6SuCZaub4ftwzZW5pJ8adzSjfm9JLFegmMO8MzJkoZU4="
|
||||
DISCORD_APP_SECRET="encrypted:BLC+chabTKr/7iLjutqOlA8r9vAn3DkGN14fUxgjRGs7udyvXUKXDYsVd8SQPC5/iraYL23+Qw8PBTnTh2P8SRq4tQq/jO0H8KHrJY+DfgjJqt2f3KK19rFvDvvEBWtvFIXwF1PrWcCrIF0T3IYn1Nq9/KRED6pbjK/HERF+q4RC"
|
||||
DISCORD_PUBLIC_KEY="encrypted:BAv92AM4VtQdyAqtLiCeFRuaMZ+6cazOMCNr6454p3PLIZDiMAbYEPzzIqyYZFWzMUJDTXx6c91I7dX33UZKG5vIB/tGiUrvHIRgnXXsbz4ZwXXYRZ0gDKzAFFyDaNk95RO8gZdvRdAAVUlTO/t2wlwEmGVj61jULNIdtuQBMa8tdl9XkhSAoq8O3oiHeKCPCCKU9QuiUJReU22KwZ0rPIk="
|
||||
DISCORD_BOT_TOKEN="encrypted:BOafG2kHKOp209oFlXUURj3yt7JLIOJbD9dChXFY1GKJMjV63LFBhyjZkpZsrXjcrc3r/FR026UlTiO1SIDxBLlHlla2yN3ip+jLl2wAD8jJWsch+HrQPH34G9C4Peo56wIptiUIr6ug9PqHqjAE5WClEJTFwSPPHgx1btHpoyxgWnqe7h0tbc2talmfOS/8xvJ+9TKRbL165MX/+HjPJI9+7kMqrHGNJA=="
|
||||
EVE_CLIENT_ID="encrypted:BPSEia/l0Aea+iX3Q5citAbtxkTBIFlBRwNhxoV4BVT4rbmGr0heJLb9ymS3srfHhlh6kra2oZzpH15UVyISL6lTxSi72CsvgsvX9cO8GdCUywSC94XBDLV5XjGMQ4vuL3ce3KDaWW+di28+7sxttAmU/b97F+547wpFkFnjb0ir"
|
||||
EVE_CLIENT_SECRET="encrypted:BGru3muBXbNenhZ+e4259tQOqELbhogNa5x0Yxxw2gbj7uiMb/KzzeaJ8WTBNFrlhS4NLKRE+EwAZp1LRKZVXMVAgCoF465c5zDZrHKaBi5SEjDnffKZOLzcpOeZgTbPMfFexGZqWuFgTtP2Bn2bu0p1MxXX5uEj++ZK2IfEONbHXzUnWRQYUts="
|
||||
EVE_CALLBACK_URL="encrypted:BCHObZ6cAfm/V79x2fhqnAAzinxyFpiRiQY/wojKQ5QJS8KEJ1FCc89Ee5tVBXDDxFRPaBwkj/g4blKpKWAWLl7s3LCZJCYpPoPIkrDOOMop1JFAMnVGrLbK6Ird2agVc+SkMbjUurffQ7pLrdhNQKK0y7vW5K6DzsoMu7klq7QiUFBbcfKMW5E5"
|
||||
ESI_USER_AGENT="encrypted:BC6tfyTm69Id4WT/csv81UxUUtmpZKoTwcV1HoZ1xSrx8+tJMIxnFVL4SxMcEa1pQXgpKgDDpSvoAaFZwndRHxSTZvfFvpoIZlUaljzzAdevUGh3+OhCFGvx9y8YwrlT4LB/L412sZD6NhgCX6rksU1iYREexj+7Kc54/sHsD7zYAIJ9y+PU+gvRDejx32oEhBEOdksnKplaTq2ApF3NCEBWt9eiB2rho6eltro="
|
||||
AUTH_DB_PATH="encrypted:BO7oCtnSoclMPTL8j/8HqQe+6p5+u4xWtEuScqPV+u1Wr/bPls9rd8DSohIwe0Y00nnhi/oSqnExCB0ip3rmQ1YA62ZfFxvmOmHwgk1MNHfCG6bE3NurHR2NE4BdDCvh+yOQ8LcN04V+Ef+tkyjKBD241H3MYmdw"
|
||||
JANICE_KEY="encrypted:BO4yawcMyniT7HH8apRtRv8uwNBFuQPRz3o8FPu7viTO+uGNMVPmoRKwI+mDjFc9JHRiIsnyOvjiOzDuojdWvoyKuilNKwpyuzkTCqjd2G7YaaYnurOkLZSllb2US/BvhN4Put04aqyGwpXyq2Ns34z080TjE0Q3oIJwgI6fSfR6"
|
||||
PERPLEXITY_API_KEY="encrypted:BCY8v0hPEk0n6VhTJuJZeff9XOZrwqqK77UqgF5PLTfwfiKUHLRUbj3e84FydRFGTRvRx3a0QqP2PAf0JgqCt5B9Xdop2curOTptmc2Z9wDoshMFl0X15xXQzFz4kMmeb3P1uJtB9RVsU1BMGMtX76wNcW9+vsNzu37PW+s0OrIJlXw3QicPYybzenQT6KUl9IMTkP+X"
|
||||
DEBUG="false"
|
||||
PORT="3000"
|
||||
NODE_ENV="production"
|
||||
LOG_LEVEL="info"
|
||||
BASE_URL="https://starkitten.cafe"
|
||||
DISCORD_APP_ID="1288711114388930601"
|
||||
DISCORD_APP_SECRET="HYK03ffTN3Cl7c0p4jqo2wl0y_AD4EQ-"
|
||||
DISCORD_PUBLIC_KEY="447bb2c27ad4127eba078b74f84c058205787df36b90e63de8b19e045fb9307f"
|
||||
DISCORD_BOT_TOKEN="MTI4ODcxMTExNDM4ODkzMDYwMQ.GqwYGA.EzZZP7heEHTkH7jrxFTp7FhIlnXT06AUhYLKHE"
|
||||
EVE_CLIENT_ID="3e12fdcfe611408d9cb499b0795b9fac"
|
||||
EVE_CLIENT_SECRET="b7ex0i8ZOLFWEaRThSFVCXk5KV7Z16NEbhneCXRk"
|
||||
EVE_CALLBACK_URL="https://starkitten.cafe/api/auth/callback"
|
||||
ESI_USER_AGENT="Star Kitten/0.0.1 (star-kitten@f302.me; +https://git.f302.me/jb/star-kitten)"
|
||||
AUTH_DB_PATH="/var/lib/litefs/auth.db"
|
||||
JANICE_KEY="DUyi5Q3Dod48IoswUBkEfNRs8Qf3cwNN"
|
||||
PERPLEXITY_API_KEY="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"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@projectdysnomia/dysnomia": "github:projectdysnomia/dysnomia#dev",
|
||||
"@star-kitten/lib": "workspace:^0.0.0"
|
||||
"@star-kitten/lib": "workspace:*"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "bunx dotenvx run -f .env.development -- bun run --watch src/main.ts",
|
||||
|
||||
126
packages/concierge-bot/src/commands/create-route.command.tsx
Normal file
126
packages/concierge-bot/src/commands/create-route.command.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import { getDB } from '@/lib/db';
|
||||
import { Constants } from '@projectdysnomia/dysnomia';
|
||||
import {
|
||||
createChatCommand,
|
||||
integerOption,
|
||||
stringOption,
|
||||
subCommandGroupOption,
|
||||
subCommandRouter,
|
||||
type CommandContext,
|
||||
type ExecutableInteraction,
|
||||
} from '@star-kitten/lib/discord';
|
||||
import { numberOption, subCommandOption } from '@star-kitten/lib/discord';
|
||||
|
||||
export default createChatCommand(
|
||||
{
|
||||
name: 'route',
|
||||
description: 'Routes',
|
||||
defaultMemberPermissions: Constants.Permissions.administrator,
|
||||
options: [
|
||||
subCommandGroupOption({
|
||||
name: 'group',
|
||||
description: 'a group',
|
||||
options: [
|
||||
subCommandOption({
|
||||
name: 'add',
|
||||
description: 'add a route',
|
||||
options: [
|
||||
stringOption({
|
||||
name: 'start',
|
||||
description: 'starting location',
|
||||
autocomplete: true,
|
||||
required: true,
|
||||
}),
|
||||
stringOption({
|
||||
name: 'end',
|
||||
description: 'end location',
|
||||
autocomplete: true,
|
||||
required: true,
|
||||
}),
|
||||
integerOption({
|
||||
name: 'isk-per-m3',
|
||||
description: 'ISK per m3',
|
||||
required: true,
|
||||
}),
|
||||
numberOption({
|
||||
name: 'collateral-percent',
|
||||
description: 'percentage of collateral to add onto the cost.',
|
||||
required: true,
|
||||
}),
|
||||
integerOption({
|
||||
name: 'max-volume',
|
||||
description: 'Maximum volume allowed for this route',
|
||||
required: true,
|
||||
}),
|
||||
integerOption({
|
||||
name: 'min-reward',
|
||||
description: 'Minimum required reward for this route',
|
||||
required: true,
|
||||
}),
|
||||
integerOption({
|
||||
name: 'expiration',
|
||||
description: 'Expiration the client should set on the contract',
|
||||
required: true,
|
||||
}),
|
||||
integerOption({
|
||||
name: 'completion',
|
||||
description: 'Days to complete time the client should set on the contract',
|
||||
required: true,
|
||||
}),
|
||||
integerOption({
|
||||
name: 'max-collateral',
|
||||
description: 'Maximum collateral allowed for this route',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
subCommandOption({
|
||||
name: 'remove',
|
||||
description: 'remove a route',
|
||||
options: [
|
||||
integerOption({
|
||||
name: 'id',
|
||||
description: 'ID of the route to remove',
|
||||
required: true,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
subCommandRouter({
|
||||
group: {
|
||||
add: async (interaction, ctx, data) => {
|
||||
console.log(`in add`);
|
||||
if (interaction.isAutocomplete()) {
|
||||
const focused = data.options?.find((opt) => opt.focused);
|
||||
console.log(`focused`, focused);
|
||||
if (focused) {
|
||||
switch (focused.name) {
|
||||
case 'start': {
|
||||
const locations = getDB().getAllLocations();
|
||||
console.log(JSON.stringify(locations.length));
|
||||
return await interaction.result(
|
||||
locations.map((l) => ({ name: l.short_name, value: String(l.location_id) })),
|
||||
);
|
||||
}
|
||||
case 'end': {
|
||||
const locations = getDB().getAllLocations();
|
||||
console.log(JSON.stringify(locations.length));
|
||||
return await interaction.result(
|
||||
locations.map((l) => ({ name: l.short_name, value: String(l.location_id) })),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
remove: (interaction, ctx) => {
|
||||
console.log('remove handler');
|
||||
if (interaction.isApplicationCommand()) {
|
||||
interaction.createMessage(`Thanks`);
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
4
packages/concierge-bot/src/commands/index.ts
Normal file
4
packages/concierge-bot/src/commands/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import './locations/command';
|
||||
import './quoute.command';
|
||||
import './time.command';
|
||||
import './create-route.command';
|
||||
@@ -1,220 +0,0 @@
|
||||
import { componentHasIdPrefix, isModalLabel, text } from '@star-kitten/lib/discord/components';
|
||||
import { createChatCommand, type CommandContext, type ExecutableInteraction } from '@star-kitten/lib/discord';
|
||||
import { PageType, usePages } from '@star-kitten/lib/discord/pages';
|
||||
import { StructureType, type Location } from '@/lib/db/location';
|
||||
import { getDB } from '@/lib/db';
|
||||
import { Constants, type ComponentInteractionSelectMenuData } from '@projectdysnomia/dysnomia';
|
||||
|
||||
interface LocationsState {
|
||||
selected?: Location;
|
||||
}
|
||||
|
||||
export default createChatCommand(
|
||||
{
|
||||
name: 'locations',
|
||||
description: 'location management',
|
||||
},
|
||||
async (interaction: ExecutableInteraction, commandCtx: CommandContext) => {
|
||||
await usePages<LocationsState>(
|
||||
{
|
||||
pages: {
|
||||
main: {
|
||||
key: 'main',
|
||||
type: PageType.MESSAGE,
|
||||
render: async (pageCtx) => {
|
||||
const locations = getDB().getAllLocations();
|
||||
console.log('Rendering locations page with locations:', locations);
|
||||
|
||||
const renderLocations = () => {
|
||||
if (locations.length === 0) {
|
||||
return 'No locations added yet.';
|
||||
}
|
||||
return locations
|
||||
.map(
|
||||
(loc) =>
|
||||
`${loc.location_id}\t${loc.short_name}\t${loc.can_jf ? 'JF' : ''}${loc.can_dst ? ' DST' : ''}${loc.can_br ? ' BR' : ''}${loc.can_smb ? ' SMB' : ''}${loc.can_bridge ? ' BRIDGE' : ''}`,
|
||||
)
|
||||
.join('\n');
|
||||
};
|
||||
|
||||
return (
|
||||
<container accent={0x11cc33}>
|
||||
<text>{`# Locations\n${renderLocations()}`}</text>
|
||||
|
||||
<actionRow>
|
||||
<stringSelect
|
||||
customId="edit-services"
|
||||
placeholder="Select Location to Edit Services"
|
||||
minValues={1}
|
||||
maxValues={1}
|
||||
>
|
||||
{locations.map((loc) => (
|
||||
<option label={loc.short_name} value={loc.location_id.toString()} />
|
||||
))}
|
||||
</stringSelect>
|
||||
</actionRow>
|
||||
<actionRow>
|
||||
<button customId="add-location" label="Add Location" style={Constants.ButtonStyles.PRIMARY} />
|
||||
</actionRow>
|
||||
</container>
|
||||
);
|
||||
},
|
||||
},
|
||||
'add-location': {
|
||||
key: 'add-location',
|
||||
type: PageType.MODAL,
|
||||
render: async (ctx) => {
|
||||
return (
|
||||
<modal title="Add Location" customId="add-location-modal">
|
||||
<label label="Location Name">
|
||||
<textInput customId="location-name" placeholder="Enter the location name" />
|
||||
</label>
|
||||
<label label="Location Short Name">
|
||||
<textInput customId="location-short-name" placeholder="Enter the location short name" />
|
||||
</label>
|
||||
<label label="Structure Type">
|
||||
<stringSelect
|
||||
customId="structure-type"
|
||||
placeholder="Select Structure Type"
|
||||
minValues={1}
|
||||
maxValues={1}
|
||||
>
|
||||
{Object.values(StructureType).map((type) => (
|
||||
<option label={type} value={type} />
|
||||
))}
|
||||
</stringSelect>
|
||||
</label>
|
||||
</modal>
|
||||
);
|
||||
},
|
||||
},
|
||||
'edit-services': {
|
||||
key: 'edit-services',
|
||||
type: PageType.MODAL,
|
||||
render: async (ctx) => {
|
||||
return (
|
||||
<modal
|
||||
title={`Edit Location Services at ${ctx.state.data.selected?.short_name || ''}:`}
|
||||
customId="edit-services-modal"
|
||||
>
|
||||
<label label="Can JF">
|
||||
<stringSelect customId="can-jf" placeholder="Can JF" minValues={1} maxValues={1}>
|
||||
<option label="Yes" value="yes" />
|
||||
<option label="No" value="no" />
|
||||
</stringSelect>
|
||||
</label>
|
||||
<label label="Can DST">
|
||||
<stringSelect customId="can-dst" placeholder="Can DST" minValues={1} maxValues={1}>
|
||||
<option label="Yes" value="yes" />
|
||||
<option label="No" value="no" />
|
||||
</stringSelect>
|
||||
</label>
|
||||
<label label="Can BR">
|
||||
<stringSelect customId="can-br" placeholder="Can BR" minValues={1} maxValues={1}>
|
||||
<option label="Yes" value="yes" />
|
||||
<option label="No" value="no" />
|
||||
</stringSelect>
|
||||
</label>
|
||||
<label label="Can SMB">
|
||||
<stringSelect customId="can-smb" placeholder="Can SMB" minValues={1} maxValues={1}>
|
||||
<option label="Yes" value="yes" />
|
||||
<option label="No" value="no" />
|
||||
</stringSelect>
|
||||
</label>
|
||||
<label label="Can Bridge">
|
||||
<stringSelect customId="can-bridge" placeholder="Can Bridge" minValues={1} maxValues={1}>
|
||||
<option label="Yes" value="yes" />
|
||||
<option label="No" value="no" />
|
||||
</stringSelect>
|
||||
</label>
|
||||
</modal>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
router: (ctx) => {
|
||||
if (ctx.custom_id === 'add-location-modal') {
|
||||
// Handle modal submission
|
||||
if (!interaction.isModalSubmit()) {
|
||||
throw new Error('Expected a modal submit interaction for add-location-modal');
|
||||
}
|
||||
|
||||
let locationName = ctx.interaction.data.components.find(
|
||||
(comp) => isModalLabel(comp) && componentHasIdPrefix(comp.component, 'location-name'),
|
||||
)?.component.value;
|
||||
let locationShortName = ctx.interaction.data.components.find(
|
||||
(comp) => isModalLabel(comp) && componentHasIdPrefix(comp.component, 'location-short-name'),
|
||||
)?.component.value;
|
||||
let structureTypeValue = ctx.interaction.data.components.find(
|
||||
(comp) => isModalLabel(comp) && componentHasIdPrefix(comp.component, 'structure-type'),
|
||||
)?.component as ComponentInteractionSelectMenuData;
|
||||
let structureType = structureTypeValue ? (structureTypeValue.values[0] as StructureType) : undefined;
|
||||
|
||||
if (locationName && locationShortName && structureType) {
|
||||
getDB().addLocation({
|
||||
name: locationName,
|
||||
short_name: locationShortName,
|
||||
structure_type: structureType,
|
||||
});
|
||||
}
|
||||
return 'main';
|
||||
}
|
||||
if (ctx.custom_id === 'add-location') {
|
||||
ctx.state.data.selected = getDB().getLocationById(ctx.interaction.data.values[0]);
|
||||
return 'add-location';
|
||||
}
|
||||
if (ctx.custom_id === 'edit-services') {
|
||||
if (!ctx.interaction.isMessageComponent()) {
|
||||
throw new Error('Expected a message component interaction for edit-services');
|
||||
}
|
||||
const data = ctx.interaction.data as ComponentInteractionSelectMenuData;
|
||||
const locationId = Number.parseInt(data.values[0]);
|
||||
const location = getDB().getLocationById(locationId);
|
||||
if (location) {
|
||||
ctx.state.data.selected = location;
|
||||
return 'edit-services';
|
||||
}
|
||||
}
|
||||
if (ctx.custom_id === 'edit-services-modal') {
|
||||
// Handle modal submission
|
||||
if (!interaction.isModalSubmit()) {
|
||||
throw new Error('Expected a modal submit interaction for edit-services-modal');
|
||||
}
|
||||
|
||||
const location = ctx.state.data.selected;
|
||||
if (!location) {
|
||||
return 'main';
|
||||
}
|
||||
|
||||
const getServiceValue = (serviceId: string) => {
|
||||
const comp = ctx.interaction.data.components.find(
|
||||
(c) => isModalLabel(c) && componentHasIdPrefix(c.component, serviceId),
|
||||
)?.component as ComponentInteractionSelectMenuData;
|
||||
return comp ? comp.values[0] === 'yes' : false;
|
||||
};
|
||||
|
||||
const can_jf = getServiceValue('can-jf');
|
||||
const can_dst = getServiceValue('can-dst');
|
||||
const can_br = getServiceValue('can-br');
|
||||
const can_smb = getServiceValue('can-smb');
|
||||
const can_bridge = getServiceValue('can-bridge');
|
||||
|
||||
getDB().updateLocation({
|
||||
...location,
|
||||
can_jf,
|
||||
can_dst,
|
||||
can_br,
|
||||
can_smb,
|
||||
can_bridge,
|
||||
});
|
||||
}
|
||||
return 'main';
|
||||
},
|
||||
initialPage: 'main',
|
||||
ephemeral: true,
|
||||
},
|
||||
interaction,
|
||||
commandCtx,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,48 @@
|
||||
import type { PageContext } from '@star-kitten/lib/discord';
|
||||
import type { LocationsState } from './state';
|
||||
import { Page } from './router';
|
||||
import { StructureType } from '@/lib/db/types/routes';
|
||||
|
||||
export default async function (ctx: PageContext<LocationsState>) {
|
||||
const isAdd = ctx.custom_id === Page.addLocationModal;
|
||||
const location = ctx.state.data.selected;
|
||||
return (
|
||||
<modal
|
||||
title={`${isAdd ? 'Add Location' : 'Edit: ' + ctx.state.data.selected?.short_name || ''}`}
|
||||
customId={isAdd ? Page.addLocationModalSubmit : Page.editLocationModalSubmit}
|
||||
>
|
||||
{isAdd && (
|
||||
<label label="Location ID">
|
||||
<textInput customId="loc-id" placeholder="Enter the structure id" required />
|
||||
</label>
|
||||
)}
|
||||
<label label="Location Name">
|
||||
<textInput customId="loc-name" placeholder="Enter the location name" required value={location?.name} />
|
||||
</label>
|
||||
<label label="Location Short Name">
|
||||
<textInput
|
||||
customId="loc-short-name"
|
||||
placeholder="Enter the location short name"
|
||||
required
|
||||
value={location?.short_name}
|
||||
/>
|
||||
</label>
|
||||
<label label="System">
|
||||
<textInput customId="loc-system" placeholder="Enter the system (e.g. Jita)" required value={location?.system} />
|
||||
</label>
|
||||
<label label="Structure Type">
|
||||
<stringSelect
|
||||
customId="loc-structure-type"
|
||||
placeholder="Select Structure Type"
|
||||
minValues={1}
|
||||
maxValues={1}
|
||||
required
|
||||
>
|
||||
{Object.values(StructureType).map((type) => (
|
||||
<option label={type} value={type} default={location?.structure_type === type} />
|
||||
))}
|
||||
</stringSelect>
|
||||
</label>
|
||||
</modal>
|
||||
);
|
||||
}
|
||||
62
packages/concierge-bot/src/commands/locations/command.ts
Normal file
62
packages/concierge-bot/src/commands/locations/command.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import {
|
||||
createChatCommand,
|
||||
type CommandContext,
|
||||
type ExecutableInteraction,
|
||||
PageType,
|
||||
usePages,
|
||||
hasUserId,
|
||||
PermissionType,
|
||||
} from '@star-kitten/lib/discord';
|
||||
import mainPage from './main.page';
|
||||
import addLocationModal from './add-location.modal';
|
||||
import editServicesModal from './edit-services.modal';
|
||||
import removeLocationModal from './remove-location.modal';
|
||||
import type { LocationsState } from './state';
|
||||
import router, { Page } from './router';
|
||||
import { Constants } from '@projectdysnomia/dysnomia';
|
||||
|
||||
export default createChatCommand(
|
||||
{
|
||||
name: 'locations',
|
||||
description: 'location management',
|
||||
defaultMemberPermissions: Constants.Permissions.administrator,
|
||||
},
|
||||
async (interaction: ExecutableInteraction, commandCtx: CommandContext) => {
|
||||
await usePages<LocationsState>(
|
||||
{
|
||||
pages: {
|
||||
[Page.main]: {
|
||||
key: Page.main,
|
||||
type: PageType.MESSAGE,
|
||||
render: mainPage,
|
||||
},
|
||||
[Page.addLocationModal]: {
|
||||
key: Page.addLocationModal,
|
||||
type: PageType.MODAL,
|
||||
render: addLocationModal,
|
||||
},
|
||||
[Page.editLocationModal]: {
|
||||
key: Page.editLocationModal,
|
||||
type: PageType.MODAL,
|
||||
render: addLocationModal,
|
||||
},
|
||||
[Page.editServicesModal]: {
|
||||
key: Page.editServicesModal,
|
||||
type: PageType.MODAL,
|
||||
render: editServicesModal,
|
||||
},
|
||||
[Page.removeLocationModal]: {
|
||||
key: Page.removeLocationModal,
|
||||
type: PageType.MODAL,
|
||||
render: removeLocationModal,
|
||||
},
|
||||
},
|
||||
router,
|
||||
initialPage: Page.main,
|
||||
ephemeral: true,
|
||||
},
|
||||
interaction,
|
||||
commandCtx,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,46 @@
|
||||
import type { PageContext } from '@star-kitten/lib/discord';
|
||||
import type { LocationsState } from './state';
|
||||
import { Page } from './router';
|
||||
import { locationSupportsType, RouteType } from '@/lib/db/types/routes';
|
||||
|
||||
export default function (ctx: PageContext<LocationsState>) {
|
||||
const location = ctx.state.data.selected!;
|
||||
return (
|
||||
<modal title={`Services: ${ctx.state.data.selected?.short_name || ''}`} customId={Page.editServicesModalSubmit}>
|
||||
<label label="Can JF">
|
||||
<stringSelect customId="can-jf" placeholder="Can JF" minValues={1} maxValues={1}>
|
||||
<option label="Yes" value={RouteType.JF + ''} default={locationSupportsType(location, RouteType.JF)} />
|
||||
<option label="No" value="0" default={!locationSupportsType(location, RouteType.JF)} />
|
||||
</stringSelect>
|
||||
</label>
|
||||
<label label="Can DST">
|
||||
<stringSelect customId="can-dst" placeholder="Can DST" minValues={1} maxValues={1}>
|
||||
<option label="Yes" value={RouteType.DST + ''} default={locationSupportsType(location, RouteType.DST)} />
|
||||
<option label="No" value="0" default={!locationSupportsType(location, RouteType.DST)} />
|
||||
</stringSelect>
|
||||
</label>
|
||||
<label label="Can BR">
|
||||
<stringSelect customId="can-br" placeholder="Can BR" minValues={1} maxValues={1}>
|
||||
<option label="Yes" value={RouteType.BR + ''} default={locationSupportsType(location, RouteType.BR)} />
|
||||
<option label="No" value="0" default={!locationSupportsType(location, RouteType.BR)} />
|
||||
</stringSelect>
|
||||
</label>
|
||||
<label label="Can SMB">
|
||||
<stringSelect customId="can-smb" placeholder="Can SMB" minValues={1} maxValues={1}>
|
||||
<option label="Yes" value={RouteType.SMB + ''} default={locationSupportsType(location, RouteType.SMB)} />
|
||||
<option label="No" value="0" default={!locationSupportsType(location, RouteType.SMB)} />
|
||||
</stringSelect>
|
||||
</label>
|
||||
<label label="Can Bridge">
|
||||
<stringSelect customId="can-bridge" placeholder="Can Bridge" minValues={1} maxValues={1}>
|
||||
<option
|
||||
label="Yes"
|
||||
value={RouteType.BRIDGE + ''}
|
||||
default={locationSupportsType(location, RouteType.BRIDGE)}
|
||||
/>
|
||||
<option label="No" value="0" default={!locationSupportsType(location, RouteType.BRIDGE)} />
|
||||
</stringSelect>
|
||||
</label>
|
||||
</modal>
|
||||
);
|
||||
}
|
||||
78
packages/concierge-bot/src/commands/locations/main.page.tsx
Normal file
78
packages/concierge-bot/src/commands/locations/main.page.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import { ButtonStyle, type PageContext } from '@star-kitten/lib/discord';
|
||||
import type { LocationsState } from './state';
|
||||
import { getDB } from '@/lib/db';
|
||||
import { Page } from './router';
|
||||
import { locationSupportsType, RouteType } from '@/lib/db/types/routes';
|
||||
|
||||
export default function (ctx: PageContext<LocationsState>) {
|
||||
const locations = getDB().getAllLocations();
|
||||
const hasLocations = locations.length > 0;
|
||||
|
||||
const renderLocations = () => {
|
||||
if (locations.length === 0) {
|
||||
return 'No locations added yet.';
|
||||
}
|
||||
return locations
|
||||
.map(
|
||||
(loc) =>
|
||||
`${loc.location_id}\t|\t${loc.short_name}\t|\t${locationSupportsType(loc, RouteType.JF) ? 'JF' : ''}${locationSupportsType(loc, RouteType.DST) ? ', DST' : ''}${locationSupportsType(loc, RouteType.BR) ? ', BR' : ''}${locationSupportsType(loc, RouteType.SMB) ? ', SMB' : ''}${locationSupportsType(loc, RouteType.BRIDGE) ? ', BRIDGE' : ''}`,
|
||||
)
|
||||
.join('\n');
|
||||
};
|
||||
|
||||
if (!hasLocations) {
|
||||
return (
|
||||
<container accent={0x11cc33}>
|
||||
<text>{`# Locations\nNo locations added yet.`}</text>
|
||||
<actionRow>
|
||||
<button customId={Page.addLocationModal} label="Add Location" style={ButtonStyle.PRIMARY} />
|
||||
</actionRow>
|
||||
</container>
|
||||
);
|
||||
}
|
||||
|
||||
const locationOptions = locations.map((loc) => <option label={loc.short_name} value={loc.location_id.toString()} />);
|
||||
|
||||
return (
|
||||
<container accent={0x11cc33}>
|
||||
<text>{`# Locations\n${renderLocations()}`}</text>
|
||||
<actionRow>
|
||||
<button customId={Page.addLocationModal} label="Add Location" style={ButtonStyle.PRIMARY} />
|
||||
</actionRow>
|
||||
|
||||
<text>{`## Edit services at`}</text>
|
||||
<actionRow>
|
||||
<stringSelect
|
||||
customId={Page.editServicesModal}
|
||||
placeholder="Select location to edit services"
|
||||
minValues={1}
|
||||
maxValues={1}
|
||||
>
|
||||
{locationOptions}
|
||||
</stringSelect>
|
||||
</actionRow>
|
||||
<text>{`## Edit location details`}</text>
|
||||
<actionRow>
|
||||
<stringSelect
|
||||
customId={Page.editLocationModal}
|
||||
placeholder="Select location to edit"
|
||||
minValues={1}
|
||||
maxValues={1}
|
||||
>
|
||||
{locationOptions}
|
||||
</stringSelect>
|
||||
</actionRow>
|
||||
<text>{`## Remove location`}</text>
|
||||
<actionRow>
|
||||
<stringSelect
|
||||
customId={Page.removeLocationModal}
|
||||
placeholder="Select location to remove"
|
||||
minValues={1}
|
||||
maxValues={1}
|
||||
>
|
||||
{locationOptions}
|
||||
</stringSelect>
|
||||
</actionRow>
|
||||
</container>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { PageContext } from '@star-kitten/lib/discord';
|
||||
import type { LocationsState } from './state';
|
||||
import { Page } from './router';
|
||||
|
||||
export default function (ctx: PageContext<LocationsState>) {
|
||||
return (
|
||||
<modal title={`Remove ${ctx.state.data.selected?.short_name || ''}?`} customId={Page.removeLocationModalSubmit}>
|
||||
<text>{`# Are you sure?\n\nConfrim that you want remove **${ctx.state.data.selected.name}**.\n\n*This action cannot be undone. Click submit to confirm.*`}</text>
|
||||
</modal>
|
||||
);
|
||||
}
|
||||
140
packages/concierge-bot/src/commands/locations/router.ts
Normal file
140
packages/concierge-bot/src/commands/locations/router.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import * as StarKitten from '@star-kitten/lib/discord';
|
||||
import type { LocationsState } from './state';
|
||||
import { getDB } from '@/lib/db';
|
||||
import type { StructureType } from '@/lib/db/types/routes';
|
||||
|
||||
export enum Page {
|
||||
main = 'main',
|
||||
addLocationModal = 'add-location-modal',
|
||||
addLocationModalSubmit = 'add-location-modal-submit',
|
||||
editLocationModal = 'edit-location-modal',
|
||||
editLocationModalSubmit = 'edit-location-modal-submit',
|
||||
editServicesModal = 'edit-services-modal',
|
||||
editServicesModalSubmit = 'edit-services-modal-submit',
|
||||
removeLocationModal = 'remove-location-modal',
|
||||
removeLocationModalSubmit = 'remove-location-modal-submit',
|
||||
}
|
||||
|
||||
export default function (ctx: StarKitten.PageContext<LocationsState>): Page {
|
||||
switch (ctx.custom_id) {
|
||||
case Page.addLocationModal:
|
||||
ctx.state.data.selected = undefined;
|
||||
return Page.addLocationModal;
|
||||
|
||||
case Page.editLocationModalSubmit:
|
||||
case Page.addLocationModalSubmit: {
|
||||
if (!ctx.interaction.isModalSubmit()) {
|
||||
throw new Error('Expected a modal submit interaction.');
|
||||
}
|
||||
|
||||
const location: any = {};
|
||||
for (const component of ctx.interaction.data.components) {
|
||||
if (StarKitten.isModalLabel(component)) {
|
||||
if (StarKitten.isModalTextInput(component.component)) {
|
||||
if (StarKitten.componentHasIdPrefix(component.component, 'loc-id')) {
|
||||
location.location_id = component.component.value.trim();
|
||||
} else if (StarKitten.componentHasIdPrefix(component.component, 'loc-name')) {
|
||||
location.name = component.component.value.trim();
|
||||
} else if (StarKitten.componentHasIdPrefix(component.component, 'loc-short-name')) {
|
||||
location.short_name = component.component.value.trim();
|
||||
} else if (StarKitten.componentHasIdPrefix(component.component, 'loc-system')) {
|
||||
location.system = component.component.value.trim();
|
||||
}
|
||||
} else if (
|
||||
StarKitten.isStringSelectMenu(component.component) &&
|
||||
StarKitten.componentHasIdPrefix(component.component, 'loc-structure-type')
|
||||
) {
|
||||
location.structure_type = component.component.values[0] as StructureType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.custom_id === Page.addLocationModalSubmit ? getDB().addLocation(location) : getDB().updateLocation(location);
|
||||
ctx.state.data.selected = undefined;
|
||||
return Page.main;
|
||||
}
|
||||
|
||||
case Page.editLocationModal: {
|
||||
if (!ctx.interaction.isSelectMenu()) {
|
||||
console.error('Expected a message component interaction.');
|
||||
return Page.main;
|
||||
}
|
||||
const data = ctx.interaction.data;
|
||||
const locationId = Number.parseInt(data.values[0]);
|
||||
const location = getDB().getLocationById(locationId);
|
||||
if (location) {
|
||||
ctx.state.data.selected = location;
|
||||
return Page.editLocationModal;
|
||||
}
|
||||
return Page.main;
|
||||
}
|
||||
|
||||
case Page.editServicesModal: {
|
||||
if (!ctx.interaction.isSelectMenu()) {
|
||||
console.error('Expected a message component interaction.');
|
||||
return Page.main;
|
||||
}
|
||||
const data = ctx.interaction.data;
|
||||
const locationId = Number.parseInt(data.values[0]);
|
||||
const location = getDB().getLocationById(locationId);
|
||||
if (location) {
|
||||
ctx.state.data.selected = location;
|
||||
return Page.editServicesModal;
|
||||
}
|
||||
return Page.main;
|
||||
}
|
||||
|
||||
case Page.editServicesModalSubmit: {
|
||||
if (ctx.interaction.isModalSubmit()) {
|
||||
const location = ctx.state.data.selected;
|
||||
if (!location) {
|
||||
return Page.main;
|
||||
}
|
||||
|
||||
let supported_route_types = 0;
|
||||
for (const component of ctx.interaction.data.components) {
|
||||
if (StarKitten.isModalLabel(component) && StarKitten.isStringSelectMenu(component.component)) {
|
||||
supported_route_types = supported_route_types | parseInt(component.component.values[0]);
|
||||
}
|
||||
}
|
||||
|
||||
getDB().updateLocation({
|
||||
...location,
|
||||
supported_route_types,
|
||||
});
|
||||
}
|
||||
ctx.state.data.selected = undefined;
|
||||
return Page.main;
|
||||
}
|
||||
|
||||
case Page.removeLocationModal: {
|
||||
if (!ctx.interaction.isSelectMenu()) {
|
||||
console.error('Expected a message component interaction.');
|
||||
return Page.main;
|
||||
}
|
||||
const data = ctx.interaction.data;
|
||||
const locationId = Number.parseInt(data.values[0]);
|
||||
const location = getDB().getLocationById(locationId);
|
||||
if (location) {
|
||||
ctx.state.data.selected = location;
|
||||
return Page.removeLocationModal;
|
||||
}
|
||||
return Page.main;
|
||||
}
|
||||
|
||||
case Page.removeLocationModalSubmit: {
|
||||
if (ctx.interaction.isModalSubmit()) {
|
||||
const location = ctx.state.data.selected;
|
||||
if (!location) {
|
||||
return Page.main;
|
||||
}
|
||||
getDB().removeLocation(location.location_id);
|
||||
}
|
||||
ctx.state.data.selected = undefined;
|
||||
return Page.main;
|
||||
}
|
||||
|
||||
default:
|
||||
return Page.main;
|
||||
}
|
||||
}
|
||||
5
packages/concierge-bot/src/commands/locations/state.ts
Normal file
5
packages/concierge-bot/src/commands/locations/state.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { Location } from '@/lib/db';
|
||||
|
||||
export interface LocationsState {
|
||||
selected?: Location;
|
||||
}
|
||||
@@ -4,15 +4,9 @@ import {
|
||||
type ComponentInteractionSelectMenuData,
|
||||
} from '@projectdysnomia/dysnomia';
|
||||
import { appraiseItems, type Appraisal } from '@star-kitten/lib/eve/third-party/janice.js';
|
||||
import {
|
||||
componentHasIdPrefix,
|
||||
isModalLabel,
|
||||
isModalSelect,
|
||||
isModalTextInput,
|
||||
} from '@star-kitten/lib/discord/components';
|
||||
import type { CommandContext, ExecutableInteraction } from '@star-kitten/lib/discord';
|
||||
import { componentHasIdPrefix, isModalLabel, isModalTextInput } from '@star-kitten/lib/discord';
|
||||
import { createChatCommand, type CommandContext, type ExecutableInteraction } from '@star-kitten/lib/discord';
|
||||
import { PageType, usePages } from '@star-kitten/lib/discord/pages';
|
||||
import { serve } from 'bun';
|
||||
// import { renderAppraisal } from './renderAppraisal';
|
||||
// import { renderAppraisalModal } from './renderAppraisalModal';
|
||||
|
||||
@@ -131,7 +125,7 @@ function uniqueDestinationForOriginAndType(typeId: number, originId?: number) {
|
||||
}
|
||||
|
||||
async function execute(interaction: ExecutableInteraction, ctx: CommandContext) {
|
||||
return await usePages<QuouteState>(
|
||||
await usePages<QuouteState>(
|
||||
{
|
||||
pages: {
|
||||
main: {
|
||||
@@ -242,7 +236,4 @@ Mexallon 2444`}
|
||||
);
|
||||
}
|
||||
|
||||
export default {
|
||||
definition,
|
||||
execute,
|
||||
};
|
||||
export default createChatCommand(definition, execute);
|
||||
|
||||
@@ -1,32 +1,4 @@
|
||||
import {
|
||||
type ExecutableInteraction,
|
||||
type CommandContext,
|
||||
Locale,
|
||||
type ChatCommandDefinition,
|
||||
} from '@star-kitten/lib/discord';
|
||||
|
||||
const definition: ChatCommandDefinition = {
|
||||
name: 'time',
|
||||
nameLocalizations: {
|
||||
[Locale.DE]: 'zeit',
|
||||
[Locale.ES_ES]: 'hora',
|
||||
[Locale.FR]: 'heure',
|
||||
[Locale.JA]: '時間',
|
||||
[Locale.KO]: '시간',
|
||||
[Locale.RU]: 'время',
|
||||
[Locale.ZH_CN]: '时间',
|
||||
},
|
||||
description: 'Get the current EVE time',
|
||||
descriptionLocalizations: {
|
||||
[Locale.DE]: 'Holen Sie sich die aktuelle EVE-Zeit',
|
||||
[Locale.ES_ES]: 'Obtén la hora actual de EVE',
|
||||
[Locale.FR]: "Obtenez l'heure actuelle d'EVE",
|
||||
[Locale.JA]: '現在のEVE時間を取得します',
|
||||
[Locale.KO]: '현재 EVE 시간을 가져옵니다',
|
||||
[Locale.RU]: 'Получите текущее время EVE',
|
||||
[Locale.ZH_CN]: '获取当前的EVE时间',
|
||||
},
|
||||
};
|
||||
import { type ExecutableInteraction, type CommandContext, Locale, createChatCommand } from '@star-kitten/lib/discord';
|
||||
|
||||
const eveTimeText = {
|
||||
[Locale.EN_US]: 'EVE Time',
|
||||
@@ -40,38 +12,50 @@ const eveTimeText = {
|
||||
[Locale.ZH_CN]: 'EVE时间',
|
||||
};
|
||||
|
||||
function jsx(component: any) {
|
||||
return {
|
||||
flags: 2,
|
||||
components: [component],
|
||||
};
|
||||
}
|
||||
export default createChatCommand(
|
||||
{
|
||||
name: 'time',
|
||||
nameLocalizations: {
|
||||
[Locale.DE]: 'zeit',
|
||||
[Locale.ES_ES]: 'hora',
|
||||
[Locale.FR]: 'heure',
|
||||
[Locale.JA]: '時間',
|
||||
[Locale.KO]: '시간',
|
||||
[Locale.RU]: 'время',
|
||||
[Locale.ZH_CN]: '时间',
|
||||
},
|
||||
description: 'Get the current EVE time',
|
||||
descriptionLocalizations: {
|
||||
[Locale.DE]: 'Holen Sie sich die aktuelle EVE-Zeit',
|
||||
[Locale.ES_ES]: 'Obtén la hora actual de EVE',
|
||||
[Locale.FR]: "Obtenez l'heure actuelle d'EVE",
|
||||
[Locale.JA]: '現在のEVE時間を取得します',
|
||||
[Locale.KO]: '현재 EVE 시간을 가져옵니다',
|
||||
[Locale.RU]: 'Получите текущее время EVE',
|
||||
[Locale.ZH_CN]: '获取当前的EVE时间',
|
||||
},
|
||||
},
|
||||
(interaction: ExecutableInteraction, ctx: CommandContext) => {
|
||||
if (!interaction.isApplicationCommand()) return;
|
||||
|
||||
async function execute(interaction: ExecutableInteraction, ctx: CommandContext) {
|
||||
if (!interaction.isApplicationCommand()) return;
|
||||
const now = new Date();
|
||||
const eveTime = now.toISOString().split('T')[1].split('.')[0];
|
||||
const eveDate = now.toLocaleDateString(interaction.locale, {
|
||||
timeZone: 'UTC',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: '2-digit',
|
||||
weekday: 'long',
|
||||
});
|
||||
|
||||
const now = new Date();
|
||||
const eveTime = now.toISOString().split('T')[1].split('.')[0];
|
||||
const eveDate = now.toLocaleDateString(interaction.locale, {
|
||||
timeZone: 'UTC',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: '2-digit',
|
||||
weekday: 'long',
|
||||
});
|
||||
|
||||
interaction.createJSXMessage(
|
||||
<container>
|
||||
<text>
|
||||
{`### ${eveTimeText[interaction.locale] || eveTimeText[Locale.EN_US]}
|
||||
interaction.createJSXMessage(
|
||||
<container>
|
||||
<text>
|
||||
{`### ${eveTimeText[interaction.locale] || eveTimeText[Locale.EN_US]}
|
||||
${eveTime}
|
||||
${eveDate}`}
|
||||
</text>
|
||||
</container>,
|
||||
);
|
||||
}
|
||||
|
||||
export default {
|
||||
definition,
|
||||
execute,
|
||||
};
|
||||
</text>
|
||||
</container>,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Database } from 'bun:sqlite';
|
||||
import locationTables, * as locationQueries from './location';
|
||||
export * from './location';
|
||||
|
||||
let db: Database = undefined;
|
||||
const queries = {
|
||||
|
||||
@@ -1,44 +1,19 @@
|
||||
import type { Database } from 'bun:sqlite';
|
||||
import { dynamicInsert, dynamicUpdate, remove, select, type QueryOptions } from '@star-kitten/lib/util/sqlite.js';
|
||||
import type { Location } from './types/routes';
|
||||
|
||||
const TABLE_NAME = 'locations';
|
||||
|
||||
export enum StructureType {
|
||||
NPC = 'NPC',
|
||||
Keepstar = 'Keepstar',
|
||||
Fortizar = 'Fortizar',
|
||||
Astrahus = 'Astrahus',
|
||||
Sotiyo = 'Sotiyo',
|
||||
Azbel = 'Azbel',
|
||||
Raitaru = 'Raitaru',
|
||||
Athanor = 'Athanor',
|
||||
Tatara = 'Tatara',
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
location_id: number;
|
||||
name: string;
|
||||
short_name: string;
|
||||
structure_type: StructureType;
|
||||
can_jf?: boolean;
|
||||
can_dst?: boolean;
|
||||
can_br?: boolean;
|
||||
can_smb?: boolean;
|
||||
can_bridge?: boolean;
|
||||
}
|
||||
|
||||
export default {
|
||||
createTable: (db: Database) => {
|
||||
db.run(
|
||||
`CREATE TABLE IF NOT EXISTS ${TABLE_NAME} (
|
||||
location_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
location_id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
short_name TEXT NOT NULL,
|
||||
structure_type TEXT NOT NULL,
|
||||
can_jf BOOLEAN NOT NULL DEFAULT 0,
|
||||
can_dst BOOLEAN NOT NULL DEFAULT 0,
|
||||
can_br BOOLEAN NOT NULL DEFAULT 0,
|
||||
can_smb BOOLEAN NOT NULL DEFAULT 0,
|
||||
can_bridge BOOLEAN NOT NULL DEFAULT 0
|
||||
system TEXT NOT NULL,
|
||||
supported_route_types INT NOT NULL DEFAULT 0
|
||||
)`,
|
||||
);
|
||||
},
|
||||
@@ -48,56 +23,24 @@ export default {
|
||||
},
|
||||
};
|
||||
|
||||
export function addLocation(db: Database, location: Omit<Location, 'location_id'>) {
|
||||
const stmt = db.prepare(
|
||||
`INSERT INTO ${TABLE_NAME} (name, short_name, structure_type, can_jf, can_dst, can_br, can_smb, can_bridge)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
);
|
||||
const result = stmt.run(
|
||||
location.name,
|
||||
location.short_name,
|
||||
location.structure_type,
|
||||
location.can_jf ? 1 : 0,
|
||||
location.can_dst ? 1 : 0,
|
||||
location.can_br ? 1 : 0,
|
||||
location.can_smb ? 1 : 0,
|
||||
location.can_bridge ? 1 : 0,
|
||||
);
|
||||
return result.lastInsertRowid as number;
|
||||
export function addLocation(db: Database, location: Location) {
|
||||
return dynamicInsert(db, TABLE_NAME, location);
|
||||
}
|
||||
|
||||
export function updateLocation(db: Database, location: Location) {
|
||||
const stmt = db.prepare(
|
||||
`UPDATE ${TABLE_NAME}
|
||||
SET name = ?, short_name = ?, structure_type = ?, can_jf = ?, can_dst = ?, can_br = ?, can_smb = ?, can_bridge = ?
|
||||
WHERE location_id = ?`,
|
||||
);
|
||||
stmt.run(
|
||||
location.name,
|
||||
location.short_name,
|
||||
location.structure_type,
|
||||
location.can_jf ? 1 : 0,
|
||||
location.can_dst ? 1 : 0,
|
||||
location.can_br ? 1 : 0,
|
||||
location.can_smb ? 1 : 0,
|
||||
location.can_bridge ? 1 : 0,
|
||||
location.location_id,
|
||||
);
|
||||
const id = location.location_id;
|
||||
delete location.location_id;
|
||||
return dynamicUpdate(db, TABLE_NAME, location, 'location_id', id);
|
||||
}
|
||||
|
||||
export function getLocationById(db: Database, locationId: number): Location | null {
|
||||
const stmt = db.prepare(`SELECT * FROM ${TABLE_NAME} WHERE location_id = ?`);
|
||||
const row = stmt.get(locationId) as Location | undefined;
|
||||
return row || null;
|
||||
export function getLocationById(db: Database, location_id: number) {
|
||||
return select<Location>(db, TABLE_NAME, {}, '*', { location_id })?.[0];
|
||||
}
|
||||
|
||||
export function getAllLocations(db: Database): Location[] {
|
||||
const stmt = db.prepare(`SELECT * FROM ${TABLE_NAME}`);
|
||||
const rows = stmt.all() as Location[];
|
||||
return rows;
|
||||
export function getAllLocations(db: Database, options?: QueryOptions<Location>): Location[] {
|
||||
return select<Location>(db, TABLE_NAME, options);
|
||||
}
|
||||
|
||||
export function deleteLocation(db: Database, locationId: number) {
|
||||
const stmt = db.prepare(`DELETE FROM ${TABLE_NAME} WHERE location_id = ?`);
|
||||
stmt.run(locationId);
|
||||
export function removeLocation(db: Database, location_id: number) {
|
||||
return remove<Location>(db, TABLE_NAME, { location_id });
|
||||
}
|
||||
|
||||
51
packages/concierge-bot/src/lib/db/route.ts
Normal file
51
packages/concierge-bot/src/lib/db/route.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import type { Database } from 'bun:sqlite';
|
||||
import { dynamicInsert, dynamicUpdate, remove, select, type QueryOptions } from '@star-kitten/lib/util/sqlite.js';
|
||||
import type { Route } from './types/routes';
|
||||
|
||||
const TABLE_NAME = 'routes';
|
||||
|
||||
export default {
|
||||
createTable: (db: Database) => {
|
||||
db.run(
|
||||
`CREATE TABLE IF NOT EXISTS ${TABLE_NAME} (
|
||||
route_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
start_location_id INTEGER NOT NULL,
|
||||
end_location_id INTEGER NOT NULL,
|
||||
isk_per_m3 INTEGER NOT NULL,
|
||||
collat_pct REAL NOT NULL,
|
||||
max_volume INTEGER NOT NULL,
|
||||
min_reward INTEGER NOT NULL,
|
||||
expiration INTEGER NOT NULL,
|
||||
completion INTEGER NOT NULL,
|
||||
max_collateral INTEGER
|
||||
)
|
||||
`,
|
||||
);
|
||||
},
|
||||
|
||||
dropTable: (db: Database) => {
|
||||
db.run(`DROP TABLE IF EXISTS ${TABLE_NAME}`);
|
||||
},
|
||||
};
|
||||
|
||||
export function addRoute(db: Database, route: Omit<Route, 'route_id'>) {
|
||||
return dynamicInsert(db, TABLE_NAME, route);
|
||||
}
|
||||
|
||||
export function updateLocation(db: Database, location: Route) {
|
||||
const id = location.route_id;
|
||||
delete location.route_id;
|
||||
return dynamicUpdate(db, TABLE_NAME, location, 'route_id', id);
|
||||
}
|
||||
|
||||
export function getRoutes(db: Database, options?: QueryOptions<Route>) {
|
||||
return select<Route>(db, TABLE_NAME, options);
|
||||
}
|
||||
|
||||
export function getRoute(db: Database, route_id: number) {
|
||||
return select<Route>(db, TABLE_NAME, {}, '*', { route_id })?.[0];
|
||||
}
|
||||
|
||||
export function removeRoute(db: Database, route_id: number) {
|
||||
return remove<Route>(db, TABLE_NAME, { route_id });
|
||||
}
|
||||
10
packages/concierge-bot/src/lib/db/types/courier-contract.ts
Normal file
10
packages/concierge-bot/src/lib/db/types/courier-contract.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { ContractStatus } from '@star-kitten/lib/eve';
|
||||
|
||||
export interface CourierContract {
|
||||
concierge_id: number; // internal id to track this db record
|
||||
contract_id: number; // id of the contract for this courier
|
||||
assigned_to: number;
|
||||
received: string;
|
||||
last_updated: string;
|
||||
status: ContractStatus;
|
||||
}
|
||||
45
packages/concierge-bot/src/lib/db/types/routes.ts
Normal file
45
packages/concierge-bot/src/lib/db/types/routes.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
export enum RouteType {
|
||||
JF = 1 << 0,
|
||||
DST = 1 << 1,
|
||||
BR = 1 << 2,
|
||||
SMB = 1 << 3,
|
||||
BRIDGE = 1 << 4,
|
||||
}
|
||||
|
||||
export enum StructureType {
|
||||
NPC = 'NPC',
|
||||
Keepstar = 'Keepstar',
|
||||
Fortizar = 'Fortizar',
|
||||
Astrahus = 'Astrahus',
|
||||
Sotiyo = 'Sotiyo',
|
||||
Azbel = 'Azbel',
|
||||
Raitaru = 'Raitaru',
|
||||
Athanor = 'Athanor',
|
||||
Tatara = 'Tatara',
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
location_id: number;
|
||||
name: string;
|
||||
short_name: string;
|
||||
structure_type: StructureType;
|
||||
system: string;
|
||||
supported_route_types: number;
|
||||
}
|
||||
|
||||
export interface Route {
|
||||
route_id: number;
|
||||
start_location_id: number;
|
||||
end_location_id: number;
|
||||
isk_per_m3: number;
|
||||
collat_pct: number; // collateral percent as a float, 1.5 = 1.5%
|
||||
max_volume: number;
|
||||
min_reward: number;
|
||||
expiration: number;
|
||||
completion: number;
|
||||
max_collateral: number;
|
||||
}
|
||||
|
||||
export function locationSupportsType(loc: Location, rt: RouteType) {
|
||||
return (loc.supported_route_types & rt) !== 0;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { startBot } from "@star-kitten/lib/discord";
|
||||
import { startBot } from '@star-kitten/lib/discord';
|
||||
import './commands';
|
||||
|
||||
startBot();
|
||||
|
||||
Reference in New Issue
Block a user