Ejemplo n.º 1
0
def score_increment(ctx, amount: int):
    """Increments the score of a user by `amount`.

    `ctx` - Discord context object\n
    `amount` (int) - amount to increment by, usually 1
    """
    if isinstance(ctx, (str, int)):
        user_id = str(ctx)
        guild = None
        channel_id = ""
    else:
        user_id = str(ctx.author.id)
        guild = ctx.guild
        channel_id = str(ctx.channel.id)

    logger.info(f"incrementing score by {amount}")
    date = str(datetime.datetime.now(datetime.timezone.utc).date())
    database.zincrby("score:global", amount, channel_id)
    database.zincrby("users:global", amount, user_id)
    database.zincrby(f"daily.score:{date}", amount, user_id)
    if guild is not None:
        logger.info("no dm")
        database.zincrby(f"users.server:{ctx.guild.id}", amount, user_id)
        if database.exists(f"race.data:{ctx.channel.id}"):
            logger.info("race in session")
            database.zincrby(f"race.scores:{ctx.channel.id}", amount, user_id)
    else:
        logger.info("dm context")
Ejemplo n.º 2
0
async def update_web_user(request: Request, user_data: dict):
    logger.info("updating user data")
    session_id = get_session_id(request)
    user_id = str(user_data["id"])
    database.hset(f"web.session:{session_id}", "user_id", user_id)
    database.expire(f"web.session:{session_id}", DATABASE_SESSION_USER_EXPIRE)
    database.hset(
        f"web.user:{user_id}",
        mapping={
            "avatar_hash": str(user_data["avatar"]),
            "avatar_url": f"https://cdn.discordapp.com/avatars/{user_id}/{user_data['avatar']}.png",
            "username": str(user_data["username"]),
            "discriminator": str(user_data["discriminator"]),
        },
    )
    await user_setup(user_id)
    tempScore = int(database.hget(f"web.session:{session_id}", "tempScore"))
    if tempScore not in (0, -1):
        score_increment(user_id, tempScore)
        database.zincrby(
            f"daily.webscore:{str(datetime.datetime.now(datetime.timezone.utc).date())}",
            1,
            user_id,
        )
        database.hset(f"web.session:{session_id}", "tempScore", -1)
    logger.info("updated user data")
Ejemplo n.º 3
0
def incorrect_increment(ctx, bird: str, amount: int):
    """Increments the value of an incorrect bird by `amount`.

    `ctx` - Discord context object or user id\n
    `bird` - bird that was incorrect\n
    `amount` (int) - amount to increment by, usually 1
    """
    if isinstance(ctx, (str, int)):
        user_id = ctx
        guild = None
    else:
        user_id = ctx.author.id
        guild = ctx.guild

    logger.info(f"incrementing incorrect {bird} by {amount}")
    date = str(datetime.datetime.now(datetime.timezone.utc).date())
    database.zincrby("incorrect:global", amount, string.capwords(str(bird)))
    database.zincrby(f"incorrect.user:{user_id}", amount, string.capwords(str(bird)))
    database.zincrby(f"daily.incorrect:{date}", amount, string.capwords(str(bird)))
    if guild is not None:
        logger.info("no dm")
        database.zincrby(
            f"incorrect.server:{ctx.guild.id}", amount, string.capwords(str(bird))
        )
    else:
        logger.info("dm context")
    if database.exists(f"session.data:{user_id}"):
        logger.info("session in session")
        database.zincrby(
            f"session.incorrect:{user_id}", amount, string.capwords(str(bird))
        )
    else:
        logger.info("no session")
Ejemplo n.º 4
0
    def test_with_score(self):
        self.setup(guild=True)
        database.zincrby("score:global", 20, str(self.ctx.channel.id))

        coroutine = self.cog.score.callback(self.cog, self.ctx)  # pylint: disable=no-member
        assert asyncio.run(coroutine) is None
        assert self.ctx.messages[
            2].content == "Wow, looks like a total of `20` birds have been answered correctly in this **channel**!\nGood job everyone!"
