Source code for inatcog.projects

"""Module to handle projects."""
from typing import Union

from pyinaturalist.models import Project


[docs]class UserProject(Project): """A collection project for observations by specific users. This class handles projects that include observations by members, with membership being managed either solely by the user, soley by the admins, or a combination of both: 1. Open membership, users join on the web: - members_only: True - do not set any "observed_by_user?" rules 2. Closed membership, admins edit the project to join users: - members_only: False - set at least one "observed_by_user?" rule 3. Closed membership, users join on web and admins edit project to "approve" join: - members_only: True - set at least one "observed_by_user?" rule - a user's observations are included when both the user joins *and* the admin "approves" the join by adding a rule for them """
[docs] def members_only(self): return next( iter( [ param.get("value") for param in self.search_parameters if param.get("field") == "members_only" ] ), False, )
[docs] def observed_by_ids(self): """Valid observer user ids for the project. TODO: clarify what the iNat code actually does for these cases and fix as needed. we implement, based on some reasonable assumptions: - for closed membership projects, exclude any user that has both an included rule (observed_by_user?) and an excluded rule (not_observed_by_user?) """ exclude_user_ids = [ rule.get("operand_id") for rule in self.project_observation_rules if rule.get("operator") == "not_observed_by_user?" ] include_user_rules = [ rule for rule in self.project_observation_rules if rule.get("operator") == "observed_by_user?" and rule.get("operand_id") not in exclude_user_ids ] if self.members_only(): if include_user_rules: # i.e. case 3, Closed (user joins & admin approves the join) include_user_ids = [ rule.get("operand_id") for rule in include_user_rules if rule.get("operand_id") in self.user_ids ] else: # i.e. case 1, Open (user joins) include_user_ids = [ user_id for user_id in self.user_ids if user_id not in exclude_user_ids ] else: if include_user_rules: # i.e. case 2, Closed (admin joins the user) include_user_ids = [ rule.get("operand_id") for rule in include_user_rules ] else: # i.e. fallback - project membership is undefined, so is empty # - as in case 2 but admins haven't joined anyone yet # - note: exclusions are irrelevant; an empty membership minus # some specific users is still "empty" include_user_ids = [] return include_user_ids
[docs]class INatProjectTable: """Lookup helper for projects.""" def __init__(self, cog): self.cog = cog
[docs] async def get_project(self, guild, query: Union[int, str]): """Get project by guild abbr or via id#/keyword lookup in API.""" project = None response = None abbrev = None if isinstance(query, str): abbrev = query.lower() if isinstance(query, int) or query.isnumeric(): project_id = query response = await self.cog.api.get_projects(int(project_id)) if guild and abbrev: guild_config = self.cog.config.guild(guild) projects = await guild_config.projects() if abbrev in projects: response = await self.cog.api.get_projects(projects[abbrev]) if not response: response = await self.cog.api.get_projects("autocomplete", q=query) if response: results = response.get("results") if results: project = results[0] if project: return Project.from_json(project) raise LookupError("iNat project not known.")