Once and for all reformat.

Will be using black code formatter
This commit is contained in:
Emily Doherty 2024-12-08 17:07:26 -08:00
parent 3a06464c29
commit 34badf17eb
25 changed files with 359 additions and 295 deletions

View File

@ -3,6 +3,7 @@ aiohttp==3.9.5
aiosignal==1.3.1 aiosignal==1.3.1
anyio==4.4.0 anyio==4.4.0
attrs==23.2.0 attrs==23.2.0
black==24.10.0
certifi==2024.7.4 certifi==2024.7.4
croniter==2.0.5 croniter==2.0.5
discord-py-interactions==5.12.1 discord-py-interactions==5.12.1

View File

@ -11,7 +11,9 @@ from token_bot.persistant_database import database as pdb
class AlertsController: class AlertsController:
def __init__(self, session: aiohttp.ClientSession): def __init__(self, session: aiohttp.ClientSession):
self._pdb: pdb.Database = pdb.Database(session) self._pdb: pdb.Database = pdb.Database(session)
self.table = aiodynamo.client.Table = self._pdb.client.table(os.getenv('ALERTS_TABLE')) self.table = aiodynamo.client.Table = self._pdb.client.table(
os.getenv("ALERTS_TABLE")
)
@staticmethod @staticmethod
def _user_to_obj(user: int | User) -> User: def _user_to_obj(user: int | User) -> User:
@ -39,5 +41,3 @@ class AlertsController:
alert = self._alert_to_obj(alert) alert = self._alert_to_obj(alert)
user = self._user_to_obj(user) user = self._user_to_obj(user)
await alert.remove_user(self.table, user) await alert.remove_user(self.table, user)

View File

@ -11,8 +11,9 @@ from token_bot.persistant_database.user_schema import User
class UsersController: class UsersController:
def __init__(self, session: aiohttp.ClientSession): def __init__(self, session: aiohttp.ClientSession):
self._pdb: pdb.Database = pdb.Database(session) self._pdb: pdb.Database = pdb.Database(session)
self.table: aiodynamo.client.Table = self._pdb.client.table(os.getenv('USERS_TABLE')) self.table: aiodynamo.client.Table = self._pdb.client.table(
os.getenv("USERS_TABLE")
)
@staticmethod @staticmethod
def _user_to_obj(user: int | User) -> User: def _user_to_obj(user: int | User) -> User:
@ -67,4 +68,3 @@ class UsersController:
await user.get(self.table) await user.get(self.table)
user.subscribed_alerts.remove(alert) user.subscribed_alerts.remove(alert)
await user.put(self.table) await user.put(self.table)

View File

@ -16,7 +16,9 @@ class History:
self._latest_price_datum: Tuple[datetime.datetime, int] | None = None self._latest_price_datum: Tuple[datetime.datetime, int] | None = None
self._update_triggers: List[UpdateTrigger] = [] self._update_triggers: List[UpdateTrigger] = []
for alert_type in AlertType: for alert_type in AlertType:
self._update_triggers.append(UpdateTrigger(Alert(alert_type, flavor, self._region))) self._update_triggers.append(
UpdateTrigger(Alert(alert_type, flavor, self._region))
)
@property @property
def flavor(self) -> Flavor: def flavor(self) -> Flavor:
@ -58,5 +60,3 @@ class History:
if trigger.alert == alert: if trigger.alert == alert:
return trigger return trigger
raise ValueError raise ValueError

View File

@ -9,7 +9,8 @@ from token_bot.token_database.region import Region
class HistoryManager: class HistoryManager:
HIGH_FIDELITY_PERIOD = '72h' HIGH_FIDELITY_PERIOD = "72h"
def __init__(self, token_db: tdb.Database): def __init__(self, token_db: tdb.Database):
self._history: Dict[Flavor, Dict[Region, History]] = {} self._history: Dict[Flavor, Dict[Region, History]] = {}
self._tdb: tdb.Database = token_db self._tdb: tdb.Database = token_db
@ -18,14 +19,21 @@ class HistoryManager:
for region in Region: for region in Region:
self._history[flavor][Region(region)] = History(flavor, Region(region)) self._history[flavor][Region(region)] = History(flavor, Region(region))
async def _retrieve_data(
async def _retrieve_data(self, flavor: Flavor, region: Region) -> List[Tuple[datetime.datetime, int]]: self, flavor: Flavor, region: Region
high_fidelity_time = datetime.datetime.now(tz=datetime.UTC) - datetime.timedelta(hours=72) ) -> List[Tuple[datetime.datetime, int]]:
high_fidelity_time = datetime.datetime.now(
tz=datetime.UTC
) - datetime.timedelta(hours=72)
all_history = await self._tdb.history(flavor, region) all_history = await self._tdb.history(flavor, region)
high_fidelity_history = await self._tdb.history(flavor, region, self.HIGH_FIDELITY_PERIOD) high_fidelity_history = await self._tdb.history(
flavor, region, self.HIGH_FIDELITY_PERIOD
)
final_response = [] final_response = []
def _convert_to_datetime(data: Tuple[str, int]) -> Tuple[datetime.datetime, int]: def _convert_to_datetime(
data: Tuple[str, int]
) -> Tuple[datetime.datetime, int]:
return datetime.datetime.fromisoformat(data[0]), data[1] return datetime.datetime.fromisoformat(data[0]), data[1]
for data_point in all_history: for data_point in all_history:
@ -33,11 +41,12 @@ class HistoryManager:
if datetime_tuple[0] < high_fidelity_time: if datetime_tuple[0] < high_fidelity_time:
final_response.append(datetime_tuple) final_response.append(datetime_tuple)
final_response.extend(_convert_to_datetime(data_point) for data_point in high_fidelity_history) final_response.extend(
_convert_to_datetime(data_point) for data_point in high_fidelity_history
)
return final_response return final_response
async def load_data(self): async def load_data(self):
for flavor in Flavor: for flavor in Flavor:
for r in Region: for r in Region:
@ -48,19 +57,17 @@ class HistoryManager:
await history.add_price(item) await history.add_price(item)
self._history[flavor][region] = history self._history[flavor][region] = history
async def update_data(self, flavor: Flavor, region: Region) -> List[Alert]: async def update_data(self, flavor: Flavor, region: Region) -> List[Alert]:
history = self._history[flavor][region] history = self._history[flavor][region]
current_price_data = await self._tdb.current(flavor) current_price_data = await self._tdb.current(flavor)
current_region_data = current_price_data[region.value.lower()] current_region_data = current_price_data[region.value.lower()]
datum = ( datum = (
datetime.datetime.fromisoformat(current_region_data[0]), datetime.datetime.fromisoformat(current_region_data[0]),
current_region_data[1] current_region_data[1],
) )
if datum != history.last_price_datum: if datum != history.last_price_datum:
return await history.add_price(datum) return await history.add_price(datum)
return [] return []
def get_history(self, flavor, region) -> History: def get_history(self, flavor, region) -> History:
return self._history[flavor][region] return self._history[flavor][region]

View File

