Пример #1
0
    async def join(self, ctx, exchange_name=""):
        """ Join the secret santa """
        if not util.is_from_guild(ctx):
            await util.send(ctx, "This message only works in a server")
            return

        if exchange_name == "":
            await ctx.send("You must provide the name of an exchange.\n" +
                           " Example: `!santa join RT2019`")
            return

        username = ctx.message.author.display_name
        user_id = ctx.message.author.id
        guild_id = ctx.message.guild.id

        session = self.sessionmaker()

        # Verify the exchange is created and open for the current guild
        exchange = session.query(Exchange) \
            .filter_by(name=exchange_name, guild_id=guild_id) \
            .one_or_none()

        if exchange is None:
            session.rollback()
            session.close()
            await ctx.send(
                f"Secret Santa exchange {exchange_name} was not found")
            return

        if not exchange.is_open:
            session.close()
            await ctx.send(
                f"Secret Santa exchange {exchange_name} is closed. Please join the next exchange"
            )
            return

        # Check if the participant has already registered
        if session.query(Registrant) \
                .filter_by(exchange=exchange_name, user_id=user_id) \
                .count() > 0:
            session.rollback()
            session.close()
            await util.send(ctx, "Silly goose, you are already registered")
            return

        registration = Registrant(exchange=exchange_name, user_id=user_id)
        session.add(registration)
        try:
            session.commit()
            message = f"{username} has joined the secret santa {exchange_name}!"
            await util.send(ctx, message)
        except:
            session.rollback()
            message = f"There was an unknown error registering {username} for {exchange_name}!"
            await util.send(ctx, message)
        session.close()
Пример #2
0
 async def list(self, ctx, exchange_name=""):
     """ List the Secret Santa exchanges or participants"""
     if not util.is_from_guild(ctx):
         await util.send(ctx, "This message only works in a server")
     if exchange_name == "":
         # List the possible exchanges
         await self.list_exchanges(ctx)
     else:
         # List the participants in the exchange
         await self.list_participants(ctx, exchange_name)
Пример #3
0
 async def list(self, context, contest_name=""):
     """ List the contests or entries"""
     if not util.is_from_guild(context):
         await util.send(context, "This message only works in a server")
     if contest_name == "":
         # List the possible contests
         await self.list_contests(context)
     else:
         # List the entries in the contest
         await self.list_entries(context, contest_name)
Пример #4
0
    async def enter(self, context, contest_name=""):
        """ Join the contest contest """
        if not util.is_from_guild(context):
            await util.send(context, "This message only works in a server")
            return

        if contest_name == "":
            await context.send("You must provide the name of an contest.\n" +
                               " Example: `!contest enter RT2019`")
            return

        username = context.message.author.display_name
        user_id = context.message.author.id
        guild_id = context.message.guild.id

        session = self.sessionmaker()

        # Verify the contest is created and open for the current guild
        contest = session.query(Contest) \
            .filter_by(name=contest_name, guild_id=guild_id) \
            .one_or_none()

        if contest is None:
            session.rollback()
            session.close()
            await context.send(f"Contest {contest_name} was not found")
            return

        if not contest.open:
            session.rollback()
            session.close()
            await context.send(
                f"Contest {contest_name} is closed. Please join the next contest"
            )
            return

        # Check if the participant has already registered
        if session.query(Entry) \
                .filter_by(contest=contest.cid, user_id=user_id) \
                .count() > 0:
            session.rollback()
            session.close()
            await util.send(context, "No cheating! You already entered")
            return

        registration = Entry(contest=contest.cid, user_id=user_id)
        session.add(registration)
        try:
            session.commit()
            message = f"{username} has joined the contest {contest_name}!"
        except:
            session.rollback()
            message = f"There was an unknown error registering {username} for {contest_name}!"
        await util.send(context, message)
        session.close()
Пример #5
0
    async def close(self, context, contest_name=""):
        """
        Closes an open contest
        """
        if not util.is_from_guild(context):
            await context.send("This command must be run from a server.")
            return

        if contest_name == "":
            await context.send(
                "You must include an contest name in this command"
                "\n\tYou must format the command this way: `!drawing close <contest_name>`"
            )
            return

        guild_id = context.message.guild.id
        session = self.sessionmaker()
        contest = session.query(Contest) \
            .filter_by(name=contest_name, guild_id=guild_id) \
            .one_or_none()

        if contest is None:
            session.close()
            await context.send(f"The contest {contest_name} does not exist.")
            return

        if contest.owner_id != context.message.author.id:
            session.close()
            print("Author: {}, Owner: {}".format(context.message.author.id,
                                                 contest.owner_id))
            owner_name = context.message.guild.get_member(
                contest.owner_id).display_name
            await context.send(
                f"Only the owner of {contest_name} ({owner_name}) may close it."
            )
            return

        if not contest.open:
            session.close()
            await context.send(f"The contest {contest_name} is already closed."
                               )
            return

        contest.open = False
        session.commit()

        await context.send(f"The contest {contest_name} has been closed.")
