示例#1
0
    async def stop_race_(self, ctx):
        first = database.zrevrange(f"race.scores:{ctx.channel.id}", 0, 0,
                                   True)[0]
        if ctx.guild is not None:
            user = ctx.guild.get_member(int(first[0]))
        else:
            user = None

        if user is None:
            user = self.bot.get_user(int(first[0]))
            if user is None:
                user = "******"
            else:
                user = f"{user.name}#{user.discriminator}"
        else:
            user = f"{user.name}#{user.discriminator} ({user.mention})"

        await ctx.send(
            f"**Congratulations, {user}!**\n" +
            f"You have won the race by correctly identifying `{int(first[1])}` birds. "
            + "*Way to go!*")

        database.hset(f"race.data:{ctx.channel.id}", "stop",
                      round(time.time()))

        await self._send_stats(ctx, "**Race stopped.**")
        database.delete(f"race.data:{ctx.channel.id}")
        database.delete(f"race.scores:{ctx.channel.id}")
示例#2
0
    def test_suite_cleanup_thing(self):
        yield
        database.delete(f"channel:{self.ctx.channel.id}")
        database.zrem("score:global", str(self.ctx.channel.id))

        database.zrem("users:global", str(self.ctx.author.id))
        database.zrem("streak:global", str(self.ctx.author.id))
        database.zrem("streak.max:global", str(self.ctx.author.id))
        database.delete(f"incorrect.user:{self.ctx.author.id}")
        database.delete(f"correct.user:{self.ctx.author.id}")

        if self.ctx.guild is not None:
            database.delete(f"users.server:{self.ctx.guild.id}")
            database.delete(f"incorrect.server:{self.ctx.guild.id}")
示例#3
0
    async def stop(self, ctx):
        logger.info("command: stop session")

        await channel_setup(ctx)
        await user_setup(ctx)

        if database.exists(f"session.data:{ctx.author.id}"):
            database.hset(f"session.data:{ctx.author.id}", "stop", round(time.time()))

            await self._send_stats(ctx, "**Session stopped.**\n")
            database.delete(f"session.data:{ctx.author.id}")
            database.delete(f"session.incorrect:{ctx.author.id}")
        else:
            await ctx.send("**There is no session running.** *You can start one with `b!session start`*")
    def setup(self, guild=False):
        self.bot = mock.Bot()
        self.cog = get_birds.Birds(self.bot)
        self.ctx = mock.Context()

        if guild:
            self.ctx.set_guild()

        database.delete(f"channel:{self.ctx.channel.id}")
        database.zrem("score:global", str(self.ctx.channel.id))

        database.zrem("users:global", str(self.ctx.author.id))
        database.zrem("streak:global", str(self.ctx.author.id))
        database.zrem("streak.max:global", str(self.ctx.author.id))

        if self.ctx.guild is not None:
            database.delete(f"users.server:{self.ctx.guild.id}")
示例#5
0
    def setup(self, guild=False):
        # pylint: disable=attribute-defined-outside-init
        self.bot = mock.Bot()
        self.cog = score.Score(self.bot)
        self.ctx = mock.Context(self.bot)

        if guild:
            self.ctx.set_guild()

        database.delete(f"channel:{self.ctx.channel.id}")
        database.zrem("score:global", str(self.ctx.channel.id))

        database.zrem("users:global", str(self.ctx.author.id))
        database.zrem("streak:global", str(self.ctx.author.id))
        database.zrem("streak.max:global", str(self.ctx.author.id))

        if self.ctx.guild is not None:
            database.delete(f"users.server:{self.ctx.guild.id}")

        asyncio.run(channel_setup(self.ctx))
        asyncio.run(user_setup(self.ctx))
示例#6
0
    async def leave(self, ctx, confirm: typing.Optional[bool] = False):
        logger.info("command: leave")

        if database.exists(f"leave:{ctx.guild.id}"):
            logger.info("confirming")
            if confirm:
                logger.info(f"confirmed. Leaving {ctx.guild}")
                database.delete(f"leave:{ctx.guild.id}")
                await ctx.send("**Ok, bye!**")
                await ctx.guild.leave()
                return
            logger.info("confirm failed. leave canceled")
            database.delete(f"leave:{ctx.guild.id}")
            await ctx.send("**Leave canceled.**")
            return

        logger.info("not confirmed")
        database.set(f"leave:{ctx.guild.id}", 0, ex=60)
        await ctx.send(
            "**Are you sure you want to remove me from the guild?**\n" +
            "Use `b!leave yes` to confirm, `b!leave no` to cancel. " +
            "You have 60 seconds to confirm before it will automatically cancel."
        )
