This commit is contained in:
Slipstream 2025-05-09 16:42:38 -06:00
parent d95638ee14
commit ee84d5fcec
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD
6 changed files with 64 additions and 28 deletions

View File

@ -2,7 +2,7 @@ import hashlib
import hmac
import json
import logging
from typing import Dict, Any
from typing import Dict, Any, Optional
from fastapi import APIRouter, Request, HTTPException, Depends, Header, Path
import discord # For Color

View File

@ -16,7 +16,7 @@ class EarningCommands(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
@commands.hybrid_command(name="daily", description="Claim your daily reward.")
@commands.command(name="daily", description="Claim your daily reward.")
async def daily(self, ctx: commands.Context):
"""Allows users to claim a daily currency reward."""
user_id = ctx.author.id
@ -54,7 +54,7 @@ class EarningCommands(commands.Cog):
await ctx.send(embed=embed)
@commands.hybrid_command(name="beg", description="Beg for some spare change.")
@commands.command(name="beg", description="Beg for some spare change.")
async def beg(self, ctx: commands.Context):
"""Allows users to beg for a small amount of currency with a chance of success."""
user_id = ctx.author.id
@ -102,7 +102,7 @@ class EarningCommands(commands.Cog):
)
await ctx.send(embed=embed)
@commands.hybrid_command(name="work", description="Do some work for a guaranteed reward.")
@commands.command(name="work", description="Do some work for a guaranteed reward.")
async def work(self, ctx: commands.Context):
"""Allows users to perform work for a small, guaranteed reward."""
user_id = ctx.author.id
@ -161,7 +161,7 @@ class EarningCommands(commands.Cog):
embed.add_field(name="New Balance", value=f"${current_balance:,}", inline=False)
await ctx.send(embed=embed)
@commands.hybrid_command(name="scavenge", description="Scavenge around for some spare change.") # Renamed to avoid conflict
@commands.command(name="scavenge", description="Scavenge around for some spare change.") # Renamed to avoid conflict
async def scavenge(self, ctx: commands.Context): # Renamed function
"""Allows users to scavenge for a small chance of finding money."""
user_id = ctx.author.id

View File