Пример #6
0
    async def winners(self, context, contest_name=""):
        """
        Show winners for a contest
        """
        syntax = "You must format the command this way: `!contest winners contest_name [num_winners|all]`"
        if not util.is_from_guild(context):
            await context.send("This command must be run from a server.")
            return

        if contest_name == "":
            await context.send(
                "You must include an contest name in this command\n\t" +
                syntax)
            return

        session = self.sessionmaker()
        guild_id = context.message.guild.id
        session = self.sessionmaker()
        contest = (session.query(Contest).filter_by(
            name=contest_name, guild_id=guild_id).one_or_none())

        if contest is None:
            session.close()
            await context.send(f"The contest {contest_name} does not exist.")
            return

        if contest.num_winners is None:
            await context.send(f"The contest {contest_name} has no winners")
            return

        winners = (session.query(Entry).filter(
            Entry.contest == contest.cid,
            Entry.win_rank.isnot(None)).order_by(Entry.win_rank).all())

        message = (
            "Congrats to the following winners: \n\t" +
            "\n\t".join([print_rank(winner, context) for winner in winners]))

        await context.send(message)
Пример #7
0
    async def create(self, ctx, name=""):
        """ Create a secret santa """
        if not util.is_from_guild(ctx):
            await util.send(ctx, "This message only works in a server")
            return
        if name == "":
            await util.send(
                ctx, "You must name your secret santa event." +
                "\nExample: `!santa create RT2019`")
            return

        exchange = Exchange(
            name=name,
            guild_id=ctx.message.guild.id,
            owner_id=ctx.message.author.id,
            is_open=True,
        )

        session = self.sessionmaker()
        session.add(exchange)
        try:
            session.commit()
            await util.send(
                ctx,
                f"The Secret Santa exchange {name} has been created and opened."
                + f" Santas may join with the command `!santa join {name}`")
        except IntegrityError:
            session.rollback()
            await util.send(
                ctx,
                f"The exchange name {name} has already been taken. Please try another"
            )
        except:
            session.rollback()
            await util.send(
                ctx, f"An error occurred trying to create exchange {name}")
        session.close()
Пример #8
0
    async def open(self, context, name=""):
        """ Create a contest """
        if not util.is_from_guild(context):
            await util.send(context, "This message only works in a server")
            return
        if name == "":
            await util.send(
                context, "You must name your contest event." +
                "\nExample: `!contest create RT2019`")
            return

        contest = Contest(
            name=name,
            guild_id=context.message.guild.id,
            owner_id=context.message.author.id,
            open=True,
        )

        session = self.sessionmaker()
        session.add(contest)
        try:
            session.commit()
            await util.send(
                context, f"The contest {name} has been created and opened." +
                f" You may join with the command `!contest enter {name}`")
        except IntegrityError:
            session.rollback()
            await util.send(
                context,
                f"The contest name {name} has already been used. Please try another"
            )
        except:
            session.rollback()
            await util.send(
                context, f"An error occurred trying to create contest {name}")
        session.close()
