diff --git a/bot.py b/bot.py index 84ec806..03362b1 100644 --- a/bot.py +++ b/bot.py @@ -715,34 +715,89 @@ async def handle_expired_giveaway(process_uuid, data): """Handles expired giveaway processes""" try: giveaway_id = data.get("giveaway_id") - if giveaway_id and giveaway_id in giveaways: - giveaway = giveaways[giveaway_id] + guild_id = data.get("guild_id") + channel_id = data.get("channel_id") + + if not giveaway_id: + logger.error(f"No giveaway_id found in process data for {process_uuid}") + update_process_status(process_uuid, "failed") + return - # Execute giveaway ending logic - winners = giveaway.pick_winners() - if winners: - winner_mentions = ", ".join([winner.mention for winner in winners]) - await giveaway.ctx.send(f"🎉 Congratulations to the winners of the giveaway '{giveaway.title}'! The winners are: {winner_mentions}") - - # Process winners - for i, winner in enumerate(winners): + # Try to get giveaway from memory first, then from database + giveaway = None + if giveaway_id in giveaways: + giveaway = giveaways[giveaway_id] + else: + # Recreate giveaway object from database data + try: + guild = client.get_guild(guild_id) + channel = guild.get_channel(channel_id) if guild else None + + if not guild or not channel: + logger.error(f"Could not find guild {guild_id} or channel {channel_id} for giveaway {giveaway_id}") + update_process_status(process_uuid, "failed") + return + + # Create a minimal context object for the giveaway + class MinimalContext: + def __init__(self, channel): + self.channel = channel + self.guild = channel.guild + + async def send(self, *args, **kwargs): + return await self.channel.send(*args, **kwargs) + + ctx = MinimalContext(channel) + + # Create giveaway object from stored data using the class method + giveaway = Giveaway.from_process_data(ctx, data) + + # Restore participants from database + stored_participants = data.get("participants", []) + for participant_data in stored_participants: try: + user = await client.fetch_user(participant_data["id"]) + giveaway.participants.append(user) + except Exception as e: + logger.error(f"Could not fetch participant {participant_data}: {e}") + + logger.info(f"Recreated giveaway {giveaway_id} from database for completion with {len(giveaway.participants)} participants") + + except Exception as e: + logger.error(f"Error recreating giveaway {giveaway_id}: {e}") + update_process_status(process_uuid, "failed") + return + + # Execute giveaway ending logic + winners = giveaway.pick_winners() + if winners: + winner_mentions = ", ".join([winner.mention for winner in winners]) + await giveaway.ctx.send(f"🎉 Congratulations to the winners of the giveaway '{giveaway.title}'! The winners are: {winner_mentions}") + + # Process winners + for i, winner in enumerate(winners): + try: + if i < len(giveaway.winner_uuids): winner_uuid = giveaway.winner_uuids[i] assign_winner_to_uuid(winner_uuid, winner.id) await winner.send(f"🎁 Congratulations! You won the giveaway '{giveaway.title}'!\n" f"Please claim your prize using the following link: {GIVEAWAY_WEBSITE_URL}{giveaway.guild_id}/{winner_uuid}") - except Exception as e: - logger.error(f"Error processing winner {winner.name}: {e}") - else: - await giveaway.ctx.send(f"The giveaway '{giveaway.title}' has ended, but there were no participants.") - - # Clean up + except Exception as e: + logger.error(f"Error processing winner {winner.name}: {e}") + else: + await giveaway.ctx.send(f"The giveaway '{giveaway.title}' has ended, but there were no participants.") + + # Clean up + if giveaway_id in giveaways: del giveaways[giveaway_id] - update_process_status(process_uuid, "completed") + update_process_status(process_uuid, "completed") + + logger.info(f"Successfully completed expired giveaway {giveaway_id}") except Exception as e: logger.error(f"Error handling expired giveaway {process_uuid}: {e}") + update_process_status(process_uuid, "failed") async def handle_expired_mute(process_uuid, data): """Handles expired mute processes - placeholder for future implementation""" @@ -1019,12 +1074,34 @@ class Giveaway: # Create process entry in active_processes table self.process_uuid = None self.create_process_entry() + + @classmethod + def from_process_data(cls, ctx, data): + """Alternative constructor for restoring from process data""" + giveaway = cls.__new__(cls) + giveaway.ctx = ctx + giveaway.guild_id = ctx.guild.id + giveaway.platform = data.get("platform", "Unknown") + giveaway.prize = data.get("prize", "Unknown Prize") + giveaway.num_winners = data.get("num_winners", 1) + giveaway.title = data.get("title", "Unknown Giveaway") + giveaway.subtitle = data.get("subtitle", "") + giveaway.duration = "restored" + giveaway.end_time = datetime.now() # Already expired + giveaway.participants = [] + giveaway.prize_uuid = data.get("prize_uuid", str(uuid.uuid4())) + giveaway.game_key = data.get("game_key", "PREDEFINED_GAME_KEY") + giveaway.winner_uuids = data.get("winner_uuids", []) + giveaway.process_uuid = None + return giveaway def create_process_entry(self): """Creates an entry in the active_processes table for this giveaway""" try: giveaway_data = { "giveaway_id": len(giveaways) + 1, # Will be set properly when added to giveaways dict + "guild_id": self.guild_id, + "channel_id": self.ctx.channel.id, "platform": self.platform, "prize": self.prize, "num_winners": self.num_winners, @@ -1032,12 +1109,12 @@ class Giveaway: "subtitle": self.subtitle, "winner_uuids": [str(uuid) for uuid in self.winner_uuids], "prize_uuid": str(self.prize_uuid), - "game_key": self.game_key + "game_key": self.game_key, + "participants": [] } giveaway_metadata = { "duration": self.duration, - "channel_id": self.ctx.channel.id, "author_id": self.ctx.author.id } @@ -1077,7 +1154,7 @@ class Giveaway: if user not in self.participants: self.participants.append(user) - # Update process data with participant count + # Update process data with participant list and count try: if self.process_uuid: current_processes = get_active_processes() @@ -1085,10 +1162,11 @@ class Giveaway: if process["uuid"] == str(self.process_uuid): data = process["data"] or {} data["participant_count"] = len(self.participants) + data["participants"] = [{"id": p.id, "name": p.name} for p in self.participants] update_process_status(self.process_uuid, "active", data=data) break except Exception as e: - logger.error(f"Error updating participant count: {e}") + logger.error(f"Error updating participant data: {e}") return True return False