@ -29,20 +29,35 @@ class UpdateTrigger:
def squelched(self): def squelched(self):
return self._squelched return self._squelched
def _find_next_trigger(self, comparison_operator: Callable, starting_point: datetime.datetime, history: List[Tuple[datetime.datetime, int]]): def _find_next_trigger(
self,
comparison_operator: Callable,
starting_point: datetime.datetime,
history: List[Tuple[datetime.datetime, int]],
):
candidate_datum: Tuple[datetime.datetime, int] | None = None candidate_datum: Tuple[datetime.datetime, int] | None = None
for datum in history: for datum in history:
if datum[0] > starting_point and datum != history[-1]: if datum[0] > starting_point and datum != history[-1]:
if candidate_datum is None or comparison_operator(datum[1], candidate_datum[1]): if candidate_datum is None or comparison_operator(
datum[1], candidate_datum[1]
):
candidate_datum = datum candidate_datum = datum
self._last_trigger = candidate_datum self._last_trigger = candidate_datum
def check_and_update(self, new_datum: Tuple[datetime.datetime, int], history: List[Tuple[datetime.datetime, int]]) -> bool: def check_and_update(
self,
new_datum: Tuple[datetime.datetime, int],
history: List[Tuple[datetime.datetime, int]],
) -> bool:
match self.alert.flavor: match self.alert.flavor:
case Flavor.RETAIL: case Flavor.RETAIL:
start_time = datetime.datetime.fromisoformat('2020-11-15 00:00:01.000000000+00:00') start_time = datetime.datetime.fromisoformat(
"2020-11-15 00:00:01.000000000+00:00"
)
case Flavor.CLASSIC: case Flavor.CLASSIC:
start_time = datetime.datetime.fromisoformat('2023-05-23 00:00:01.000000000+00:00') start_time = datetime.datetime.fromisoformat(
"2023-05-23 00:00:01.000000000+00:00"
)
case _: case _:
raise NotImplementedError raise NotImplementedError

View File

@ -1,4 +1,3 @@
from .alert_type import AlertType from .alert_type import AlertType
from .user_schema import User from .user_schema import User
from .alert_schema import Alert from .alert_schema import Alert

View File

@ -7,7 +7,9 @@ class AlertCategory(Enum):
CUSTOM = 3 CUSTOM = 3
@staticmethod @staticmethod
def from_str(category: str): # It gets mad when I use the Type[AlertCategory] as a type hint def from_str(
category: str,
): # It gets mad when I use the Type[AlertCategory] as a type hint
match category: match category:
case "high_alert_button": case "high_alert_button":
return AlertCategory.HIGH return AlertCategory.HIGH

View File

@ -11,7 +11,9 @@ import token_bot.persistant_database as pdb
class Alert: class Alert:
def __init__(self, alert: pdb.AlertType, flavor: Flavor, region: Region, price: int = 0) -> None: def __init__(
self, alert: pdb.AlertType, flavor: Flavor, region: Region, price: int = 0
) -> None:
# AlertType is the Primary Key # AlertType is the Primary Key
self.alert_type: pdb.AlertType = alert self.alert_type: pdb.AlertType = alert
# Flavor (Retail, Classic) is the Sort Key # Flavor (Retail, Classic) is the Sort Key
@ -22,18 +24,18 @@ class Alert:
self.users: List[pdb.User] = [] self.users: List[pdb.User] = []
@classmethod @classmethod
def from_item(cls, primary_key: int, sort_key: str, users: List[int]) -> 'Alert': def from_item(cls, primary_key: int, sort_key: str, users: List[int]) -> "Alert":
alert_type = pdb.AlertType(primary_key) alert_type = pdb.AlertType(primary_key)
flavor_repr, region_repr, price_repr = sort_key.split('-') flavor_repr, region_repr, price_repr = sort_key.split("-")
flavor = Flavor(int(flavor_repr)) flavor = Flavor(int(flavor_repr))
region = Region(region_repr) region = Region(region_repr)
price = int(price_repr) price = int(price_repr)
return cls(alert_type, flavor, region, price) return cls(alert_type, flavor, region, price)
@classmethod @classmethod
def from_str(cls, string_trinity: str) -> 'Alert': def from_str(cls, string_trinity: str) -> "Alert":
alert_repr, flavor_repr, region_repr, price_repr = string_trinity.split('-') alert_repr, flavor_repr, region_repr, price_repr = string_trinity.split("-")
if len(string_trinity.split('-')) != 4: if len(string_trinity.split("-")) != 4:
raise ValueError raise ValueError
alert = pdb.AlertType(int(alert_repr)) alert = pdb.AlertType(int(alert_repr))
flavor = Flavor(int(flavor_repr)) flavor = Flavor(int(flavor_repr))
@ -61,20 +63,24 @@ class Alert:
def key(self) -> dict[str, str | int]: def key(self) -> dict[str, str | int]:
return { return {
self.primary_key_name: self.primary_key, self.primary_key_name: self.primary_key,
self.sort_key_name: self.sort_key self.sort_key_name: self.sort_key,
} }
def __str__(self): def __str__(self):
return f"{self.alert_type.value}-{self.flavor.value}-{self.region.value}-{self.price}" return f"{self.alert_type.value}-{self.flavor.value}-{self.region.value}-{self.price}"
def __eq__(self, other): def __eq__(self, other):
return self.alert_type == other.alert_type and self.flavor == other.flavor and self.price == other.price return (
self.alert_type == other.alert_type
and self.flavor == other.flavor
and self.price == other.price
)
def to_human_string(self): def to_human_string(self):
if self.alert_type == AlertType.SPECIFIC_PRICE: if self.alert_type == AlertType.SPECIFIC_PRICE:
raise NotImplementedError raise NotImplementedError
else: else:
alert_type_str = ' '.join(self.alert_type.name.split("_")) alert_type_str = " ".join(self.alert_type.name.split("_"))
return f"{alert_type_str.title()}" return f"{alert_type_str.title()}"
async def _lazy_load(self, table: Table, consistent: bool = False) -> None: async def _lazy_load(self, table: Table, consistent: bool = False) -> None:
@ -95,19 +101,16 @@ class Alert:
item={ item={
self.primary_key_name: self.primary_key, self.primary_key_name: self.primary_key,
self.sort_key_name: self.sort_key, self.sort_key_name: self.sort_key,
'users': user_ids "users": user_ids,
} }
) )
async def get(self, table: Table, consistent: bool = False) -> bool: async def get(self, table: Table, consistent: bool = False) -> bool:
try: try:
response = await table.get_item( response = await table.get_item(key=self.key, consistent_read=consistent)
key=self.key,
consistent_read=consistent
)
except ItemNotFound: except ItemNotFound:
return False return False
self.users = [pdb.User(int(user_id)) for user_id in response['users']] self.users = [pdb.User(int(user_id)) for user_id in response["users"]]
self._loaded = True self._loaded = True
return True return True
@ -116,13 +119,17 @@ class Alert:
return self.users return self.users
async def add_user(self, table: Table, user: pdb.User, consistent: bool = False) -> None: async def add_user(
self, table: Table, user: pdb.User, consistent: bool = False
) -> None:
await self._lazy_load(table, consistent=consistent) await self._lazy_load(table, consistent=consistent)
if user not in self.users: if user not in self.users:
await self._append_user(table=table, user=user) await self._append_user(table=table, user=user)
async def remove_user(self, table: Table, user: pdb.User, consistent: bool = True) -> None: async def remove_user(
self, table: Table, user: pdb.User, consistent: bool = True
) -> None:
await self._lazy_load(table, consistent=consistent) await self._lazy_load(table, consistent=consistent)
if user in self.users: if user in self.users:

View File

@ -1,5 +1,6 @@
from enum import Enum from enum import Enum
class AlertType(Enum): class AlertType(Enum):
ALL_TIME_HIGH = 1 ALL_TIME_HIGH = 1
ALL_TIME_LOW = 2 ALL_TIME_LOW = 2

View File

@ -8,5 +8,6 @@ from aiodynamo.http.aiohttp import AIOHTTP
class Database: class Database:
def __init__(self, session: aiohttp.ClientSession): def __init__(self, session: aiohttp.ClientSession):
self.client = Client(AIOHTTP(session), Credentials.auto(), os.getenv('AWS_REGION')) self.client = Client(
AIOHTTP(session), Credentials.auto(), os.getenv("AWS_REGION")
)

View File

@ -8,7 +8,12 @@ from token_bot.token_database.region import Region
class User: class User:
def __init__(self, user_id: int, region: Region = None, subscribed_alerts: List['pdb.Alert'] = None) -> None: def __init__(
self,
user_id: int,
region: Region = None,
subscribed_alerts: List["pdb.Alert"] = None,
) -> None:
self.user_id: int = user_id self.user_id: int = user_id
self._loaded: bool = False self._loaded: bool = False
self.region: Region = region self.region: Region = region
@ -21,7 +26,9 @@ class User:
return hash(self.user_id) return hash(self.user_id)
@classmethod @classmethod
def from_item(cls, primary_key: int, region: Region, subscribed_alerts: List[str]) -> 'User': def from_item(
cls, primary_key: int, region: Region, subscribed_alerts: List[str]
) -> "User":
alerts = [pdb.Alert.from_str(alert_str) for alert_str in subscribed_alerts] alerts = [pdb.Alert.from_str(alert_str) for alert_str in subscribed_alerts]
return cls(primary_key, region, alerts) return cls(primary_key, region, alerts)
@ -31,17 +38,18 @@ class User:
@property @property
def primary_key_name(self) -> str: def primary_key_name(self) -> str:
return 'user_id' return "user_id"
@property @property
def key(self) -> Dict[str, str]: def key(self) -> Dict[str, str]:
return { return {self.primary_key_name: self.primary_key}
self.primary_key_name: self.primary_key
}
def _subscribed_alerts_as_trinity_list(self) -> List[str]: def _subscribed_alerts_as_trinity_list(self) -> List[str]:
return [str(alert) for alert in self.subscribed_alerts] if self.subscribed_alerts else [] return (
[str(alert) for alert in self.subscribed_alerts]
if self.subscribed_alerts
else []
)
async def _lazy_load(self, table: Table, consistent: bool = False) -> None: async def _lazy_load(self, table: Table, consistent: bool = False) -> None:
if consistent or not self._loaded: if consistent or not self._loaded:
@ -51,8 +59,8 @@ class User:
await table.put_item( await table.put_item(
item={ item={
self.primary_key_name: self.primary_key, self.primary_key_name: self.primary_key,
'region': self.region, "region": self.region,
'subscribed_alerts': self._subscribed_alerts_as_trinity_list() "subscribed_alerts": self._subscribed_alerts_as_trinity_list(),
} }
) )
@ -65,26 +73,27 @@ class User:
async def get(self, table: Table, consistent: bool = False) -> bool: async def get(self, table: Table, consistent: bool = False) -> bool:
try: try:
response = await table.get_item( response = await table.get_item(key=self.key, consistent_read=consistent)
key=self.key,
consistent_read=consistent
)
except ItemNotFound: except ItemNotFound:
return False return False
self.subscribed_alerts = [] self.subscribed_alerts = []
for string_trinity in response['subscribed_alerts']: for string_trinity in response["subscribed_alerts"]:
self.subscribed_alerts.append(pdb.Alert.from_str(string_trinity)) self.subscribed_alerts.append(pdb.Alert.from_str(string_trinity))
self.region = Region(response['region']) self.region = Region(response["region"])
return True return True
async def add_alert(self, table: Table, alert: 'pdb.Alert', consistent: bool = False) -> None: async def add_alert(
self, table: Table, alert: "pdb.Alert", consistent: bool = False
) -> None:
await self._lazy_load(table, consistent=consistent) await self._lazy_load(table, consistent=consistent)
if alert not in self.subscribed_alerts: if alert not in self.subscribed_alerts:
self.subscribed_alerts.append(alert) self.subscribed_alerts.append(alert)
await self.put(table) await self.put(table)
async def remove_alert(self, table: Table, alert: 'pdb.Alert', consistent: bool = True) -> None: async def remove_alert(
self, table: Table, alert: "pdb.Alert", consistent: bool = True
) -> None:
await self._lazy_load(table, consistent=consistent) await self._lazy_load(table, consistent=consistent)
if alert in self.subscribed_alerts: if alert in self.subscribed_alerts:
self.subscribed_alerts.remove(alert) self.subscribed_alerts.remove(alert)

View File

@ -10,16 +10,12 @@ class TokenBot:
load_dotenv() load_dotenv()
print("#### WoW Token Bot Startup ####") print("#### WoW Token Bot Startup ####")
logging.basicConfig( logging.basicConfig(
format='%(asctime)s.%(msecs)03d %(levelname)s %(module)s - %(funcName)s: %(message)s', format="%(asctime)s.%(msecs)03d %(levelname)s %(module)s - %(funcName)s: %(message)s",
datefmt='%Y-%m-%d %H:%M:%S', datefmt="%Y-%m-%d %H:%M:%S",
) )
log = logging.getLogger("TokenBotLogger") log = logging.getLogger("TokenBotLogger")
log.setLevel(logging.INFO) log.setLevel(logging.INFO)
self.bot = Client( self.bot = Client(intents=Intents.DEFAULT, asyncio_debug=True, logger=log)
intents=Intents.DEFAULT,
asyncio_debug=True,
logger=log
)
def run(self): def run(self):
self.bot.load_extension("token_bot.core") self.bot.load_extension("token_bot.core")

View File

@ -34,7 +34,9 @@ class Database:
raise TokenHttpException(resp.status) raise TokenHttpException(resp.status)
async def current(self, flavor: Flavor) -> dict: async def current(self, flavor: Flavor) -> dict:
return await self._get_data(f'current/{flavor.name.lower()}.json') return await self._get_data(f"current/{flavor.name.lower()}.json")
async def history(self, flavor: Flavor, region: Region, relative_time: str = 'all'): async def history(self, flavor: Flavor, region: Region, relative_time: str = "all"):
return await self._get_data(f'relative/{flavor.name.lower()}/{region.value.lower()}/{relative_time}.json') return await self._get_data(
f"relative/{flavor.name.lower()}/{region.value.lower()}/{relative_time}.json"
)

