Exemple #1
0
    async def userscore(
        self, ctx, *, user: typing.Optional[typing.Union[discord.Member, str]] = None
    ):
        logger.info("command: userscore")

        if user is not None:
            if isinstance(user, str):
                await ctx.send("Not a user!")
                return
            usera = user.id
            logger.info(usera)
            score = database.zscore("users:global", str(usera))
            if score is not None:
                score = int(score)
                user = f"<@{usera}>"
            else:
                await ctx.send("This user does not exist on our records!")
                return
        else:
            user = f"<@{ctx.author.id}>"
            score = int(database.zscore("users:global", str(ctx.author.id)))

        embed = discord.Embed(type="rich", colour=discord.Color.blurple())
        embed.set_author(name="Bird ID - An Ornithology Bot")
        embed.add_field(
            name="User Score:", value=f"{user} has answered correctly {score} times."
        )
        await ctx.send(embed=embed)
Exemple #2
0
    def moderation_check(ctx):
        """Checks different moderation checks.

        Disallows:
        - Users that are banned from the bot,
        - Channels that are ignored
        """
        logger.info("global check: checking banned")
        if database.zscore("ignore:global", str(ctx.channel.id)) is not None:
            raise GenericError(code=192)
        if database.zscore("banned:global", str(ctx.author.id)) is not None:
            raise GenericError(code=842)
        return True
Exemple #3
0
async def user_setup(ctx):
    """Sets up a new discord user for score tracking.

    `ctx` - Discord context object or user id
    """
    if isinstance(ctx, (str, int)):
        user_id = str(ctx)
        guild = None
        ctx = None
    else:
        user_id = str(ctx.author.id)
        guild = ctx.guild

    logger.info("checking user data")
    if database.zscore("users:global", user_id) is None:
        database.zadd("users:global", {user_id: 0})
        logger.info("user global added")
        if ctx is not None:
            await ctx.send("Welcome <@" + user_id + ">!")

    date = str(datetime.datetime.now(datetime.timezone.utc).date())
    if database.zscore(f"daily.score:{date}", user_id) is None:
        database.zadd(f"daily.score:{date}", {user_id: 0})
        logger.info("user daily added")

    # Add streak
    if (database.zscore("streak:global", user_id) is None) or (database.zscore(
            "streak.max:global", user_id) is None):
        database.zadd("streak:global", {user_id: 0})
        database.zadd("streak.max:global", {user_id: 0})
        logger.info("added streak")

    if guild is not None:
        global_score = database.zscore("users:global", str(ctx.author.id))
        database.zadd(f"users.server:{ctx.guild.id}",
                      {str(ctx.author.id): global_score})
        logger.info("synced scores")

        if not database.exists(f"custom.list:{ctx.author.id}"):
            role_ids = [role.id for role in ctx.author.roles]
            role_names = [role.name.lower() for role in ctx.author.roles]
            if set(role_names).intersection(set(states["CUSTOM"]["aliases"])):
                index = role_names.index(
                    states["CUSTOM"]["aliases"][0].lower())
                role = ctx.guild.get_role(role_ids[index])
                await ctx.author.remove_roles(
                    role, reason="Remove state role for bird list")
                logger.info("synced roles")
Exemple #4
0
async def channel_setup(ctx):
    """Sets up a new discord channel.
    
    `ctx` - Discord context object
    """
    logger.info("checking channel setup")
    if database.exists(f"channel:{ctx.channel.id}"):
        logger.info("channel data ok")
    else:
        database.hmset(
            f"channel:{ctx.channel.id}", {
                "bird": "",
                "answered": 1,
                "sBird": "",
                "sAnswered": 1,
                "goatsucker": "",
                "gsAnswered": 1,
                "prevJ": 20,
                "prevB": "",
                "prevS": "",
                "prevK": 20
            })
        # true = 1, false = 0, index 0 is last arg, prevJ is 20 to define as integer
        logger.info("channel data added")
        await ctx.send("Ok, setup! I'm all ready to use!")

    if database.zscore("score:global", str(ctx.channel.id)) is not None:
        logger.info("channel score ok")
    else:
        database.zadd("score:global", {str(ctx.channel.id): 0})
        logger.info("channel score added")
