diff --git a/command_handling/first_handler.py b/command_handling/first_handler.py index 5a12abc..4fad549 100644 --- a/command_handling/first_handler.py +++ b/command_handling/first_handler.py @@ -33,7 +33,7 @@ def get_first_stats(interaction: discord.Interaction): # makes string containing list of people in first place (except user) first_place_message = "" - if len(first_places) == 1: + if len(first_places) == 0: first_place_message = f"{first_places[0]}" else: # form list of first place @@ -48,7 +48,7 @@ def get_first_stats(interaction: discord.Interaction): if user_is_first: # first place is triggering command! response_message = f"You are first place! Keep it up, you have {ParticipantData.get_instance().get_points(interaction.user.id)} point(s)!\n" - if not len(first_places) == 1: + if not len(first_places) == 0: response_message = f"You are tied with {first_place_message}\n" else: points_behind = ParticipantData.get_instance().get_points( diff --git a/main.py b/main.py index 51debf0..572217a 100644 --- a/main.py +++ b/main.py @@ -45,7 +45,7 @@ intenderinos = discord.Intents.default() intenderinos.members = True - +# I was here activity = discord.activity.Activity( type=discord.ActivityType.competing, name="Leetcode" ) @@ -180,7 +180,11 @@ async def on_guild_join(guild: Guild): @tree.command(description="Say hello.") @app_commands.checks.cooldown(1, 1) async def hello(interaction: discord.Interaction): - check_submission_channel() + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + entry = random.randrange(0, len(greeting) - 1) await interaction.response.send_message( f"{greeting[entry]} {interaction.user.mention}" @@ -193,7 +197,11 @@ async def hello(interaction: discord.Interaction): @tree.command(description="See today's problem.") @app_commands.checks.cooldown(1, COOLDOWN_SECONDS) async def current_challenge(interaction: discord.Interaction): - check_submission_channel() + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + embeds = getProblemEmbeds(store["cotd"]) await interaction.response.send_message( @@ -230,8 +238,13 @@ async def submit( "Elixir", ], ): - check_submission_channel() + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + await interaction.response.defer() + submission = await handle_submission(interaction, attachment, language) response_message = f"Thanks for uploading, {interaction.user.display_name}! Received {language} file: {attachment.filename}." @@ -291,7 +304,11 @@ async def submit( @tree.command(description="Provides the Top given value members.") @app_commands.describe(value="What number of the top members you want to see") async def top(interaction: discord.Interaction, value: int): - check_submission_channel() + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + await interaction.response.send_message( await format_rank_list( interaction, ParticipantData.get_instance().get_top(value), value @@ -302,7 +319,11 @@ async def top(interaction: discord.Interaction, value: int): @app_commands.checks.cooldown(1, COOLDOWN_SECONDS) @tree.command(description="provides the Top 10 members.") async def top10(interaction: discord.Interaction): - check_submission_channel() + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + await interaction.response.send_message( await format_rank_list( interaction, ParticipantData.get_instance().get_top(10), 10 @@ -313,7 +334,11 @@ async def top10(interaction: discord.Interaction): @app_commands.checks.cooldown(1, COOLDOWN_SECONDS) @tree.command(description="Provides how many points you have.") async def mypoints(interaction: discord.Interaction): - check_submission_channel() + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + await interaction.response.send_message( f"You currently have {ParticipantData.get_instance().get_points(interaction.user.id)} point(s)." ) @@ -322,14 +347,22 @@ async def mypoints(interaction: discord.Interaction): @app_commands.checks.cooldown(1, COOLDOWN_SECONDS) @tree.command(description="Compares you with the first place member.") async def first(interaction: discord.Interaction): - check_submission_channel() + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + await interaction.response.defer() await interaction.followup.send(get_first_stats(interaction)) @tree.command(description="Display your personal stats.") async def get_stats(interaction: discord.Interaction): - check_submission_channel() + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + await interaction.response.defer() ParticipantData.get_instance().add_participant(interaction.user.id) @@ -357,6 +390,11 @@ async def get_stats(interaction: discord.Interaction): ) @app_commands.checks.cooldown(1, COOLDOWN_SECONDS) async def rules(interaction: discord.Interaction): + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + await interaction.response.send_message( f'**Rules**\n---------\n • Please partricipate in good faith. Don\'t cheat! This competition is to help you improve on your leetcode skills and facilitate fun in our server. If you cheat you are defeating the purpose.\n\n • Challenges are posted at {DAILY_ANNOUNCEMENT_TIME.strftime("%I : %M %p")} in the announcement channel.\n\n • Submit solution files either through DM to me or in the submission channel through the /submit command.\n\n • Opt in to reminder pings through the /remindme command and opt out through the /stopreminders command.\n\n\n ***Happy Trotting Broncoder!***' ) @@ -365,6 +403,11 @@ async def rules(interaction: discord.Interaction): @tree.command(description="Provides a list of supported non admin commands.") @app_commands.checks.cooldown(1, COOLDOWN_SECONDS) async def supported_commands(interaction: discord.Interaction): + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + await interaction.response.send_message( f"**************************************************\n COMMANDS\n currently supported commands:\n ---------------------------\n FUN\n * hello : Say hello.\n\n ---------------------------\n PROBLEM SUBMISSION\n * current_challenge : See today's problem.\n * submit : Submit your code to be tested and judged.\n\n ---------------------------\n STATS\n * top: Provides the Top given value members.\n * top10: Provides the Top 10 members\n * mypoints: Provides how many points you have.\n * first: Compares you with the first place member.\n * get_stats: Display your personal stats.\n\n ---------------------------\n UTILITY\n * rules: Provides the rules and instructions to use the bot for the competition.\n * supported_commands: Provides a list of supported non admin commands.\n * remindme: Enroll yourself in competition reminders.\n * stopreminders: Remove yourself from the competition reminders.\n\n****************************************************" ) @@ -373,7 +416,11 @@ async def supported_commands(interaction: discord.Interaction): @tree.command(description="Enroll yourself in competition reminders.") @app_commands.checks.cooldown(1, COOLDOWN_SECONDS) async def remindme(interaction: discord.Interaction): - check_submission_channel() + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + if "Broncoder" in [u.name for u in interaction.user.roles]: # Add file? await interaction.response.send_message( @@ -392,7 +439,11 @@ async def remindme(interaction: discord.Interaction): @app_commands.checks.has_role("Broncoder") # add error catch to not crash async def stopreminders(interaction: discord.Interaction): - check_submission_channel() + if store.__getitem__("submission_channel_id") == 0: + return await check_submission_channel(interaction) + elif interaction.channel_id != store.__getitem__("submission_channel_id"): + return await check_submission_channel(interaction, True) + comp_role = discord.utils.get(interaction.guild.roles, name="Broncoder") await interaction.user.remove_roles(comp_role) await interaction.response.send_message( @@ -547,10 +598,19 @@ async def givepoints(interaction: discord.Interaction, setting:str, point_value: ******************************************************""" -def check_submission_channel(): - assert ( - store.__getitem__("submission_channel_id") != 0 - ), "Code submission channel not set" +async def check_submission_channel( + interaction: discord.Interaction, channel_exists: bool = False +): + if channel_exists: + await interaction.response.send_message( + content=f"You sent this command in the wrong channel! Please use <#{store.__getitem__('submission_channel_id')}>", + ephemeral=True, + ) + else: + await interaction.response.send_message( + content="No code submission channel set. Please notify an admin to fix this.", + ephemeral=True, + ) @tree.error @@ -567,17 +627,6 @@ async def tree_errors( "You do not have the permission to execute this command!", ephemeral=True, ) - elif isinstance(error, app_commands.CommandInvokeError): - error_message = "An error has occurred. Please contact an admin regarding what steps you took for this error message to occur." - if store.__getitem__("submission_channel_id") == 0: - error_message = ( - "No code submission channel set. Please notify an admin to fix this." - ) - - await interaction.followup.send( - content=error_message, - ephemeral=True, - ) else: print( "Ignoring exception in command {}:".format(interaction.command), diff --git a/messages/channel_config_view.py b/messages/channel_config_view.py index 229fe5c..fa86fdf 100644 --- a/messages/channel_config_view.py +++ b/messages/channel_config_view.py @@ -4,17 +4,6 @@ store = PersistentStore.get_instance() -class InfoButton(discord.ui.Button["ChannelConfigView"]): - def __init__(self): - super().__init__( - style=discord.ButtonStyle.secondary, label="Info", disabled=True - ) - - async def callback(self, interaction: discord.Interaction): - view: ChannelConfigView = self.view - await interaction.response.edit_message(content="Info", view=view) - - class AnnounceButton(discord.ui.Button["ChannelConfigView"]): def __init__(self, channel_id): self.channel_id = channel_id @@ -54,9 +43,6 @@ def __init__(self, channel_id): self.buttons = {} - self.buttons["info"] = InfoButton() - self.add_item(self.buttons["info"]) - self.buttons["announce"] = AnnounceButton(channel_id) self.add_item(self.buttons["announce"]) diff --git a/submission_handling/selenium.py b/submission_handling/selenium.py index 67f9545..8e45003 100644 --- a/submission_handling/selenium.py +++ b/submission_handling/selenium.py @@ -1,5 +1,5 @@ -from operator import truediv from selenium import webdriver +from selenium.webdriver.chrome.service import Service from selenium.common.exceptions import TimeoutException from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC @@ -17,24 +17,28 @@ # TODO: Add captcha support to some extent +LOCAL_TESTING = False timeout = 60 my_browser_state = BrowserState() options = webdriver.ChromeOptions() -""" -desired_capabilities = DesiredCapabilities.CHROME -options.add_experimental_option("excludeSwitches", ["enable-logging"]) -driver = webdriver.Chrome(desired_capabilities=desired_capabilities, options=options) -""" - -options.binary_location = os.environ.get("GOOGLE_CHROME_BIN") -options.add_argument("--headless") -options.add_argument("--disable-dev-shm-usage") -options.add_argument("--no-sandbox") -driver = webdriver.Chrome( - executable_path=os.environ.get("CHROMEDRIVER_PATH"), options=options -) +if LOCAL_TESTING: + desired_capabilities = DesiredCapabilities.CHROME + options.add_experimental_option("excludeSwitches", ["enable-logging"]) + driver = webdriver.Chrome( + desired_capabilities=desired_capabilities, options=options + ) +else: + options.binary_location = os.environ.get("GOOGLE_CHROME_BIN") + options.add_argument("--headless") + options.add_argument("--disable-dev-shm-usage") + options.add_argument("--no-sandbox") + driver = webdriver.Chrome( + service=Service(executable_path=os.environ.get("CHROMEDRIVER_PATH")), + options=options, + ) + # Used for Heroku Testing response_dict_base = {"msg": None, "err": False, "details": {}} @@ -65,12 +69,6 @@ async def setup(question): driver.find_element(By.ID, "signin_btn").click() - try: - element_present = EC.presence_of_element_located((By.ID, "profile-app")) - WebDriverWait(driver, timeout).until(element_present) - except TimeoutException: - exit() - driver.get("https://leetcode.com/problems/{}".format(question["titleSlug"])) try: @@ -172,16 +170,22 @@ async def submitCode(code, language="Python3"): await typeCode(code) - driver.find_element(By.XPATH, '//button[@data-cy="submit-code-btn"]').click() + # driver.find_element(By.XPATH, '//button[@data-cy="submit-code-btn"]').click() + driver.find_element( + By.XPATH, + '//*[@id="app"]/div/div[2]/div[1]/div/div[3]/div/div[3]/div[2]/div/button/span', + ).click() + # Attempt at finding an alternate path to click the button by clicking the inner span within the button + + """ + BUG: Error seems to be around this region. My assumption is that the submit button is somehow not being clicked. + Commenting out the code segment below containing 'status_present' will throw a TimeoutException-related error saying that a timeout occurred in trying to find the element of 'detail_present' + Commenting out both code segments of 'status_present' and 'detail_present' will causes 'result_url' to throw an error of being unable to find the element in question. + """ try: - pending_present = EC.presence_of_element_located( - (By.XPATH, "//*[contains(text(), 'Pending')]") - ) + status_present = EC.presence_of_element_located((By.CLASS_NAME, "status__1eAa")) - judging_present = EC.presence_of_element_located( - (By.XPATH, "//*[contains(text(), 'Judging')]") - ) - WebDriverWait(driver, timeout).until(pending_present or judging_present) + WebDriverWait(driver, timeout).until(status_present) except TimeoutException: exit()