View File

@ -4,4 +4,3 @@ from enum import Enum
class Flavor(Enum): class Flavor(Enum):
RETAIL = 1 RETAIL = 1
CLASSIC = 2 CLASSIC = 2

View File

@ -1,7 +1,8 @@
from enum import Enum from enum import Enum
class Region(str, Enum): class Region(str, Enum):
US = 'us' US = "us"
EU = 'eu' EU = "eu"
KR = 'kr' KR = "kr"
TW = 'tw' TW = "tw"

View File

@ -5,8 +5,19 @@ import logging
from typing import Type, Dict, List from typing import Type, Dict, List
import aiohttp import aiohttp
from interactions import Extension, SlashContext, component_callback, \ from interactions import (
ComponentContext, StringSelectMenu, Message, Embed, EmbedField, is_owner, check, StringSelectOption Extension,
SlashContext,
component_callback,
ComponentContext,
StringSelectMenu,
Message,
Embed,
EmbedField,
is_owner,
check,
StringSelectOption,
)
from interactions import Task, IntervalTrigger from interactions import Task, IntervalTrigger
from interactions import slash_command, listen from interactions import slash_command, listen
from interactions.api.events import Component from interactions.api.events import Component
@ -29,6 +40,7 @@ from token_bot.ui.select_menus.region_menu import REGION_MENU
#### Static Helper Functions #### Static Helper Functions
async def gather_alerts_by_flavor(alerts: List[Alert]) -> Dict[Flavor, List[Alert]]: async def gather_alerts_by_flavor(alerts: List[Alert]) -> Dict[Flavor, List[Alert]]:
alerts_by_flavor = {} alerts_by_flavor = {}
for alert in alerts: for alert in alerts:
@ -39,7 +51,6 @@ async def gather_alerts_by_flavor(alerts: List[Alert]) -> Dict[Flavor, List[Aler
return alerts_by_flavor return alerts_by_flavor
class Tracker(Extension): class Tracker(Extension):
def __init__(self, bot): def __init__(self, bot):
self._users: UsersController | None = None self._users: UsersController | None = None
@ -47,7 +58,6 @@ class Tracker(Extension):
self._tdb: tdb.Database | None = None self._tdb: tdb.Database | None = None
self._history_manager: HistoryManager | None = None self._history_manager: HistoryManager | None = None
################################### ###################################
# Task Functions # # Task Functions #
################################### ###################################
@ -68,21 +78,24 @@ class Tracker(Extension):
users_alerts[user].append(alert) users_alerts[user].append(alert)
for user in users_alerts: for user in users_alerts:
discord_user = await self.bot.fetch_user(user.user_id) discord_user = await self.bot.fetch_user(user.user_id)
embeds = [Embed( embeds = [
Embed(
title="TokenBot Tracker Alert Triggered", title="TokenBot Tracker Alert Triggered",
color=0xb10000, color=0xB10000,
description=f"Hello, you requested to be sent an alert when the price of the World of Warcraft " description=f"Hello, you requested to be sent an alert when the price of the World of Warcraft "
f"token reaches a certain value.\n\n" f"token reaches a certain value.\n\n"
f"As a reminder, you can remove an alert via ```/remove-alert```\n" f"As a reminder, you can remove an alert via ```/remove-alert```\n"
f"or you can remove all registrations via ```/remove-registration```\n\n" f"or you can remove all registrations via ```/remove-registration```\n\n",
)] )
]
alerts_by_flavor = await gather_alerts_by_flavor(users_alerts[user]) alerts_by_flavor = await gather_alerts_by_flavor(users_alerts[user])
for flavor in alerts_by_flavor: for flavor in alerts_by_flavor:
embeds.append(await self.render_alert_flavor(alerts_by_flavor[flavor], user=user)) embeds.append(
await self.render_alert_flavor(alerts_by_flavor[flavor], user=user)
)
await discord_user.send(embeds=embeds) await discord_user.send(embeds=embeds)
################################### ###################################
# Slash Commands # # Slash Commands #
################################### ###################################
@ -97,28 +110,30 @@ class Tracker(Extension):
self.bot.logger.log(logging.INFO, "TokenBot Tracker: Initialized") self.bot.logger.log(logging.INFO, "TokenBot Tracker: Initialized")
self.bot.logger.log(logging.INFO, "TokenBot Tracker: Loading Historical Data") self.bot.logger.log(logging.INFO, "TokenBot Tracker: Loading Historical Data")
await self._history_manager.load_data() await self._history_manager.load_data()
self.bot.logger.log(logging.INFO, "TokenBot Tracker: Loading Historical Data Finished") self.bot.logger.log(
logging.INFO, "TokenBot Tracker: Loading Historical Data Finished"
)
self.bot.logger.log(logging.INFO, "TokenBot Tracker: Started") self.bot.logger.log(logging.INFO, "TokenBot Tracker: Started")
self.update_data.start() self.update_data.start()
@slash_command( @slash_command(
name="register", name="register",
description="Register with TokenBot for alerts on token price changes." description="Register with TokenBot for alerts on token price changes.",
) )
async def register(self, ctx: SlashContext): async def register(self, ctx: SlashContext):
text = ("## Select a region to register with \n\n" text = (
"## Select a region to register with \n\n"
"Please note: \n" "Please note: \n"
"* You can only be registered with one region at a time \n" "* You can only be registered with one region at a time \n"
"* Changing your region will remove all previous alerts you have signed up for \n" "* Changing your region will remove all previous alerts you have signed up for \n"
"* You can remove all alerts and registration using ```/remove-registration```") "* You can remove all alerts and registration using ```/remove-registration```"
)
menu = copy.deepcopy(REGION_MENU) menu = copy.deepcopy(REGION_MENU)
await ctx.send(text, components=menu, ephemeral=True) await ctx.send(text, components=menu, ephemeral=True)
@slash_command( @slash_command(
name="remove-registration", name="remove-registration",
description="Remove all alerts and registration from TokenBot" description="Remove all alerts and registration from TokenBot",
) )
async def remove_registration(self, ctx: SlashContext): async def remove_registration(self, ctx: SlashContext):
if await self._users.exists(ctx.user.id): if await self._users.exists(ctx.user.id):
@ -127,43 +142,35 @@ class Tracker(Extension):
await self._alerts.remove_user(alert, user) await self._alerts.remove_user(alert, user)
await self._users.delete(ctx.user.id) await self._users.delete(ctx.user.id)
await ctx.send("All alert subscriptions and user registration deleted", ephemeral=True) await ctx.send(
"All alert subscriptions and user registration deleted", ephemeral=True
)
@slash_command( @slash_command(
name="exists", name="exists", description="Check if you are registered with TokenBot"
description="Check if you are registered with TokenBot"
) )
@check(is_owner()) @check(is_owner())
async def exists(self, ctx: SlashContext): async def exists(self, ctx: SlashContext):
await ctx.send(str(await self._users.exists(ctx.user.id)), ephemeral=True) await ctx.send(str(await self._users.exists(ctx.user.id)), ephemeral=True)
@slash_command(description="The current retail token cost")
@slash_command(
description="The current retail token cost"
)
async def current(self, ctx: SlashContext): async def current(self, ctx: SlashContext):
current_str = await self.get_current_token(ctx, tdb.Flavor.RETAIL) current_str = await self.get_current_token(ctx, tdb.Flavor.RETAIL)
await ctx.send(current_str, ephemeral=True) await ctx.send(current_str, ephemeral=True)
@slash_command(description="The current classic token cost")
@slash_command(
description="The current classic token cost"
)
async def current_classic(self, ctx: SlashContext): async def current_classic(self, ctx: SlashContext):
current_str = await self.get_current_token(ctx, tdb.Flavor.CLASSIC) current_str = await self.get_current_token(ctx, tdb.Flavor.CLASSIC)
await ctx.send(current_str, ephemeral=True) await ctx.send(current_str, ephemeral=True)
@slash_command(name="add-alert", description="Add an alert listener")
@slash_command(
name="add-alert",
description="Add an alert listener"
)
async def add_alert(self, ctx: SlashContext): async def add_alert(self, ctx: SlashContext):
if not await self._users.exists(ctx.user.id): if not await self._users.exists(ctx.user.id):
await ctx.send("You are not registered with any region\n" await ctx.send(
"You are not registered with any region\n"
"Please register with /register before adding alerts", "Please register with /register before adding alerts",
ephemeral=True) ephemeral=True,
)
return return
user = await self._users.get(ctx.user.id) user = await self._users.get(ctx.user.id)
@ -186,23 +193,25 @@ class Tracker(Extension):
if not await self._users.is_subscribed(user, alert): if not await self._users.is_subscribed(user, alert):
await asyncio.gather( await asyncio.gather(
self._users.add_alert(user, alert), self._users.add_alert(user, alert),
self._alerts.add_user(alert, user) self._alerts.add_user(alert, user),
) )
await ctx.send("Successfully added alert", ephemeral=True) await ctx.send("Successfully added alert", ephemeral=True)
else: else:
await ctx.send("You are already subscribed to this alert", ephemeral=True) await ctx.send(
"You are already subscribed to this alert", ephemeral=True
)
@slash_command( @slash_command(
name="remove-alert", name="remove-alert", description="Remove an alert you have signed up for"
description="Remove an alert you have signed up for"
) )
async def remove_alert(self, ctx: SlashContext): async def remove_alert(self, ctx: SlashContext):
if not await self._users.exists(ctx.user.id): if not await self._users.exists(ctx.user.id):
await ctx.send("You are not registered with any region\n" await ctx.send(
"You are not registered with any region\n"
"Please register with /register before adding alerts", "Please register with /register before adding alerts",
ephemeral=True) ephemeral=True,
)
return return
user = await self._users.get(ctx.user.id) user = await self._users.get(ctx.user.id)
alerts = await self._users.list_alerts(user) alerts = await self._users.list_alerts(user)
@ -217,20 +226,20 @@ class Tracker(Extension):
else: else:
await asyncio.gather( await asyncio.gather(
self._users.remove_alert(user, alert), self._users.remove_alert(user, alert),
self._alerts.remove_user(alert, user) self._alerts.remove_user(alert, user),
) )
await ctx.send("Successfully removed alert", ephemeral=True) await ctx.send("Successfully removed alert", ephemeral=True)
@slash_command( @slash_command(
name="list-alerts", name="list-alerts", description="List all alerts you have signed up for"
description="List all alerts you have signed up for"
) )
async def list_alerts(self, ctx: SlashContext): async def list_alerts(self, ctx: SlashContext):
if not await self._users.exists(ctx.user.id): if not await self._users.exists(ctx.user.id):
await ctx.send("You are not registered with any region\n" await ctx.send(
"You are not registered with any region\n"
"Please register with /register before adding alerts", "Please register with /register before adding alerts",
ephemeral=True) ephemeral=True,
)
return return
user = await self._users.get(ctx.user.id) user = await self._users.get(ctx.user.id)
alerts = await self._users.list_alerts(user) alerts = await self._users.list_alerts(user)
@ -238,55 +247,66 @@ class Tracker(Extension):
await ctx.send("You do not have any alerts registered", ephemeral=True) await ctx.send("You do not have any alerts registered", ephemeral=True)
return return
alerts_str = f"You have {len(alerts)} out of 25 maximum alerts registered" alerts_str = f"You have {len(alerts)} out of 25 maximum alerts registered"
embeds = [Embed( embeds = [
Embed(
title="List of TokenBot Tracker Alerts", title="List of TokenBot Tracker Alerts",
color=0x0000b1, color=0x0000B1,
description=alerts_str description=alerts_str,
)] )
]
alerts_by_flavor = await gather_alerts_by_flavor(alerts) alerts_by_flavor = await gather_alerts_by_flavor(alerts)
for flavor in alerts_by_flavor: for flavor in alerts_by_flavor:
embeds.append(await self.render_alert_flavor(alerts_by_flavor[flavor], user=user)) embeds.append(
await self.render_alert_flavor(alerts_by_flavor[flavor], user=user)
)
await ctx.send(embeds=embeds, ephemeral=True) await ctx.send(embeds=embeds, ephemeral=True)
################################### ###################################
# Callbacks Commands # # Callbacks Commands #
################################### ###################################
@component_callback('flavor_menu') @component_callback("flavor_menu")
async def flavor_menu(self, ctx: ComponentContext): async def flavor_menu(self, ctx: ComponentContext):
await ctx.send(f"Selected Flavor: {ctx.values[0]}", ephemeral=True) await ctx.send(f"Selected Flavor: {ctx.values[0]}", ephemeral=True)
@component_callback('high_alert_menu') @component_callback("high_alert_menu")
async def alert_menu(self, ctx: ComponentContext): async def alert_menu(self, ctx: ComponentContext):
await ctx.send(f"Selected Alert: {ctx.values[0]}", ephemeral=True) await ctx.send(f"Selected Alert: {ctx.values[0]}", ephemeral=True)
@component_callback('low_alert_menu') @component_callback("low_alert_menu")
async def alert_menu(self, ctx: ComponentContext): async def alert_menu(self, ctx: ComponentContext):
await ctx.send(f"Selected Alert: {ctx.values[0]}", ephemeral=True) await ctx.send(f"Selected Alert: {ctx.values[0]}", ephemeral=True)
@component_callback('remove_alert_menu') @component_callback("remove_alert_menu")
async def remove_alert_menu(self, ctx: ComponentContext): async def remove_alert_menu(self, ctx: ComponentContext):
await ctx.send(f"You have selected to remove the following alert: {ctx.values[0].title()}", ephemeral=True) await ctx.send(
f"You have selected to remove the following alert: {ctx.values[0].title()}",
ephemeral=True,
)
@component_callback('region_menu') @component_callback("region_menu")
async def region_menu(self, ctx: ComponentContext): async def region_menu(self, ctx: ComponentContext):
user = User(ctx.user.id, Region(ctx.values[0].lower()), subscribed_alerts=[]) user = User(ctx.user.id, Region(ctx.values[0].lower()), subscribed_alerts=[])
await self._users.add(user) await self._users.add(user)
discord_user = await self.bot.fetch_user(user.user_id) discord_user = await self.bot.fetch_user(user.user_id)
await discord_user.send("You have successfully registered with TokenBot!\n" await discord_user.send(
"You have successfully registered with TokenBot!\n"
"Most interactions will happen in direct messages with TokenBot here.\n" "Most interactions will happen in direct messages with TokenBot here.\n"
"You can remove your registration and alerts at any time using ```/remove-registration```\n") "You can remove your registration and alerts at any time using ```/remove-registration```\n"
await ctx.send(f"Successfully registered with the {ctx.values[0]} region", ephemeral=True) )
await ctx.send(
f"Successfully registered with the {ctx.values[0]} region", ephemeral=True
)
@component_callback('high_alert_button') @component_callback("high_alert_button")
async def high_alert_button(self, ctx: ComponentContext): async def high_alert_button(self, ctx: ComponentContext):
await ctx.send("You selected to add a High Price Alert", ephemeral=True) await ctx.send("You selected to add a High Price Alert", ephemeral=True)
@component_callback('low_alert_button') @component_callback("low_alert_button")
async def low_alert_button(self, ctx: ComponentContext): async def low_alert_button(self, ctx: ComponentContext):
await ctx.send("You selected to add a Low Price Alert", ephemeral=True) await ctx.send("You selected to add a Low Price Alert", ephemeral=True)
@component_callback('custom_alert_button') @component_callback("custom_alert_button")
async def custom_alert_button(self, ctx: ComponentContext): async def custom_alert_button(self, ctx: ComponentContext):
await ctx.send("You selected to add a Custom Price Alert", ephemeral=True) await ctx.send("You selected to add a Custom Price Alert", ephemeral=True)
@ -298,34 +318,40 @@ class Tracker(Extension):
user: User = await self._users.get(ctx.user.id) user: User = await self._users.get(ctx.user.id)
region = user.region.name region = user.region.name
region_history = self._history_manager.get_history(flavor, user.region) region_history = self._history_manager.get_history(flavor, user.region)
price_movement_str = format(region_history.last_price_movement, ',') price_movement_str = format(region_history.last_price_movement, ",")
if region_history.last_price_movement > 0: if region_history.last_price_movement > 0:
price_movement_str = f"+{price_movement_str}" price_movement_str = f"+{price_movement_str}"
return (f"Last Price Value for {region}: {format(region_history.last_price_datum[1], ",")}\n" return (
f"Last Price Value for {region}: {format(region_history.last_price_datum[1], ",")}\n"
f"Last Update Time: {region_history.last_price_datum[0].strftime('%Y-%m-%d %H:%M:%S UTC')}\n" f"Last Update Time: {region_history.last_price_datum[0].strftime('%Y-%m-%d %H:%M:%S UTC')}\n"
f"Last Price Movement: {price_movement_str}") f"Last Price Movement: {price_movement_str}"
)
async def remove_alert_select_menu(self, ctx: SlashContext, user: User): async def remove_alert_select_menu(self, ctx: SlashContext, user: User):
alerts_by_flavor = await gather_alerts_by_flavor(user.subscribed_alerts) alerts_by_flavor = await gather_alerts_by_flavor(user.subscribed_alerts)
select_options: List[StringSelectOption] = [] select_options: List[StringSelectOption] = []
for flavor in alerts_by_flavor: for flavor in alerts_by_flavor:
for alert in alerts_by_flavor[flavor]: for alert in alerts_by_flavor[flavor]:
select_options.append(StringSelectOption( select_options.append(
StringSelectOption(
label=f"{alert.flavor.name.lower().title()} {alert.to_human_string()}", label=f"{alert.flavor.name.lower().title()} {alert.to_human_string()}",
value=f"{alert.flavor.name.lower()} {alert.to_human_string()}" value=f"{alert.flavor.name.lower()} {alert.to_human_string()}",
)) )
)
menu = StringSelectMenu( menu = StringSelectMenu(
select_options, select_options,
placeholder="Select an alert to remove", placeholder="Select an alert to remove",
custom_id="remove_alert_menu" custom_id="remove_alert_menu",
)
message = await ctx.send(
"Select an alert to remove", components=menu, ephemeral=True
) )
message = await ctx.send("Select an alert to remove", components=menu, ephemeral=True)
try: try:
alert_component: Component = await self.bot.wait_for_component(messages=message, alert_component: Component = await self.bot.wait_for_component(
components=menu, timeout=30) messages=message, components=menu, timeout=30
)
except TimeoutError: except TimeoutError:
menu.disabled = True menu.disabled = True
await message.edit(context=ctx, components=menu, content="Timed out") await message.edit(context=ctx, components=menu, content="Timed out")
@ -335,23 +361,24 @@ class Tracker(Extension):
await message.edit(context=ctx, components=menu) await message.edit(context=ctx, components=menu)
selection_split = alert_component.ctx.values[0].split(" ") selection_split = alert_component.ctx.values[0].split(" ")
flavor = Flavor[selection_split[0].upper()] flavor = Flavor[selection_split[0].upper()]
alert_type = AlertType.from_str(' '.join(selection_split[1:])) alert_type = AlertType.from_str(" ".join(selection_split[1:]))
return Alert(alert_type, flavor, user.region) return Alert(alert_type, flavor, user.region)
async def flavor_select_menu(self, ctx: SlashContext) -> Type[Flavor]: async def flavor_select_menu(self, ctx: SlashContext) -> Type[Flavor]:
flavor_menu = copy.deepcopy(FLAVOR_MENU) flavor_menu = copy.deepcopy(FLAVOR_MENU)
flavor_message = await ctx.send( flavor_message = await ctx.send(
"Select a flavor to add alerts for", "Select a flavor to add alerts for", components=flavor_menu, ephemeral=True
components=flavor_menu, )
ephemeral=True)
try: try:
flavor_component: Component = await self.bot.wait_for_component(messages=flavor_message, flavor_component: Component = await self.bot.wait_for_component(
components=flavor_menu, timeout=30) messages=flavor_message, components=flavor_menu, timeout=30
)
except TimeoutError: except TimeoutError:
flavor_menu.disabled = True flavor_menu.disabled = True
await flavor_message.edit(context=ctx, components=flavor_menu, content="Timed out") await flavor_message.edit(
context=ctx, components=flavor_menu, content="Timed out"
)
raise TimeoutError raise TimeoutError
else: else:
flavor = Flavor[flavor_component.ctx.values[0].upper()] flavor = Flavor[flavor_component.ctx.values[0].upper()]
@ -359,21 +386,21 @@ class Tracker(Extension):
await flavor_message.edit(context=ctx, components=flavor_menu) await flavor_message.edit(context=ctx, components=flavor_menu)
return flavor return flavor
async def alert_category_select_menu(self, ctx: SlashContext) -> AlertCategory: async def alert_category_select_menu(self, ctx: SlashContext) -> AlertCategory:
alert_type_button = copy.deepcopy(ALERT_TYPE_ROW) alert_type_button = copy.deepcopy(ALERT_TYPE_ROW)
alert_type_message = await ctx.send( alert_type_message = await ctx.send(
"Select an alert type to add", "Select an alert type to add", components=alert_type_button, ephemeral=True
components=alert_type_button, )
ephemeral=True)
try: try:
alert_type_component: Component = await self.bot.wait_for_component(messages=alert_type_message, alert_type_component: Component = await self.bot.wait_for_component(
components=alert_type_button, messages=alert_type_message, components=alert_type_button, timeout=30
timeout=30) )
except TimeoutError: except TimeoutError:
for button in alert_type_button[0].components: for button in alert_type_button[0].components:
button.disabled = True button.disabled = True
await alert_type_message.edit(context=ctx, components=alert_type_button, content="Timed out") await alert_type_message.edit(
context=ctx, components=alert_type_button, content="Timed out"
)
raise TimeoutError raise TimeoutError
else: else:
alert_type = AlertCategory.from_str(alert_type_component.ctx.custom_id) alert_type = AlertCategory.from_str(alert_type_component.ctx.custom_id)
@ -382,10 +409,13 @@ class Tracker(Extension):
await alert_type_message.edit(context=ctx, components=alert_type_button) await alert_type_message.edit(context=ctx, components=alert_type_button)
return alert_type return alert_type
async def _alert_select_menu_handler(
async def _alert_select_menu_handler(self, ctx: SlashContext, menu: StringSelectMenu, message: Message) -> AlertType: self, ctx: SlashContext, menu: StringSelectMenu, message: Message
) -> AlertType:
try: try:
component: Component = await self.bot.wait_for_component(messages=message, components=menu, timeout=30) component: Component = await self.bot.wait_for_component(
messages=message, components=menu, timeout=30
)
except TimeoutError: except TimeoutError:
menu.disabled = True menu.disabled = True
await message.edit(context=ctx, components=menu, content="Timed out") await message.edit(context=ctx, components=menu, content="Timed out")
@ -395,26 +425,27 @@ class Tracker(Extension):
await message.edit(context=ctx, components=menu) await message.edit(context=ctx, components=menu)
return AlertType.from_str(component.ctx.values[0]) return AlertType.from_str(component.ctx.values[0])
async def high_alert_select_menu(self, ctx: SlashContext) -> AlertType: async def high_alert_select_menu(self, ctx: SlashContext) -> AlertType:
high_menu = copy.deepcopy(HIGH_ALERT_MENU) high_menu = copy.deepcopy(HIGH_ALERT_MENU)
high_message = await ctx.send( high_message = await ctx.send(
"Select a time range to add a High Alert for", "Select a time range to add a High Alert for",
components=high_menu, components=high_menu,
ephemeral=True) ephemeral=True,
)
return await self._alert_select_menu_handler(ctx, high_menu, high_message) return await self._alert_select_menu_handler(ctx, high_menu, high_message)
async def low_alert_select_menu(self, ctx: SlashContext) -> AlertType: async def low_alert_select_menu(self, ctx: SlashContext) -> AlertType:
low_menu = copy.deepcopy(LOW_ALERT_MENU) low_menu = copy.deepcopy(LOW_ALERT_MENU)
low_message = await ctx.send( low_message = await ctx.send(
"Select a time range to add a Low Alert for", "Select a time range to add a Low Alert for",
components=low_menu, components=low_menu,
ephemeral=True) ephemeral=True,
)
return await self._alert_select_menu_handler(ctx, low_menu, low_message) return await self._alert_select_menu_handler(ctx, low_menu, low_message)
async def render_alert_flavor(
async def render_alert_flavor(self, alerts: List[Alert], user: User | None = None) -> Embed: self, alerts: List[Alert], user: User | None = None
) -> Embed:
region = alerts[0].region region = alerts[0].region
flavor = alerts[0].flavor flavor = alerts[0].flavor
fields: List[EmbedField] = [] fields: List[EmbedField] = []
@ -422,10 +453,13 @@ class Tracker(Extension):
history = self._history_manager.get_history(alert.flavor, alert.region) history = self._history_manager.get_history(alert.flavor, alert.region)
trigger = await history.find_update_trigger_from_alert(alert) trigger = await history.find_update_trigger_from_alert(alert)
if trigger.last_trigger is not None: if trigger.last_trigger is not None:
alert_str = (f"Last Alerting Price Value: {format(trigger.last_alerting[1], ",")}\n" alert_str = (
f"Last Alerting Time: {trigger.last_alerting[0].strftime('%Y-%m-%d %H:%M:%S UTC')}\n") f"Last Alerting Price Value: {format(trigger.last_alerting[1], ",")}\n"
f"Last Alerting Time: {trigger.last_alerting[0].strftime('%Y-%m-%d %H:%M:%S UTC')}\n"
)
if user is not None and user.user_id == 265678699435655169: if user is not None and user.user_id == 265678699435655169:
alert_str += (f"\nShowing you some internals since you are the bot owner:\n" alert_str += (
f"\nShowing you some internals since you are the bot owner:\n"
f"```history.last_price_datum:\n" f"```history.last_price_datum:\n"
f"\t{history.last_price_datum[0].strftime('%Y-%m-%d %H:%M:%S UTC')}\n" f"\t{history.last_price_datum[0].strftime('%Y-%m-%d %H:%M:%S UTC')}\n"
f"\t{history.last_price_datum[1]}\n" f"\t{history.last_price_datum[1]}\n"
@ -435,15 +469,20 @@ class Tracker(Extension):
f"trigger.last_trigger:\n" f"trigger.last_trigger:\n"
f"\t{trigger.last_trigger[0].strftime('%Y-%m-%d %H:%M:%S UTC')}\n" f"\t{trigger.last_trigger[0].strftime('%Y-%m-%d %H:%M:%S UTC')}\n"
f"\t{trigger.last_trigger[1]}\n" f"\t{trigger.last_trigger[1]}\n"
f"trigger.squelched:\n\t{trigger.squelched}```") f"trigger.squelched:\n\t{trigger.squelched}```"
)
else: else:
alert_str = "You should only be seeing this if the bot has not finished importing history at startup." alert_str = "You should only be seeing this if the bot has not finished importing history at startup."
fields.append( fields.append(
EmbedField( EmbedField(
name=f"{alert.to_human_string()} Alert", value=alert_str, inline=False)) name=f"{alert.to_human_string()} Alert",
value=alert_str,
inline=False,
)
)
embed = Embed( embed = Embed(
title=f"Alerts for {region.name} {flavor.name.lower().title()}", title=f"Alerts for {region.name} {flavor.name.lower().title()}",
color=0xb10000, color=0xB10000,
fields=fields fields=fields,
) )
return embed return embed

View File

@ -1,6 +1,9 @@
from interactions import ActionRow from interactions import ActionRow
from token_bot.ui.buttons.tracker.alert_category import HIGH_ALERT_BUTTON, LOW_ALERT_BUTTON from token_bot.ui.buttons.tracker.alert_category import (
HIGH_ALERT_BUTTON,
LOW_ALERT_BUTTON,
)
ALERT_TYPE_ROW: list[ActionRow] = [ ALERT_TYPE_ROW: list[ActionRow] = [
ActionRow( ActionRow(

View File

@ -1,67 +1,45 @@
from interactions import Button, ButtonStyle from interactions import Button, ButtonStyle
ATH_ADD_BUTTON = Button( ATH_ADD_BUTTON = Button(
custom_id='ath_add_button', custom_id="ath_add_button", style=ButtonStyle.GREEN, label="All Time High"
style=ButtonStyle.GREEN,
label="All Time High"
) )
ATL_ADD_BUTTON = Button( ATL_ADD_BUTTON = Button(
custom_id='atl_add_button', custom_id="atl_add_button", style=ButtonStyle.RED, label="All Time Low"
style=ButtonStyle.RED,
label="All Time Low"
) )
DH_ADD_BUTTON = Button( DH_ADD_BUTTON = Button(
custom_id='dh_add_button', custom_id="dh_add_button", style=ButtonStyle.GREEN, label="Daily High"
style=ButtonStyle.GREEN,
label="Daily High"
) )
DL_ADD_BUTTON = Button( DL_ADD_BUTTON = Button(
custom_id='dl_add_button', custom_id="dl_add_button", style=ButtonStyle.RED, label="Daily Low"
style=ButtonStyle.RED,
label="Daily Low"
) )
WH_ADD_BUTTON = Button( WH_ADD_BUTTON = Button(
custom_id='wh_add_button', custom_id="wh_add_button", style=ButtonStyle.GREEN, label="Weekly High"
style=ButtonStyle.GREEN,
label="Weekly High"
) )
WL_ADD_BUTTON = Button( WL_ADD_BUTTON = Button(
custom_id='wl_add_button', custom_id="wl_add_button", style=ButtonStyle.RED, label="Weekly Low"
style=ButtonStyle.RED,
label="Weekly Low"
) )
MH_ADD_BUTTON = Button( MH_ADD_BUTTON = Button(
custom_id='mh_add_button', custom_id="mh_add_button", style=ButtonStyle.GREEN, label="Monthly High"
style=ButtonStyle.GREEN,
label="Monthly High"
) )
ML_ADD_BUTTON = Button( ML_ADD_BUTTON = Button(
custom_id='ml_add_button', custom_id="ml_add_button", style=ButtonStyle.RED, label="Monthly Low"
style=ButtonStyle.RED,
label="Monthly Low"
) )
YH_ADD_BUTTON = Button( YH_ADD_BUTTON = Button(
custom_id='yh_add_button', custom_id="yh_add_button", style=ButtonStyle.GREEN, label="Yearly High"
style=ButtonStyle.GREEN,
label="Yearly High"
) )
YL_ADD_BUTTON = Button( YL_ADD_BUTTON = Button(
custom_id='yl_add_button', custom_id="yl_add_button", style=ButtonStyle.RED, label="Yearly Low"
style=ButtonStyle.RED,
label="Yearly Low"
) )
SP_ADD_BUTTON = Button( SP_ADD_BUTTON = Button(
custom_id='sp_add_button', custom_id="sp_add_button", style=ButtonStyle.GRAY, label="Custom Limit Price"
style=ButtonStyle.GRAY,
label="Custom Limit Price"
) )

View File

@ -1,19 +1,13 @@
from interactions import Button, ButtonStyle from interactions import Button, ButtonStyle
HIGH_ALERT_BUTTON = Button( HIGH_ALERT_BUTTON = Button(
custom_id='high_alert_button', custom_id="high_alert_button", style=ButtonStyle.GREEN, label="High Price Alert"
style=ButtonStyle.GREEN,
label="High Price Alert"
) )
LOW_ALERT_BUTTON = Button( LOW_ALERT_BUTTON = Button(
custom_id='low_alert_button', custom_id="low_alert_button", style=ButtonStyle.RED, label="Low Price Alert"
style=ButtonStyle.RED,
label="Low Price Alert"
) )
CUSTOM_ALERT_BUTTON = Button( CUSTOM_ALERT_BUTTON = Button(
custom_id='sp_add_button', custom_id="sp_add_button", style=ButtonStyle.GRAY, label="Custom Price Alert"
style=ButtonStyle.GRAY,
label="Custom Price Alert"
) )

View File

@ -1,19 +1,13 @@
from interactions import Button, ButtonStyle from interactions import Button, ButtonStyle
HIGH_ALERT = Button( HIGH_ALERT = Button(
custom_id='high_alert_button', custom_id="high_alert_button", style=ButtonStyle.GREEN, label="Add High Alert"
style=ButtonStyle.GREEN,
label="Add High Alert"
) )
LOW_ALERT = Button( LOW_ALERT = Button(
custom_id='low_alert_button', custom_id="low_alert_button", style=ButtonStyle.RED, label="Add Low Alert"
style=ButtonStyle.RED,
label="Add Low Alert"
) )
CUSTOM_ALERT = Button( CUSTOM_ALERT = Button(
custom_id='custom_alert_button', custom_id="custom_alert_button", style=ButtonStyle.GRAY, label="Add Custom Alert"
style=ButtonStyle.GRAY,
label="Add Custom Alert"
) )

View File

@ -1,15 +1,25 @@
from interactions import StringSelectMenu from interactions import StringSelectMenu
HIGH_ALERT_MENU = StringSelectMenu( HIGH_ALERT_MENU = StringSelectMenu(
"Daily High", "Weekly High", "Monthly High", "Yearly High", "All Time High", "Daily High",
"Weekly High",
"Monthly High",
"Yearly High",
"All Time High",
placeholder="Select a time period", placeholder="Select a time period",
min_values=1, max_values=1, min_values=1,
custom_id='high_alert_menu' max_values=1,
custom_id="high_alert_menu",
) )
LOW_ALERT_MENU = StringSelectMenu( LOW_ALERT_MENU = StringSelectMenu(
"Daily Low", "Weekly Low", "Monthly Low", "Yearly Low", "All Time Low", "Daily Low",
"Weekly Low",
"Monthly Low",
"Yearly Low",
"All Time Low",
placeholder="Select a time period", placeholder="Select a time period",
min_values=1, max_values=1, min_values=1,
custom_id='low_alert_menu' max_values=1,
custom_id="low_alert_menu",
) )

View File

@ -1,8 +1,10 @@
from interactions import StringSelectMenu from interactions import StringSelectMenu
FLAVOR_MENU = StringSelectMenu( FLAVOR_MENU = StringSelectMenu(
"Retail", "Classic", "Retail",
"Classic",
placeholder="Select version of WoW", placeholder="Select version of WoW",
min_values=1, max_values=1, min_values=1,
custom_id='flavor_menu' max_values=1,
custom_id="flavor_menu",
) )

View File

@ -1,8 +1,12 @@
from interactions import StringSelectMenu from interactions import StringSelectMenu
REGION_MENU = StringSelectMenu( REGION_MENU = StringSelectMenu(
"US", "EU", "KR", "TW", "US",
"EU",
"KR",
"TW",
placeholder="Select a region", placeholder="Select a region",
min_values=1, max_values=1, min_values=1,
custom_id='region_menu' max_values=1,
custom_id="region_menu",
) )