@ -975,7 +975,7 @@ class GamesCog(commands.Cog, name="Games"):
# --- Prefix Commands (Legacy Support) ---
@commands.command(name="coinflipbet")
@commands.command(name="coinflipbet", add_to_app_commands=False)
async def coinflipbet_prefix(self, ctx: commands.Context, opponent: discord.Member):
"""(Prefix) Challenge another user to a coin flip game."""
initiator = ctx.author
@ -989,25 +989,25 @@ class GamesCog(commands.Cog, name="Games"):
message = await ctx.send(initial_message, view=view)
view.message = message
@commands.command(name="coinflip")
@commands.command(name="coinflip", add_to_app_commands=False)
async def coinflip_prefix(self, ctx: commands.Context):
"""(Prefix) Flip a coin."""
result = flip_coin()
await ctx.send(f"The coin landed on **{result}**! 🪙")
@commands.command(name="roll")
@commands.command(name="roll", add_to_app_commands=False)
async def roll_prefix(self, ctx: commands.Context):
"""(Prefix) Roll a dice."""
result = roll_dice()
await ctx.send(f"You rolled a **{result}**! 🎲")
@commands.command(name="magic8ball")
@commands.command(name="magic8ball", add_to_app_commands=False)
async def magic8ball_prefix(self, ctx: commands.Context, *, question: str):
"""(Prefix) Ask the magic 8 ball."""
response = magic8ball_response()
await ctx.send(f"🎱 {response}")
@commands.command(name="tictactoe")
@commands.command(name="tictactoe", add_to_app_commands=False)
async def tictactoe_prefix(self, ctx: commands.Context, opponent: discord.Member):
"""(Prefix) Challenge another user to Tic-Tac-Toe."""
initiator = ctx.author
@ -1021,7 +1021,7 @@ class GamesCog(commands.Cog, name="Games"):
message = await ctx.send(initial_message, view=view)
view.message = message
@commands.command(name="tictactoebot")
@commands.command(name="tictactoebot", add_to_app_commands=False)
async def tictactoebot_prefix(self, ctx: commands.Context, difficulty: str = "minimax"):
"""(Prefix) Play Tic-Tac-Toe against the bot."""
difficulty_value = difficulty.lower()
@ -1057,7 +1057,7 @@ class GamesCog(commands.Cog, name="Games"):
)
view.message = message
@commands.command(name="rpschallenge")
@commands.command(name="rpschallenge", add_to_app_commands=False)
async def rpschallenge_prefix(self, ctx: commands.Context, opponent: discord.Member):
"""(Prefix) Challenge another user to Rock-Paper-Scissors."""
initiator = ctx.author
@ -1071,7 +1071,7 @@ class GamesCog(commands.Cog, name="Games"):
message = await ctx.send(initial_message, view=view)
view.message = message
@commands.command(name="rps")
@commands.command(name="rps", add_to_app_commands=False)
async def rps_prefix(self, ctx: commands.Context, choice: str):
"""(Prefix) Play Rock-Paper-Scissors against the bot."""
choices = ["Rock", "Paper", "Scissors"]
@ -1099,7 +1099,7 @@ class GamesCog(commands.Cog, name="Games"):
f"{result}"
)
@commands.command(name="chess")
@commands.command(name="chess", add_to_app_commands=False)
async def chess_prefix(self, ctx: commands.Context, opponent: discord.Member):
"""(Prefix) Start a game of chess with another user."""
initiator = ctx.author
@ -1120,12 +1120,12 @@ class GamesCog(commands.Cog, name="Games"):
asyncio.create_task(view._send_or_update_dm(view.white_player))
asyncio.create_task(view._send_or_update_dm(view.black_player))
@commands.command(name="hangman")
@commands.command(name="hangman", add_to_app_commands=False)
async def hangman_prefix(self, ctx: commands.Context):
"""(Prefix) Play a game of Hangman."""
await play_hangman(self.bot, ctx.channel, ctx.author)
@commands.command(name="guess")
@commands.command(name="guess", add_to_app_commands=False)
async def guess_prefix(self, ctx: commands.Context, guess: int):
"""(Prefix) Guess a number between 1 and 100."""
number_to_guess = random.randint(1, 100)

View File