Exemple #5
0
async def channel_setup(ctx):
    """Sets up a new discord channel.

    `ctx` - Discord context object
    """
    logger.info("checking channel setup")
    if database.exists(f"channel:{ctx.channel.id}"):
        logger.info("channel data ok")
    else:
        database.hset(
            f"channel:{ctx.channel.id}",
            mapping={"bird": "", "answered": 1, "prevB": "", "prevJ": 20},
        )
        # true = 1, false = 0, index 0 is last arg, prevJ is 20 to define as integer
        logger.info("channel data added")
        await ctx.send("Ok, setup! I'm all ready to use!")

    if database.zscore("score:global", str(ctx.channel.id)) is not None:
        logger.info("channel score ok")
    else:
        database.zadd("score:global", {str(ctx.channel.id): 0})
        logger.info("channel score added")

    if ctx.guild is not None:
        if (
            database.zadd("channels:global", {f"{ctx.guild.id}:{ctx.channel.id}": 0})
            != 0
        ):
            logger.info("server lookup ok")
        else:
            logger.info("server lookup added")
Exemple #6
0
    async def _send_stats(self, ctx, preamble):
        placings = 5
        database_key = f"race.scores:{ctx.channel.id}"
        if database.zcard(database_key) == 0:
            logger.info(f"no users in {database_key}")
            await ctx.send("There are no users in the database.")
            return

        if placings > database.zcard(database_key):
            placings = database.zcard(database_key)

        leaderboard_list = database.zrevrangebyscore(
            database_key, "+inf", "-inf", 0, placings, True
        )
        embed = discord.Embed(
            type="rich", colour=discord.Color.blurple(), title=preamble
        )
        embed.set_author(name="Bird ID - An Ornithology Bot")
        leaderboard = ""

        for i, stats in enumerate(leaderboard_list):
            if ctx.guild is not None:
                user = await fetch_get_user(int(stats[0]), ctx=ctx, member=True)
            else:
                user = None

            if user is None:
                user = await fetch_get_user(int(stats[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})"

            leaderboard += f"{i+1}. {user_info} - {int(stats[1])}\n"

        start = int(database.hget(f"race.data:{ctx.channel.id}", "start"))
        elapsed = str(datetime.timedelta(seconds=round(time.time()) - start))

        embed.add_field(
            name="Options", value=await self._get_options(ctx), inline=False
        )
        embed.add_field(
            name="Stats", value=f"**Race Duration:** `{elapsed}`", inline=False
        )
        embed.add_field(name="Leaderboard", value=leaderboard, inline=False)

        if ctx.author:
            if database.zscore(database_key, str(ctx.author.id)) is not None:
                placement = int(database.zrevrank(database_key, str(ctx.author.id))) + 1
                embed.add_field(
                    name="You:", value=f"You are #{placement}.", inline=False
                )
            else:
                embed.add_field(
                    name="You:", value="You haven't answered any correctly."
                )

        await ctx.send(embed=embed)
Exemple #7
0
 def user_banned(ctx):
     """Disallows users that are banned from the bot."""
     logger.info("global check: checking banned")
     if database.zscore("banned:global", str(ctx.author.id)) is None:
         return True
     else:
         raise GenericError(code=842)
Exemple #8
0
    async def ignore(self,
                     ctx,
                     channels: commands.Greedy[discord.TextChannel] = None):
        logger.info("command: invite")

        added = ""
        removed = ""
        if channels is not None:
            logger.info(f"ignored channels: {[c.name for c in channels]}")
            for channel in channels:
                if database.zscore("ignore:global", str(channel.id)) is None:
                    added += f"`#{channel.name}` (`{channel.category.name if channel.category else 'No Category'}`)\n"
                    database.zadd("ignore:global",
                                  {str(channel.id): ctx.guild.id})
                else:
                    removed += f"`#{channel.name}` (`{channel.category.name if channel.category else 'No Category'}`)\n"
                    database.zrem("ignore:global", str(channel.id))
        else:
            await ctx.send("**No valid channels were passed.**")

        ignored = "".join([
            f"`#{channel.name}` (`{channel.category.name if channel.category else 'No Category'}`)\n"
            for channel in map(
                lambda c: ctx.guild.get_channel(int(c)),
                database.zrangebyscore("ignore:global", ctx.guild.id -
                                       0.1, ctx.guild.id + 0.1),
            )
        ])

        await ctx.send(
            (f"**Ignoring:**\n{added}" if added else "") +
            (f"**Stopped ignoring:**\n{removed}" if removed else "") +
            (f"**Ignored Channels:**\n{ignored}" if ignored else
             "**No channels in this server are currently ignored.**"))
Exemple #9
0
async def bird_setup(ctx, bird: str):
    """Sets up a new bird for incorrect tracking.
    
    `ctx` - Discord context object
    `bird` - bird to setup
    """
    logger.info("checking bird data")
    if database.zscore("incorrect:global", string.capwords(bird)) is not None:
        logger.info("bird global ok")
    else:
        database.zadd("incorrect:global", {string.capwords(bird): 0})
        logger.info("bird global added")

    if database.zscore(f"incorrect.user:{ctx.author.id}",
                       string.capwords(bird)) is not None:
        logger.info("bird user ok")
    else:
        database.zadd(f"incorrect.user:{ctx.author.id}",
                      {string.capwords(bird): 0})
        logger.info("bird user added")

    if ctx.guild is not None:
        logger.info("no dm")
        if database.zscore(f"incorrect.server:{ctx.guild.id}",
                           string.capwords(bird)) is not None:
            logger.info("bird server ok")
        else:
            database.zadd(f"incorrect.server:{ctx.guild.id}",
                          {string.capwords(bird): 0})
            logger.info("bird server added")
    else:
        logger.info("dm context")

    if database.exists(f"session.data:{ctx.author.id}"):
        logger.info("session in session")
        if database.zscore(f"session.incorrect:{ctx.author.id}",
                           string.capwords(bird)) is not None:
            logger.info("bird session ok")
        else:
            database.zadd(f"session.incorrect:{ctx.author.id}",
                          {string.capwords(bird): 0})
            logger.info("bird session added")
    else:
        logger.info("no session")
Exemple #10
0
    async def streak(self, ctx):
        if ctx.invoked_subcommand is not None:
            return
        logger.info("command: streak")
        args = " ".join(ctx.message.content.split(" ")[1:])
        if args:
            user = await commands.MemberConverter().convert(ctx, args)
        else:
            user = None

        if user is not None:
            if isinstance(user, str):
                await ctx.send("Not a user!")
                return
            usera = user.id
            logger.info(usera)
            streak = database.zscore("streak:global", str(usera))
            max_streak = database.zscore("streak.max:global", str(usera))
            if streak is not None and max_streak is not None:
                streak = int(streak)
                max_streak = int(max_streak)
                user = f"<@{usera}>"
            else:
                await ctx.send("This user does not exist on our records!")
                return
        else:
            user = f"<@{ctx.author.id}>"
            streak = int(database.zscore("streak:global", str(ctx.author.id)))
            max_streak = int(
                database.zscore("streak.max:global", str(ctx.author.id)))

        embed = discord.Embed(type="rich",
                              colour=discord.Color.blurple(),
                              title="**User Streaks**")
        embed.set_author(name="Bird ID - An Ornithology Bot")
        current_streak = f"{user} has answered `{streak}` in a row!"
        max_streak = f"{user}'s max was `{max_streak}` in a row!"
        embed.add_field(name="**Current Streak**",
                        value=current_streak,
                        inline=False)
        embed.add_field(name="**Max Streak**", value=max_streak, inline=False)

        await ctx.send(embed=embed)
Exemple #11
0
    async def prechecks(ctx):
        await ctx.trigger_typing()

        logger.info("global check: checking permissions")
        await commands.bot_has_permissions(send_messages=True,
                                           embed_links=True,
                                           attach_files=True).predicate(ctx)

        logger.info("global check: checking banned")
        if database.zscore("ignore:global", str(ctx.channel.id)) is not None:
            raise GenericError(code=192)
        if database.zscore("banned:global", str(ctx.author.id)) is not None:
            raise GenericError(code=842)

        logger.info("global check: logging command frequency")
        database.zincrby("frequency.command:global", 1, str(ctx.command))

        logger.info("global check: database setup")
        await channel_setup(ctx)
        await user_setup(ctx)

        return True
Exemple #12
0
def streak_increment(ctx, amount: int):
    """Increments the streak of a user by `amount`.

    `ctx` - Discord context object or user id\n
    `amount` (int) - amount to increment by, usually 1.
    If amount is None, the streak is ended.
    """
    if isinstance(ctx, (str, int)):
        user_id = str(ctx)
    else:
        user_id = str(ctx.author.id)

    if amount is not None:
        # increment streak and update max
        database.zincrby("streak:global", amount, user_id)
        if database.zscore("streak:global", user_id) > database.zscore(
                "streak.max:global", user_id):
            database.zadd(
                "streak.max:global",
                {user_id: database.zscore("streak:global", user_id)},
            )
    else:
        database.zadd("streak:global", {user_id: 0})
Exemple #13
0
    async def score(self, ctx, scope=""):
        logger.info("command: score")

        if scope in ("server", "s"):
            total_correct = self._server_total(ctx)
            await ctx.send(
                f"Wow, looks like a total of `{total_correct}` birds have been answered correctly in this **server**!\n"
                + "Good job everyone!")
        else:
            total_correct = int(
                database.zscore("score:global", str(ctx.channel.id)))
            await ctx.send(
                f"Wow, looks like a total of `{total_correct}` birds have been answered correctly in this **channel**!\n"
                + "Good job everyone!")
Exemple #14
0
async def user_setup(ctx):
    """Sets up a new discord user for score tracking.
    
    `ctx` - Discord context object
    """
    logger.info("checking user data")
    if database.zscore("users:global", str(ctx.author.id)) is not None:
        logger.info("user global ok")
    else:
        database.zadd("users:global", {str(ctx.author.id): 0})
        logger.info("user global added")
        await ctx.send("Welcome <@" + str(ctx.author.id) + ">!")

    #Add streak
    if (database.zscore("streak:global", str(ctx.author.id))
            is not None) and (database.zscore("streak.max:global",
                                              str(ctx.author.id)) is not None):
        logger.info("user streak in already")
    else:
        database.zadd("streak:global", {str(ctx.author.id): 0})
        database.zadd("streak.max:global", {str(ctx.author.id): 0})
        logger.info("added streak")

    if ctx.guild is not None:
        logger.info("no dm")
        if database.zscore(f"users.server:{ctx.guild.id}",
                           str(ctx.author.id)) is not None:
            server_score = database.zscore(f"users.server:{ctx.guild.id}",
                                           str(ctx.author.id))
            global_score = database.zscore("users:global", str(ctx.author.id))
            if server_score is global_score:
                logger.info("user server ok")
            else:
                database.zadd(f"users.server:{ctx.guild.id}",
                              {str(ctx.author.id): global_score})
        else:
            score = int(database.zscore("users:global", str(ctx.author.id)))
            database.zadd(f"users.server:{ctx.guild.id}",
                          {str(ctx.author.id): score})
            logger.info("user server added")
    else:
        logger.info("dm context")
Exemple #15
0
    async def check(self, ctx, *, arg):
        logger.info("command: check")

        await channel_setup(ctx)
        await user_setup(ctx)

        currentBird = database.hget(f"channel:{ctx.channel.id}",
                                    "bird").decode("utf-8")
        if currentBird == "":  # no bird
            await ctx.send("You must ask for a bird first!")
        else:  # if there is a bird, it checks answer
            logger.info("currentBird: " +
                        str(currentBird.lower().replace("-", " ")))
            logger.info("args: " + str(arg.lower().replace("-", " ")))

            await bird_setup(ctx, currentBird)
            sciBird = await get_sciname(currentBird)
            if spellcheck(arg, currentBird) or spellcheck(arg, sciBird):
                logger.info("correct")

                database.hset(f"channel:{ctx.channel.id}", "bird", "")
                database.hset(f"channel:{ctx.channel.id}", "answered", "1")

                if database.exists(f"session.data:{ctx.author.id}"):
                    logger.info("session active")
                    session_increment(ctx, "correct", 1)

                database.zincrby("streak:global", 1, str(ctx.author.id))
                # check if streak is greater than max, if so, increases max
                if database.zscore("streak:global", str(
                        ctx.author.id)) > database.zscore(
                            "streak.max:global", str(ctx.author.id)):
                    database.zadd(
                        "streak.max:global", {
                            str(ctx.author.id):
                            database.zscore("streak:global", str(
                                ctx.author.id))
                        })

                await ctx.send("Correct! Good job!" if not database.
                               exists(f"race.data:{ctx.channel.id}") else
                               f"**{ctx.author.mention}**, you are correct!")
                url = get_wiki_url(currentBird)
                await ctx.send(url if not database.exists(
                    f"race.data:{ctx.channel.id}") else f"<{url}>")
                score_increment(ctx, 1)
                if int(database.zscore("users:global",
                                       str(ctx.author.id))) in achievement:
                    number = str(
                        int(database.zscore("users:global",
                                            str(ctx.author.id))))
                    await ctx.send(
                        f"Wow! You have answered {number} birds correctly!")
                    filename = f"bot/media/achievements/{number}.PNG"
                    with open(filename, 'rb') as img:
                        await ctx.send(
                            file=discord.File(img, filename="award.png"))

                if database.exists(f"race.data:{ctx.channel.id}") and str(
                        database.hget(f"race.data:{ctx.channel.id}",
                                      "media"))[2:-1] == "image":

                    limit = int(
                        database.hget(f"race.data:{ctx.channel.id}", "limit"))
                    first = database.zrevrange(f"race.scores:{ctx.channel.id}",
                                               0, 0, True)[0]
                    if int(first[1]) >= limit:
                        logger.info("race ending")
                        race = self.bot.get_cog("Race")
                        await race.stop_race_(ctx)
                    else:
                        logger.info("auto sending next bird image")
                        addon, bw, taxon = database.hmget(
                            f"race.data:{ctx.channel.id}",
                            ["addon", "bw", "taxon"])
                        birds = self.bot.get_cog("Birds")
                        await birds.send_bird_(ctx, addon.decode("utf-8"),
                                               bw.decode("utf-8"),
                                               taxon.decode("utf-8"))

            else:
                logger.info("incorrect")

                database.zadd("streak:global", {str(ctx.author.id): 0})

                if database.exists(f"session.data:{ctx.author.id}"):
                    logger.info("session active")
                    session_increment(ctx, "incorrect", 1)

                incorrect_increment(ctx, str(currentBird), 1)

                if database.exists(f"race.data:{ctx.channel.id}"):
                    await ctx.send("Sorry, that wasn't the right answer.")
                else:
                    database.hset(f"channel:{ctx.channel.id}", "bird", "")
                    database.hset(f"channel:{ctx.channel.id}", "answered", "1")
                    await ctx.send("Sorry, the bird was actually " +
                                   currentBird.lower() + ".")
                    url = get_wiki_url(currentBird)
                    await ctx.send(url)
Exemple #16
0
    async def checkgoat(self, ctx, *, arg):
        logger.info("command: checkgoat")

        await channel_setup(ctx)
        await user_setup(ctx)

        currentBird = database.hget(f"channel:{ctx.channel.id}",
                                    "goatsucker").decode("utf-8")
        if currentBird == "":  # no bird
            await ctx.send("You must ask for a bird first!")
        else:  # if there is a bird, it checks answer
            await bird_setup(ctx, currentBird)
            index = goatsuckers.index(currentBird)
            sciBird = sciGoat[index]
            database.hset(f"channel:{ctx.channel.id}", "gsAnswered", "1")
            database.hset(f"channel:{ctx.channel.id}", "goatsucker", "")
            if spellcheck(arg, currentBird) or spellcheck(arg, sciBird):
                logger.info("correct")

                if database.exists(f"session.data:{ctx.author.id}"):
                    logger.info("session active")
                    session_increment(ctx, "correct", 1)

                # increment streak and update max
                database.zincrby("streak:global", 1, str(ctx.author.id))
                if database.zscore("streak:global", str(
                        ctx.author.id)) > database.zscore(
                            "streak.max:global", str(ctx.author.id)):
                    database.zadd(
                        "streak.max:global", {
                            str(ctx.author.id):
                            database.zscore("streak:global", str(
                                ctx.author.id))
                        })

                await ctx.send("Correct! Good job!")
                url = get_wiki_url(currentBird)
                await ctx.send(url)
                score_increment(ctx, 1)
                if int(database.zscore("users:global",
                                       str(ctx.author.id))) in achievement:
                    number = str(
                        int(database.zscore("users:global",
                                            str(ctx.author.id))))
                    await ctx.send(
                        f"Wow! You have answered {number} birds correctly!")
                    filename = f"bot/media/achievements/{number}.PNG"
                    with open(filename, 'rb') as img:
                        await ctx.send(
                            file=discord.File(img, filename="award.png"))

            else:
                logger.info("incorrect")

                database.zadd("streak:global", {str(ctx.author.id): 0})

                if database.exists(f"session.data:{ctx.author.id}"):
                    logger.info("session active")
                    session_increment(ctx, "incorrect", 1)

                incorrect_increment(ctx, str(currentBird), 1)
                await ctx.send("Sorry, the bird was actually " +
                               currentBird.lower() + ".")
                url = get_wiki_url(currentBird)
                await ctx.send(url)
            logger.info("currentBird: " +
                        str(currentBird.lower().replace("-", " ")))
            logger.info("args: " + str(arg.lower().replace("-", " ")))
Exemple #17
0
    async def check(self, ctx, *, arg):
        logger.info("command: check")

        currentBird = database.hget(f"channel:{ctx.channel.id}",
                                    "bird").decode("utf-8")
        if currentBird == "":  # no bird
            await ctx.send("You must ask for a bird first!")
            return
        # if there is a bird, it checks answer
        sciBird = (await get_sciname(currentBird)).lower().replace("-", " ")
        arg = arg.lower().replace("-", " ")
        currentBird = currentBird.lower().replace("-", " ")
        alpha_code = alpha_codes.get(string.capwords(currentBird))
        logger.info("currentBird: " + currentBird)
        logger.info("arg: " + arg)

        bird_setup(ctx, currentBird)

        race_in_session = bool(database.exists(f"race.data:{ctx.channel.id}"))
        if race_in_session:
            logger.info("race in session")
            if database.hget(f"race.data:{ctx.channel.id}", "strict"):
                logger.info("strict spelling")
                correct = arg in (currentBird, sciBird)
            else:
                logger.info("spelling leniency")
                correct = spellcheck(arg, currentBird) or spellcheck(
                    arg, sciBird)

            if not correct and database.hget(f"race.data:{ctx.channel.id}",
                                             "alpha"):
                logger.info("checking alpha codes")
                correct = arg.upper() == alpha_code
        else:
            logger.info("no race")
            if database.hget(f"session.data:{ctx.author.id}", "strict"):
                logger.info("strict spelling")
                correct = arg in (currentBird, sciBird)
            else:
                logger.info("spelling leniency")
                correct = (spellcheck(arg, currentBird)
                           or spellcheck(arg, sciBird)
                           or arg.upper() == alpha_code)

        if correct:
            logger.info("correct")

            database.hset(f"channel:{ctx.channel.id}", "bird", "")
            database.hset(f"channel:{ctx.channel.id}", "answered", "1")

            session_increment(ctx, "correct", 1)
            streak_increment(ctx, 1)
            database.zincrby(f"correct.user:{ctx.author.id}", 1,
                             string.capwords(str(currentBird)))

            if (race_in_session and Filter.from_int(
                    int(database.hget(f"race.data:{ctx.channel.id}",
                                      "filter"))).vc):
                await voice_functions.stop(ctx, silent=True)

            await ctx.send(
                f"Correct! Good job! The bird was **{currentBird}**."
                if not race_in_session else
                f"**{ctx.author.mention}**, you are correct! The bird was **{currentBird}**."
            )
            url = get_wiki_url(ctx, currentBird)
            await ctx.send(url)
            score_increment(ctx, 1)
            if int(database.zscore("users:global",
                                   str(ctx.author.id))) in achievement:
                number = str(
                    int(database.zscore("users:global", str(ctx.author.id))))
                await ctx.send(
                    f"Wow! You have answered {number} birds correctly!")
                filename = f"bot/media/achievements/{number}.PNG"
                with open(filename, "rb") as img:
                    await ctx.send(file=discord.File(img, filename="award.png")
                                   )

            if race_in_session:
                media = database.hget(f"race.data:{ctx.channel.id}",
                                      "media").decode("utf-8")

                limit = int(
                    database.hget(f"race.data:{ctx.channel.id}", "limit"))
                first = database.zrevrange(f"race.scores:{ctx.channel.id}", 0,
                                           0, True)[0]
                if int(first[1]) >= limit:
                    logger.info("race ending")
                    race = self.bot.get_cog("Race")
                    await race.stop_race_(ctx)
                else:
                    logger.info(f"auto sending next bird {media}")
                    filter_int, taxon, state = database.hmget(
                        f"race.data:{ctx.channel.id}",
                        ["filter", "taxon", "state"])
                    birds = self.bot.get_cog("Birds")
                    await birds.send_bird_(
                        ctx,
                        media,
                        Filter.from_int(int(filter_int)),
                        taxon.decode("utf-8"),
                        state.decode("utf-8"),
                    )

        else:
            logger.info("incorrect")

            streak_increment(ctx, None)  # reset streak
            session_increment(ctx, "incorrect", 1)
            incorrect_increment(ctx, str(currentBird), 1)

            if race_in_session:
                await ctx.send("Sorry, that wasn't the right answer.")
            else:
                database.hset(f"channel:{ctx.channel.id}", "bird", "")
                database.hset(f"channel:{ctx.channel.id}", "answered", "1")
                await ctx.send("Sorry, the bird was actually **" +
                               currentBird + "**.")
                url = get_wiki_url(ctx, currentBird)
                await ctx.send(url)
Exemple #18
0
    async def user_lb(self, ctx, title, page, database_key=None, data=None):
        if database_key is None and data is None:
            raise GenericError("database_key and data are both NoneType", 990)
        if database_key is not None and data is not None:
            raise GenericError("database_key and data are both set", 990)

        if page < 1:
            page = 1

        user_amount = (
            int(database.zcard(database_key))
            if database_key is not None
            else data.count()
        )
        page = (page * 10) - 10

        if user_amount == 0:
            logger.info(f"no users in {database_key}")
            await ctx.send("There are no users in the database.")
            return

        if page >= user_amount:
            page = user_amount - (user_amount % 10 if user_amount % 10 != 0 else 10)

        users_per_page = 10
        leaderboard_list = (
            database.zrevrangebyscore(
                database_key, "+inf", "-inf", page, users_per_page, True
            )
            if database_key is not None
            else data.iloc[page : page + users_per_page - 1].items()
        )

        embed = discord.Embed(type="rich", colour=discord.Color.blurple())
        embed.set_author(name="Bird ID - An Ornithology Bot")
        leaderboard = ""

        for i, stats in enumerate(leaderboard_list):
            if ctx.guild is not None:
                user = ctx.guild.get_member(int(stats[0]))
            else:
                user = None

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

            leaderboard += f"{i+1+page}. {user} - {int(stats[1])}\n"

        embed.add_field(name=title, value=leaderboard, inline=False)

        user_score = (
            database.zscore(database_key, str(ctx.author.id))
            if database_key is not None
            else data.get(str(ctx.author.id))
        )

        if user_score is not None:
            if database_key is not None:
                placement = int(database.zrevrank(database_key, str(ctx.author.id))) + 1
                distance = int(
                    database.zrevrange(
                        database_key, placement - 2, placement - 2, True
                    )[0][1]
                ) - int(user_score)
            else:
                placement = int(data.rank(ascending=False)[str(ctx.author.id)])
                distance = int(data.iloc[placement - 2] - user_score)

            if placement == 1:
                embed.add_field(
                    name="You:",
                    value=f"You are #{placement} on the leaderboard.\nYou are in first place.",
                    inline=False,
                )
            elif distance == 0:
                embed.add_field(
                    name="You:",
                    value=f"You are #{placement} on the leaderboard.\nYou are tied with #{placement-1}",
                    inline=False,
                )
            else:
                embed.add_field(
                    name="You:",
                    value=f"You are #{placement} on the leaderboard.\nYou are {distance} away from #{placement-1}",
                    inline=False,
                )
        else:
            embed.add_field(name="You:", value="You haven't answered any correctly.")

        await ctx.send(embed=embed)
Exemple #19
0
def bird_setup(ctx, bird: str):
    """Sets up a new bird for incorrect tracking.

    `ctx` - Discord context object or user id\n
    `bird` - bird to setup
    """
    if isinstance(ctx, (str, int)):
        user_id = ctx
        guild = None
    else:
        user_id = ctx.author.id
        guild = ctx.guild

    logger.info("checking bird data")
    if database.zscore("incorrect:global", string.capwords(bird)) is not None:
        logger.info("bird global ok")
    else:
        database.zadd("incorrect:global", {string.capwords(bird): 0})
        logger.info("bird global added")

    if database.zscore(f"incorrect.user:{user_id}", string.capwords(bird)) is not None:
        logger.info("bird user ok")
    else:
        database.zadd(f"incorrect.user:{user_id}", {string.capwords(bird): 0})
        logger.info("bird user added")

    date = str(datetime.datetime.now(datetime.timezone.utc).date())
    if database.zscore(f"daily.incorrect:{date}", string.capwords(bird)) is not None:
        logger.info("bird daily ok")
    else:
        database.zadd(f"daily.incorrect:{date}", {string.capwords(bird): 0})
        logger.info("bird daily added")

    if database.zscore("frequency.bird:global", string.capwords(bird)) is not None:
        logger.info("bird freq global ok")
    else:
        database.zadd("frequency.bird:global", {string.capwords(bird): 0})
        logger.info("bird freq global added")

    if guild is not None:
        logger.info("no dm")
        if (
            database.zscore(f"incorrect.server:{ctx.guild.id}", string.capwords(bird))
            is not None
        ):
            logger.info("bird server ok")
        else:
            database.zadd(
                f"incorrect.server:{ctx.guild.id}", {string.capwords(bird): 0}
            )
            logger.info("bird server added")
    else:
        logger.info("dm context")

    if database.exists(f"session.data:{user_id}"):
        logger.info("session in session")
        if (
            database.zscore(f"session.incorrect:{user_id}", string.capwords(bird))
            is not None
        ):
            logger.info("bird session ok")
        else:
            database.zadd(f"session.incorrect:{user_id}", {string.capwords(bird): 0})
            logger.info("bird session added")
    else:
        logger.info("no session")