From 5ce9d596d91817b73f6160e3dbf8fcefff67dc92 Mon Sep 17 00:00:00 2001 From: Ben Armstrong Date: Sun, 10 May 2020 13:16:04 -0300 Subject: [PATCH] Refactor to support unified project stats support. --- inatcog/inat_embeds.py | 66 ++++++++++++++++++++++++++++++++++++++++++ inatcog/inatcog.py | 65 ++--------------------------------------- 2 files changed, 69 insertions(+), 62 deletions(-) diff --git a/inatcog/inat_embeds.py b/inatcog/inat_embeds.py index c4b192a0..45c3d209 100644 --- a/inatcog/inat_embeds.py +++ b/inatcog/inat_embeds.py @@ -11,6 +11,7 @@ from .interfaces import MixinMeta from .maps import INatMapURL from .obs import PAT_OBS_LINK +from .projects import UserProject, ObserverStats from .taxa import ( format_taxon_name, format_taxon_names, @@ -391,6 +392,71 @@ async def format_ancestors(description, rec): return embed + async def get_user_project_stats(self, project_id, user, species=False): + """Get user's ranked obs & spp stats for a project.""" + kwargs = {} + if species: + kwargs["order_by"] = "species_count" + # FIXME: cache for a short while so users can compare stats but not + # have to worry about stale data. + response = await self.api.get_project_observers_stats( + project_id=project_id, **kwargs + ) + stats = [ObserverStats.from_dict(observer) for observer in response["results"]] + if stats: + rank = next( + ( + index + 1 + for (index, d) in enumerate(stats) + if d.user_id == user.user_id + ), + None, + ) + if rank: + ranked = stats[rank - 1] + count = ranked.species_count if species else ranked.observation_count + else: + rank = "unranked" + count = "unknown" + return (count, rank) + + async def get_user_server_projects_stats(self, ctx, user): + """Get a user's stats for the server's user projects.""" + user_projects = await self.config.guild(ctx.guild).user_projects() or {} + project_ids = list(map(int, user_projects)) + projects = await self.api.get_projects(project_ids, refresh_cache=True) + stats = [] + for project_id in project_ids: + if project_id not in projects: + continue + user_project = UserProject.from_dict(projects[project_id]["results"][0]) + if user.user_id in user_project.observed_by_ids(): + abbrev = user_projects[str(project_id)] + obs_stats = await self.get_user_project_stats(project_id, user) + spp_stats = await self.get_user_project_stats( + project_id, user, species=True + ) + stats.append((project_id, abbrev, obs_stats, spp_stats)) + return stats + + async def make_user_embed(self, ctx, member, user): + """Make an embed for user including user stats.""" + embed = make_embed(description=f"{member.mention} is {user.profile_link()}") + project_stats = await self.get_user_server_projects_stats(ctx, user) + for project_id, abbrev, obs_stats, spp_stats in project_stats: + obs_count, _obs_rank = obs_stats + spp_count, _spp_rank = spp_stats + url = ( + f"{WWW_BASE_URL}/observations?project_id={project_id}" + f"&user_id={user.user_id}" + ) + fmt = f"[{obs_count}]({url}&view=observations) / [{spp_count}]({url}&view=species)" + embed.add_field(name=f"Obs / Spp {abbrev}", value=fmt, inline=True) + ids = user.identifications_count + url = f"[{ids}]({WWW_BASE_URL}/identifications?user_id={user.user_id})" + embed.add_field(name="Ids", value=url, inline=True) + return embed + async def send_embed_for_taxon_image(self, ctx, taxon): """Make embed for taxon image & send.""" msg = await ctx.send(embed=await self.make_image_embed(taxon)) diff --git a/inatcog/inatcog.py b/inatcog/inatcog.py index 8b1969c4..d15c7030 100644 --- a/inatcog/inatcog.py +++ b/inatcog/inatcog.py @@ -1071,74 +1071,15 @@ async def user(self, ctx, *, who: QuotedContextMemberConverter): if not ctx.guild: return + member = who.member try: - user = await self.user_table.get_user(who.member, refresh_cache=True) + user = await self.user_table.get_user(member, refresh_cache=True) except LookupError as err: reason = err.args[0] await ctx.send(embed=sorry(apology=reason)) return - embed = make_embed(description=f"{who.member.mention} is {user.profile_link()}") - user_projects = await self.config.guild(ctx.guild).user_projects() or {} - project_ids = list(map(int, user_projects)) - projects = await self.api.get_projects(project_ids, refresh_cache=True) - for project_id in project_ids: - if project_id not in projects: - continue - user_project = UserProject.from_dict(projects[project_id]["results"][0]) - if user.user_id in user_project.observed_by_ids(): - response = await self.api.get_project_observers_stats( - project_id=project_id - ) - stats = [ - ObserverStats.from_dict(observer) - for observer in response["results"] - ] - if stats: - emoji = user_projects[str(project_id)] - # FIXME: DRY! - obs_rank = next( - ( - index + 1 - for (index, d) in enumerate(stats) - if d.user_id == user.user_id - ), - None, - ) - if obs_rank: - obs_cnt = stats[obs_rank - 1].observation_count - else: - obs_rank = "unranked" - obs_cnt = "unknown" - response = await self.api.get_project_observers_stats( - project_id=project_id, order_by="species_count" - ) - stats = [ - ObserverStats.from_dict(observer) - for observer in response["results"] - ] - spp_rank = next( - ( - index + 1 - for (index, d) in enumerate(stats) - if d.user_id == user.user_id - ), - None, - ) - if spp_rank: - spp_cnt = stats[spp_rank - 1].species_count - else: - spp_cnt = "unknown" - url = ( - f"{WWW_BASE_URL}/observations?project_id={project_id}" - f"&user_id={user.user_id}" - ) - fmt = f"[{obs_cnt}]({url}&view=observations) / [{spp_cnt}]({url}&view=species)" - embed.add_field(name=f"Obs / Spp {emoji}", value=fmt, inline=True) - ids = user.identifications_count - url = f"[{ids}]({WWW_BASE_URL}/identifications?user_id={user.user_id})" - embed.add_field(name="Ids", value=url, inline=True) - + embed = await self.make_user_embed(ctx, member, user) await ctx.send(embed=embed) @commands.command()