Ejemplo n.º 5
0
def update_web_user(user_data):
    logger.info("updating user data")
    session_id = get_session_id()
    user_id = str(user_data["id"])
    database.hset(f"web.session:{session_id}", "user_id", user_id)
    database.expire(f"web.session:{session_id}", DATABASE_SESSION_EXPIRE)
    database.hset(
        f"web.user:{user_id}",
        mapping={
            "avatar_hash": str(user_data["avatar"]),
            "avatar_url":
            f"https://cdn.discordapp.com/avatars/{user_id}/{user_data['avatar']}.png",
            "username": str(user_data["username"]),
            "discriminator": str(user_data["discriminator"]),
        },
    )
    asyncio.run(user_setup(user_id))
    tempScore = int(database.hget(f"web.session:{session_id}", "tempScore"))
    if tempScore not in (0, -1):
        database.zincrby("users:global", tempScore, int(user_id))
        database.hset(f"web.session:{session_id}", "tempScore", -1)
    logger.info("updated user data")
Ejemplo n.º 6
0
async def get_files(sciBird: str,
                    media_type: str,
                    filters: Filter,
                    retries: int = 0):
    """Returns a list of image/song filenames.

    This function also does cache management,
    looking for files in the cache for media and
    downloading images to the cache if not found.

    `sciBird` (str) - scientific name of bird\n
    `media_type` (str) - type of media (images/songs)\n
    `filters` (bot.filters Filter)\n
    """
    logger.info(f"get_files retries: {retries}")
    directory = f"bot_files/cache/{media_type}/{sciBird}{filters.to_int()}/"
    # track counts for more accurate eviction
    database.zincrby("frequency.media:global", 1,
                     f"{media_type}/{sciBird}{filters.to_int()}")
    try:
        logger.info("trying")
        files_dir = os.listdir(directory)
        logger.info(directory)
        if not files_dir:
            raise GenericError("No Files", code=100)
        return [f"{directory}{path}" for path in files_dir]
    except (FileNotFoundError, GenericError):
        logger.info("fetching files")
        # if not found, fetch images
        logger.info("scibird: " + str(sciBird))
        filenames = await download_media(sciBird, media_type, filters,
                                         directory)
        if not filenames:
            if retries < 3:
                retries += 1
                return await get_files(sciBird, media_type, filters, retries)
            logger.info("More than 3 retries")

        return filenames
Ejemplo n.º 7
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
Ejemplo n.º 8
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})
Ejemplo n.º 9
0
def score_increment(ctx, amount: int):
    """Increments the score of a user by `amount`.

    `ctx` - Discord context object\n
    `amount` (int) - amount to increment by, usually 1
    """
    logger.info(f"incrementing score by {amount}")
    database.zincrby("score:global", amount, str(ctx.channel.id))
    database.zincrby("users:global", amount, str(ctx.author.id))
    if ctx.guild is not None:
        logger.info("no dm")
        database.zincrby(f"users.server:{ctx.guild.id}", amount,
                         str(ctx.author.id))
    else:
        logger.info("dm context")
    if database.exists(f"race.data:{ctx.channel.id}"):
        logger.info("race in session")
        database.zincrby(f"race.scores:{ctx.channel.id}", amount,
                         str(ctx.author.id))
Ejemplo n.º 10
0
def incorrect_increment(ctx, bird: str, amount: int):
    """Increments the value of an incorrect bird by `amount`.

    `ctx` - Discord context object\n
    `bird` - bird that was incorrect\n
    `amount` (int) - amount to increment by, usually 1
    """
    logger.info(f"incrementing incorrect {bird} by {amount}")
    database.zincrby("incorrect:global", amount, string.capwords(str(bird)))
    database.zincrby(f"incorrect.user:{ctx.author.id}", amount,
                     string.capwords(str(bird)))
    if ctx.guild is not None:
        logger.info("no dm")
        database.zincrby(f"incorrect.server:{ctx.guild.id}", amount,
                         string.capwords(str(bird)))
    else:
        logger.info("dm context")
    if database.exists(f"session.data:{ctx.author.id}"):
        logger.info("session in session")
        database.zincrby(f"session.incorrect:{ctx.author.id}", amount,
                         string.capwords(str(bird)))
    else:
        logger.info("no session")
Ejemplo n.º 11
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)
Ejemplo n.º 12
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("-", " ")))
Ejemplo n.º 13
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)
Ejemplo n.º 14
0
 def increment_bird_frequency(ctx, bird):
     bird_setup(ctx, bird)
     database.zincrby("frequency.bird:global", 1, string.capwords(bird))
Ejemplo n.º 15
0
 def log_command_frequency(ctx):
     """Logs the command used to the database."""
     logger.info("global check: logging command frequency")
     database.zincrby("frequency.command:global", 1, str(ctx.command))
     return True