Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions command_handling/first_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
Expand Down
101 changes: 75 additions & 26 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

intenderinos = discord.Intents.default()
intenderinos.members = True

# I was here
activity = discord.activity.Activity(
type=discord.ActivityType.competing, name="Leetcode"
)
Expand Down Expand Up @@ -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}"
Expand All @@ -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:
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why repeat this and not put it in to a function? If you make a change somewhere you will have to remember to make a change everywhere else.

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(
Expand Down Expand Up @@ -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}."
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)."
)
Expand All @@ -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)
Expand Down Expand Up @@ -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!***'
)
Expand All @@ -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****************************************************"
)
Expand All @@ -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(
Expand All @@ -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(
Expand Down Expand Up @@ -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
Expand All @@ -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),
Expand Down
14 changes: 0 additions & 14 deletions messages/channel_config_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"])

Expand Down
60 changes: 32 additions & 28 deletions submission_handling/selenium.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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": {}}

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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()

Expand Down