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")
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")
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")
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!"
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")
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
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
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})
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))
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")
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)
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("-", " ")))
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)
def increment_bird_frequency(ctx, bird): bird_setup(ctx, bird) database.zincrby("frequency.bird:global", 1, string.capwords(bird))
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