@ -22,8 +22,8 @@ log = logging.getLogger(__name__)
# Helper to parse repo URL and determine platform
def parse_repo_url(url: str) -> tuple[Optional[str], Optional[str]]:
"""Parses a Git repository URL to extract platform and a simplified repo identifier."""
# Changed from +? to + for the repo name part for robustness, though unlikely to be the issue for simple URLs.
github_match = re.match(r"https^(?:https?://)?(?:www\.)?github\.com/([\w.-]+/[\w.-]+)(?:\.git)?/?$", url)
# Fixed regex pattern for GitHub URLs
github_match = re.match(r"^(?:https?://)?(?:www\.)?github\.com/([\w.-]+/[\w.-]+)(?:\.git)?/?$", url)
if github_match:
return "github", github_match.group(1)
@ -81,7 +81,7 @@ class GitMonitorCog(commands.Cog):
if target_branch:
params["sha"] = target_branch # GitHub uses 'sha' for branch/tag/commit SHA
# No 'since_sha' for GitHub commits list. Manual filtering after fetch.
async with session.get(api_url, params=params) as response:
if response.status == 200:
commits_payload = await response.json()
@ -91,7 +91,7 @@ class GitMonitorCog(commands.Cog):
temp_new_commits = [] # Clear previous if we found the last one
continue
temp_new_commits.append(commit_item)
if temp_new_commits:
new_commits_data = temp_new_commits
latest_fetched_sha = new_commits_data[-1]['sha']
@ -124,7 +124,7 @@ class GitMonitorCog(commands.Cog):
temp_new_commits = []
continue
temp_new_commits.append(commit_item)
if temp_new_commits:
new_commits_data = temp_new_commits
latest_fetched_sha = new_commits_data[-1]['id']
@ -161,7 +161,7 @@ class GitMonitorCog(commands.Cog):
verified_status = "Verified" if verification.get('verified') else "Unverified"
if verification.get('reason') and verification.get('reason') != 'unsigned':
verified_status += f" ({verification.get('reason')})"
# Files changed and stats require another API call per commit: GET /repos/{owner}/{repo}/commits/{sha}
# This is too API intensive for a simple polling loop.
# We will omit detailed file stats for polled GitHub commits for now.
@ -200,7 +200,7 @@ class GitMonitorCog(commands.Cog):
embed.add_field(name="Commit", value=f"[`{commit_id_short}`]({commit_url})", inline=True)
# embed.add_field(name="Branch", value="default (polling)", inline=True) # Placeholder
embed.add_field(name="Changes", value=files_changed_str, inline=False)
if embed:
try:
await channel.send(embed=embed)
@ -211,11 +211,11 @@ class GitMonitorCog(commands.Cog):
log.error(f"Discord HTTP error sending message for {repo_url}: {dhe}")
else:
log.warning(f"Channel {channel_id} not found for guild {guild_id} for repo {repo_url}")
# Update polling status in DB
if latest_fetched_sha != last_sha or not new_commits_data : # Update if new sha or just to update timestamp
await settings_manager.update_repository_polling_status(repo_id, latest_fetched_sha, datetime.datetime.now(datetime.timezone.utc))
# Small delay between processing each repo to be nice to APIs
await asyncio.sleep(2) # 2 seconds delay
@ -365,14 +365,14 @@ class GitMonitorCog(commands.Cog):
return
embed = discord.Embed(title=f"Monitored Repositories for {interaction.guild.name}", color=discord.Color.blue())
description_lines = []
for repo in monitored_repos:
channel = self.bot.get_channel(repo['notification_channel_id'])
channel_mention = channel.mention if channel else f"ID: {repo['notification_channel_id']}"
method = repo['monitoring_method'].capitalize()
platform = repo['platform'].capitalize()
# Attempt to get a cleaner repo name if possible
_, repo_name_simple = parse_repo_url(repo['repository_url'])
display_name = repo_name_simple if repo_name_simple else repo['repository_url']
@ -384,7 +384,7 @@ class GitMonitorCog(commands.Cog):
f"- Channel: {channel_mention}\n"
f"- DB ID: `{repo['id']}`"
)
embed.description = "\n\n".join(description_lines)
if len(embed.description) > 4000 : # Discord embed description limit
embed.description = embed.description[:3990] + "\n... (list truncated)"

View File

@ -1,3 +1,4 @@
import datetime
import asyncpg
import redis.asyncio as redis
import os

35
test_url_parser.py Normal file
View File

@ -0,0 +1,35 @@
import re
from typing import Optional, Tuple
# Copy of the fixed parse_repo_url function
def parse_repo_url(url: str) -> Tuple[Optional[str], Optional[str]]:
"""Parses a Git repository URL to extract platform and a simplified repo identifier."""
# Fixed regex pattern for GitHub URLs
github_match = re.match(r"^(?:https?://)?(?:www\.)?github\.com/([\w.-]+/[\w.-]+)(?:\.git)?/?$", url)
if github_match:
return "github", github_match.group(1)
gitlab_match = re.match(r"^(?:https?://)?(?:www\.)?gitlab\.com/([\w.-]+(?:/[\w.-]+)+)(?:\.git)?/?$", url)
if gitlab_match:
return "gitlab", gitlab_match.group(1)
return None, None
# Test URLs
test_urls = [
"https://github.com/Slipstreamm/discordbot",
"http://github.com/Slipstreamm/discordbot",
"github.com/Slipstreamm/discordbot",
"www.github.com/Slipstreamm/discordbot",
"https://github.com/Slipstreamm/discordbot.git",
"https://gitlab.com/group/project",
"https://gitlab.com/group/subgroup/project",
"invalid-url"
]
# Test each URL
print("Testing URL parsing with fixed regex pattern:")
print("-" * 50)
for url in test_urls:
platform, repo_id = parse_repo_url(url)
result = f"Valid: {platform}, {repo_id}" if platform else "Invalid URL"
print(f"{url} => {result}")