示例#7
0
    async def stop_race_(self, ctx):
        if Filter.from_int(
                int(database.hget(f"race.data:{ctx.channel.id}",
                                  "filter"))).vc:
            await voice_functions.disconnect(ctx, silent=True)
            database.delete(f"voice.server:{ctx.guild.id}")

        first = database.zrevrange(f"race.scores:{ctx.channel.id}", 0, 0,
                                   True)[0]
        if ctx.guild is not None:
            user = await fetch_get_user(int(first[0]), ctx=ctx, member=True)
        else:
            user = None

        if user is None:
            user = await fetch_get_user(int(first[0]), ctx=ctx, member=False)
            if user is None:
                user_info = "Deleted"
            else:
                user_info = f"{esc(user.name)}#{user.discriminator}"
        else:
            user_info = f"{esc(user.name)}#{user.discriminator} ({user.mention})"

        await ctx.send(
            f"**Congratulations, {user_info}!**\n" +
            f"You have won the race by correctly identifying `{int(first[1])}` birds. "
            + "*Way to go!*")

        database.hset(f"race.data:{ctx.channel.id}", "stop",
                      round(time.time()))

        await self._send_stats(ctx, "**Race stopped.**")
        database.delete(f"race.data:{ctx.channel.id}")
        database.delete(f"race.scores:{ctx.channel.id}")

        logger.info("race end: skipping last bird")
        database.hset(f"channel:{ctx.channel.id}", "bird", "")
        database.hset(f"channel:{ctx.channel.id}", "answered", "1")