Пример #9
0
    async def close(self, context, exchange_name=""):
        """
        Closes an open exchange and matches santas with targets.
        """
        if not util.is_from_guild(context):
            await context.send("This command must be run from a server.")
            return

        if exchange_name == "":
            await context.send(
                "You must include an exchange name in this command"
                "\n\tYou must format the command this way: `!santa close <exchange_name>`"
            )
            return

        session = self.sessionmaker()
        exchange = session.query(Exchange).filter_by(
            name=exchange_name).one_or_none()

        if exchange is None:
            session.close()
            await context.send(f"The exchange {exchange_name} does not exist.")
            return

        if exchange.owner_id != context.message.author.id:
            session.close()
            print("Author: {}, Owner: {}".format(context.message.author.id,
                                                 exchange.owner_id))
            owner_name = context.message.guild.get_member(
                exchange.owner_id).display_name
            await context.send(
                f"Only the owner of {exchange_name} ({owner_name}) may close it."
            )
            return

        if not exchange.is_open:
            session.close()
            await context.send(
                f"The exchange {exchange_name} is already closed.")
            return

        # Get participants
        participants = [
            part.user_id
            for part in session.query(Registrant.user_id).filter_by(
                exchange=exchange_name).all()
        ]

        # Remove participants who have left the guild
        removed_users = list()
        for participant in participants:
            if context.message.guild.get_member(participant) is None:
                participants.remove(participant)
                user = context.bot.get_user(participant)
                if user is None:
                    removed_users.append(f"Unknown participant {participant}")
                else:
                    removed_users.append(user.name + "#" + user.id)

        if len(removed_users) > 0:
            await context.send(
                f"Users who have left the server have been removed from the exchange: "
                + ", ".join(removed_users))

        if len(participants) < 2:
            session.close()
            await context.send(
                f"There must be at least 2 Santas in {exchange_name} for it to close."
            )
            return

        # Prevent prohibited pairs
        tries = 0
        matches = list()
        while True:
            tries = tries + 1
            matches = match_santa_pairs(participants)

            # Check to see if the match is prohibited
            prohibited = False
            pairs = matches + [(b, a) for a, b in matches]
            for pair in pairs:
                if session.query(ProhibitedMatches).filter(
                        ProhibitedMatches.first_id == pair[0],
                        ProhibitedMatches.second_id == pair[1]).count() > 0:
                    prohibited = True
                    break

            if not prohibited:
                break

            # Break out if we are stuck in a loop
            if prohibited and tries > 100:
                session.close()
                message = f"Unable to make pairs for {exchange_name}. Please add more people and try again."
                await context.send(message)
                return

        pairings = [
            Pairing(
                exchange=exchange_name,
                santa_id=match[0],
                target_id=match[1],
            ) for match in matches
        ]

        # Update the database
        exchange.is_open = False
        session.add_all(pairings)
        session.commit()

        # Alert Santas as to their targets
        awaits = list()
        for santa, target in matches:
            target_name = context.message.guild.get_member(target).display_name
            message = (
                f"Congratulations Santa! You've been assigned {target_name} for {exchange_name}"
                f"\n\nPlease **reply to this message** using the following commands to message your target."
                f"\n\t> To send a message to your target, use `!santa message {exchange_name} Your message`"
                f"\n\t> To send a reply to your santa, use `!santa reply {exchange_name} Your message`"
                "\n\nIt may be worth setting yourself to invisible while communicating with your target to "
                "help keep your identity secret.")
            awaits.append(context.bot.get_user(santa).send(message))

        message = f"The Secret Santa exchange {exchange_name} has been closed and PMs have been sent to Santas.\n"

        awaits.append(context.send(message))

        await wait(awaits)
Пример #10
0
    async def draw(self, context, contest_name="", num_winners=""):
        """
        Draw winners for a contest
        num_winners must be either a positive number, or "all"
        """
        syntax = "You must format the command this way: `!contest draw contest_name [num_winners|all]`"

        if not util.is_from_guild(context):
            await context.send("This command must be run from a server.")
            return

        if contest_name == "":
            await context.send(
                "You must include an contest name in this command\n\t" +
                syntax)
            return

        guild_id = context.message.guild.id
        session = self.sessionmaker()

        contest = session.query(Contest) \
            .filter_by(name=contest_name, guild_id=guild_id) \
            .one_or_none()

        if contest is None:
            session.close()
            await context.send(f"The contest {contest_name} does not exist.")
            return

        if contest.owner_id != context.message.author.id:
            session.close()
            print("Author: {}, Owner: {}".format(context.message.author.id,
                                                 contest.owner_id))
            owner_name = context.message.guild.get_member(
                contest.owner_id).display_name
            await context.send(
                f"Only the owner of {contest_name} ({owner_name}) may close it."
            )
            return

        if num_winners == "":
            num_winners = 1
            all_winners = False
        elif num_winners.lower() == "all":
            all_winners = True
            num_winners = 1  # Temporary, until we get number of entries
        else:
            try:
                num_winners = int(num_winners)
            except:
                await context.send(
                    f"{num_winners} is not a valid number or 'all'\n\t" +
                    syntax)
                return

        if num_winners < 1:
            await context.send(
                f"The number of winners must be greater than 1.\n\t" + syntax)
            return

        if contest.num_winners is not None:
            prev_winners = contest.num_winners
        else:
            prev_winners = 0

        # Get entries who are not winners
        entries = (session.query(Entry).filter(Entry.contest == contest.cid,
                                               Entry.win_rank == None).all())

        # Remove winners
        entries = [entry for entry in entries if entry.win_rank is None]

        # Remove entries who have left the guild
        removed_users = list()
        for entry in entries:
            if context.message.guild.get_member(entry.user_id) is None:
                entries.remove(entry)
                removed_users.append(
                    util.get_displayname(entry.user_id, context))
                session.delete(entry)

        if len(removed_users) > 0:
            await context.send(
                f"Users who have left the server have been removed from the contest: "
                + ", ".join(removed_users))

        if all_winners or len(entries) < num_winners:
            num_winners = len(entries)

        # Randomize order, then pick the top few as winners
        shuffle(entries)
        winners = entries[:num_winners]

        for rank, winner in enumerate(winners, prev_winners + 1):
            winner.win_rank = rank

        contest.num_winners = prev_winners + num_winners

        # Update the database
        session.commit()

        message = (
            "Congrats to the following winners: \n\t" +
            "\n\t".join([print_rank(winner, context) for winner in winners]))

        await context.send(message)