示例#8
0
    async def custom(self, ctx, *, args=""):
        logger.info("command: custom list set")

        args = args.lower().strip().split(" ")
        logger.info(f"parsed args: {args}")

        if ("replace" not in args and ctx.message.attachments
                and database.exists(f"custom.list:{ctx.author.id}")):
            await ctx.send(
                "Woah there. You already have a custom list. " +
                "To view its contents, use `b!custom view`. " +
                "If you want to replace your list, upload the file with `b!custom replace`."
            )
            return

        if "delete" in args and database.exists(
                f"custom.list:{ctx.author.id}"):
            if (database.exists(f"custom.confirm:{ctx.author.id}")
                    and database.get(f"custom.confirm:{ctx.author.id}").decode(
                        "utf-8") == "delete"):
                database.delete(f"custom.list:{ctx.author.id}",
                                f"custom.confirm:{ctx.author.id}")
                await ctx.send("Ok, your list was deleted.")
                return

            database.set(f"custom.confirm:{ctx.author.id}", "delete", ex=86400)
            await ctx.send(
                "Are you sure you want to permanently delete your list? " +
                "Use `b!custom delete` again within 24 hours to clear your custom list."
            )
            return

        if ("confirm" in args
                and database.exists(f"custom.confirm:{ctx.author.id}") and
                database.get(f"custom.confirm:{ctx.author.id}").decode("utf-8")
                == "confirm"):
            # list was validated by server and user, making permanent
            logger.info("user confirmed")
            database.persist(f"custom.list:{ctx.author.id}")
            database.delete(f"custom.confirm:{ctx.author.id}")
            database.set(f"custom.cooldown:{ctx.author.id}", 0, ex=86400)
            await ctx.send(
                "Ok, your custom bird list is now available. Use `b!custom view` "
                +
                "to view your list. You can change your list again in 24 hours."
            )
            return

        if ("validate" in args
                and database.exists(f"custom.confirm:{ctx.author.id}") and
                database.get(f"custom.confirm:{ctx.author.id}").decode("utf-8")
                == "valid"):
            # list was validated, now for user confirm
            logger.info("valid list, user needs to confirm")
            database.expire(f"custom.list:{ctx.author.id}", 86400)
            database.set(f"custom.confirm:{ctx.author.id}",
                         "confirm",
                         ex=86400)
            birdlist = "\n".join(
                bird.decode("utf-8")
                for bird in database.smembers(f"custom.list:{ctx.author.id}"))
            await ctx.send(
                f"**Please confirm the following list.** ({int(database.scard(f'custom.list:{ctx.author.id}'))} items)"
            )
            await self.broken_send(ctx, birdlist, between="```\n")
            await ctx.send(
                "Once you have looked over the list and are sure you want to add it, "
                +
                "please use `b!custom confirm` to have this list added as a custom list. "
                + "You have another 24 hours to confirm. " +
                "To start over, upload a new list with the message `b!custom replace`."
            )
            return

        if "view" in args:
            if not database.exists(f"custom.list:{ctx.author.id}"):
                await ctx.send(
                    "You don't have a custom list. To add a custom list, " +
                    "upload a txt file with a bird's name on each line to this DM "
                    + "and put `b!custom` in the **Add a Comment** section.")
                return
            birdlist = "\n".join(
                bird.decode("utf-8")
                for bird in database.smembers(f"custom.list:{ctx.author.id}"))
            birdlist = f"{birdlist}"
            await ctx.send(
                f"**Your Custom Bird List** ({int(database.scard(f'custom.list:{ctx.author.id}'))} items)"
            )
            await self.broken_send(ctx, birdlist, between="```\n")
            return

        if not database.exists(
                f"custom.list:{ctx.author.id}") or "replace" in args:
            # user inputted bird list, now validating
            start = time.perf_counter()
            if database.exists(f"custom.cooldown:{ctx.author.id}"):
                await ctx.send(
                    "Sorry, you'll have to wait 24 hours between changing lists."
                )
                return
            logger.info("reading received bird list")
            if not ctx.message.attachments:
                logger.info("no file detected")
                await ctx.send(
                    "Sorry, no file was detected. Upload your txt file and put `b!custom` in the **Add a Comment** section."
                )
                return
            decoded = await auto_decode(await
                                        ctx.message.attachments[0].read())
            if not decoded:
                logger.info("invalid character encoding")
                await ctx.send(
                    "Sorry, something went wrong. Are you sure this is a text file?"
                )
                return
            parsed_birdlist = set(
                map(lambda x: x.strip(),
                    decoded.strip().split("\n")))
            parsed_birdlist.discard("")
            parsed_birdlist = list(parsed_birdlist)
            if len(parsed_birdlist) > 200:
                logger.info("parsed birdlist too long")
                await ctx.send(
                    "Sorry, we're not supporting custom lists larger than 200 birds. Make sure there are no empty lines."
                )
                return
            logger.info("checking for invalid characters")
            char = re.compile(r"[^A-Za-z '\-\xC0-\xD6\xD8-\xF6\xF8-\xFF]")
            for item in parsed_birdlist:
                if len(item) > 1000:
                    logger.info("item too long")
                    await ctx.send(
                        f"Line starting with `{item[:100]}` exceeds 1000 characters."
                    )
                    return
                search = char.search(item)
                if search:
                    logger.info("invalid character detected")
                    await ctx.send(
                        f"An invalid character `{search.group()}` was detected. Only letters, spaces, hyphens, and apostrophes are allowed."
                    )
                    await ctx.send(
                        f"Error on line starting with `{item[:100]}`, position {search.span()[0]}"
                    )
                    return
            database.delete(f"custom.list:{ctx.author.id}",
                            f"custom.confirm:{ctx.author.id}")
            await self.validate(ctx, parsed_birdlist)
            elapsed = time.perf_counter() - start
            await ctx.send(
                f"**Finished validation in {round(elapsed//60)} minutes {round(elapsed%60, 4)} seconds.** {ctx.author.mention}"
            )
            logger.info(
                f"Finished validation in {round(elapsed//60)} minutes {round(elapsed%60, 4)} seconds."
            )
            return

        if database.exists(f"custom.confirm:{ctx.author.id}"):
            next_step = database.get(f"custom.confirm:{ctx.author.id}").decode(
                "utf-8")
            if next_step == "valid":
                await ctx.send(
                    "You need to validate your list. Use `b!custom validate` to do so. "
                    +
                    "You can also delete or replace your list with `b!custom [delete|replace]`"
                )
                return
            if next_step == "confirm":
                await ctx.send(
                    "You need to confirm your list. Use `b!custom confirm` to do so. "
                    +
                    "You can also delete or replace your list with `b!custom [delete|replace]`"
                )
                return
            if next_step == "delete":
                await ctx.send(
                    "You're in the process of deleting your list. Use `b!custom delete` to do so. "
                    + "You can also replace your list with `b!custom replace`")
                return
            capture_message(
                f"custom.confirm database invalid with {next_step}")
            await ctx.send(
                "Whoops, something went wrong. Please report this incident " +
                "in the support server below.\nhttps://discord.gg/2HbshwGjnm")
            return

        await ctx.send(
            "Use `b!custom view` to view your bird list or `b!custom replace` to replace your bird list."
        )