def can_user_manage_organisation(organisation_id: int, user_id: int): """ Check that the user is an admin for the org or a global admin""" if UserService.is_user_an_admin(user_id): return True else: return OrganisationService.is_user_an_org_manager( organisation_id, user_id)
def is_user_action_permitted_on_project(authenticated_user_id: int, project_id: int) -> bool: """ Is user action permitted on project""" project = Project.get(project_id) author_id = project.author_id allowed_roles = [TeamRoles.PROJECT_MANAGER.value] is_admin = UserService.is_user_an_admin(authenticated_user_id) is_author = UserService.is_user_the_project_author( authenticated_user_id, author_id) is_org_manager = False if hasattr(project, "organisation_id") and project.organisation_id: org_id = project.organisation_id org = OrganisationService.get_organisation_by_id_as_dto( org_id, authenticated_user_id) if org.is_manager: is_org_manager = True is_manager_team = None if hasattr(project, "project_teams") and project.project_teams: teams_dto = TeamService.get_project_teams_as_dto(project_id) if teams_dto.teams: teams_allowed = [ team_dto for team_dto in teams_dto.teams if team_dto.role in allowed_roles ] user_membership = [ team_dto.team_id for team_dto in teams_allowed if TeamService.is_user_member_of_team( team_dto.team_id, authenticated_user_id) ] if user_membership: is_manager_team = True return is_admin or is_author or is_org_manager or is_manager_team
def get_team_as_dto(team_id: int, user_id: int) -> TeamDTO: team = TeamService.get_team_by_id(team_id) if team is None: raise NotFound() team_dto = TeamDetailsDTO() team_dto.team_id = team.id team_dto.name = team.name team_dto.invite_only = team.invite_only team_dto.visibility = TeamVisibility(team.visibility).name team_dto.description = team.description team_dto.logo = team.organisation.logo team_dto.organisation = team.organisation.name team_dto.organisation_id = team.organisation.id if user_id != 0: if UserService.is_user_an_admin(user_id): team_dto.is_general_admin = True if OrganisationService.is_user_an_org_manager( team.organisation.id, user_id): team_dto.is_org_admin = True else: team_dto.is_general_admin = False team_dto.is_org_admin = False team_members = TeamService._get_team_members(team_id) for member in team_members: user = UserService.get_user_by_id(member.user_id) member_dto = TeamMembersDTO() member_dto.username = user.username member_dto.pictureUrl = user.picture_url member_dto.function = TeamMemberFunctions(member.function).name member_dto.picture_url = user.picture_url member_dto.active = member.active team_dto.members.append(member_dto) team_projects = TeamService.get_projects_by_team_id(team.id) for team_project in team_projects: project_team_dto = TeamProjectDTO() project_team_dto.project_name = team_project.name project_team_dto.project_id = team_project.project_id project_team_dto.role = TeamRoles(team_project.role).name team_dto.team_projects.append(project_team_dto) org_projects = OrganisationService.get_projects_by_organisation_id( team.organisation.id) for org_project in org_projects: org_project_dto = OrganisationProjectsDTO() org_project_dto.project_id = org_project.id org_project_dto.project_name = org_project.name team_dto.organisation_projects.append(org_project_dto) return team_dto
def user_is_manager(team_id: int, user_id: int): if UserService.is_user_an_admin(user_id): return True managers = TeamService._get_team_managers(team_id) for member in managers: if member.user_id == user_id: return True return False
def create_draft_project(draft_project_dto: DraftProjectDTO) -> int: """ Validates and then persists draft projects in the DB :param draft_project_dto: Draft Project DTO with data from API :raises InvalidGeoJson :returns ID of new draft project """ user_id = draft_project_dto.user_id is_admin = UserService.is_user_an_admin(user_id) user_orgs = OrganisationService.get_organisations_managed_by_user_as_dto( user_id) is_org_manager = len(user_orgs.organisations) > 0 # First things first, we need to validate that the author_id is a PM. issue #1715 if not (is_admin or is_org_manager): user = UserService.get_user_by_id(user_id) raise (ProjectAdminServiceError( f"User {user.username} is not permitted to create project")) # If we're cloning we'll copy all the project details from the clone, otherwise create brand new project if draft_project_dto.cloneFromProjectId: draft_project = Project.clone(draft_project_dto.cloneFromProjectId, user_id) else: draft_project = Project() org = OrganisationService.get_organisation_by_id( draft_project_dto.organisation) if org is None: raise NotFound("Organisation does not exist") draft_project_dto.organisation = org draft_project.create_draft_project(draft_project_dto) draft_project.set_project_aoi(draft_project_dto) # if arbitrary_tasks requested, create tasks from aoi otherwise use tasks in DTO if draft_project_dto.has_arbitrary_tasks: tasks = GridService.tasks_from_aoi_features( draft_project_dto.area_of_interest) draft_project.task_creation_mode = TaskCreationMode.ARBITRARY.value else: tasks = draft_project_dto.tasks ProjectAdminService._attach_tasks_to_project(draft_project, tasks) if draft_project_dto.cloneFromProjectId: draft_project.save() # Update the clone else: draft_project.create() # Create the new project draft_project.set_default_changeset_comment() draft_project.set_country_info() return draft_project.id
def _user_can_validate_task(user_id: int, mapped_by: int) -> bool: """ check whether a user is able to validate a task. Users cannot validate their own tasks unless they are a PM (admin counts as project manager too) :param user_id: id of user attempting to validate :param mapped_by: id of user who mapped the task :return: Boolean """ is_admin = UserService.is_user_an_admin(user_id) if is_admin: return True else: mapped_by_me = mapped_by == user_id if not mapped_by_me: return True return False
def delete_project(project_id: int, authenticated_user_id: int): """ Deletes project if it has no completed tasks """ project = ProjectAdminService._get_project_by_id(project_id) is_admin = UserService.is_user_an_admin(authenticated_user_id) user_orgs = OrganisationService.get_organisations_managed_by_user_as_dto( authenticated_user_id) is_org_manager = len(user_orgs.organisations) > 0 if is_admin or is_org_manager: if project.can_be_deleted(): project.delete() else: raise ProjectAdminServiceError( "Project has mapped tasks, cannot be deleted") else: raise ProjectAdminServiceError( "User does not have permissions to delete project")
def is_user_team_manager(team_id: int, user_id: int): # Admin manages all teams if UserService.is_user_an_admin(user_id): return True managers = TeamService._get_team_managers(team_id) for member in managers: if member.user_id == user_id: return True # Org admin manages teams attached to their org user_managed_orgs = [ org.id for org in OrganisationService.get_organisations(user_id) ] if Team.get(team_id).organisation_id in user_managed_orgs: return True return False
def get_team_as_dto(team_id: int, user_id: int, abbreviated: bool) -> TeamDetailsDTO: team = TeamService.get_team_by_id(team_id) if team is None: raise NotFound() team_dto = TeamDetailsDTO() team_dto.team_id = team.id team_dto.name = team.name team_dto.invite_only = team.invite_only team_dto.visibility = TeamVisibility(team.visibility).name team_dto.description = team.description team_dto.logo = team.organisation.logo team_dto.organisation = team.organisation.name team_dto.organisation_id = team.organisation.id team_dto.organisation_slug = team.organisation.slug if user_id != 0: if UserService.is_user_an_admin(user_id): team_dto.is_general_admin = True if OrganisationService.is_user_an_org_manager( team.organisation.id, user_id): team_dto.is_org_admin = True else: team_dto.is_general_admin = False team_dto.is_org_admin = False if abbreviated: return team_dto team_dto.members = [ team.as_dto_team_member(member) for member in team.members ] team_projects = TeamService.get_projects_by_team_id(team.id) team_dto.team_projects = [ team.as_dto_team_project(project) for project in team_projects ] return team_dto
def is_user_action_permitted_on_project(authenticated_user_id: int, project_id: int) -> bool: """ Is user action permitted on project""" project = Project.get(project_id) author_id = project.author_id allowed_roles = [TeamRoles.PROJECT_MANAGER.value] is_admin = UserService.is_user_an_admin(authenticated_user_id) is_author = UserService.is_user_the_project_author( authenticated_user_id, author_id) is_org_manager = False is_manager_team = False if not (is_admin or is_author): if hasattr(project, "organisation_id") and project.organisation_id: org_id = project.organisation_id is_org_manager = OrganisationService.is_user_an_org_manager( org_id, authenticated_user_id) if not is_org_manager: is_manager_team = TeamService.check_team_membership( project_id, allowed_roles, authenticated_user_id) return is_admin or is_author or is_org_manager or is_manager_team
def get_all_teams( user_id: int = None, team_name_filter: str = None, team_role_filter: str = None, member_filter: int = None, member_request_filter: int = None, manager_filter: int = None, organisation_filter: int = None, omit_members: bool = False, ) -> TeamsListDTO: query = db.session.query(Team) orgs_query = None is_admin = UserService.is_user_an_admin(user_id) if organisation_filter: orgs_query = query.filter( Team.organisation_id == organisation_filter) if manager_filter and not (manager_filter == user_id and is_admin): manager_teams = query.filter( TeamMembers.user_id == manager_filter, TeamMembers.active == True, # noqa TeamMembers.function == TeamMemberFunctions.MANAGER.value, Team.id == TeamMembers.team_id, ) manager_orgs_teams = query.filter( Team.organisation_id.in_([ org.id for org in OrganisationService.get_organisations( manager_filter) ])) query = manager_teams.union(manager_orgs_teams) if team_name_filter: query = query.filter(Team.name.ilike("%" + team_name_filter + "%"), ) if team_role_filter: try: role = TeamRoles[team_role_filter.upper()].value project_teams = (db.session.query(ProjectTeams).filter( ProjectTeams.role == role).subquery()) query = query.join(project_teams) except KeyError: pass if member_filter: team_member = (db.session.query(TeamMembers).filter( TeamMembers.user_id == member_filter, TeamMembers.active.is_(True)).subquery()) query = query.join(team_member) if member_request_filter: team_member = (db.session.query(TeamMembers).filter( TeamMembers.user_id == member_request_filter, TeamMembers.active.is_(False), ).subquery()) query = query.join(team_member) if orgs_query: query = query.union(orgs_query) teams_list_dto = TeamsListDTO() for team in query.all(): team_dto = TeamDTO() team_dto.team_id = team.id team_dto.name = team.name team_dto.invite_only = team.invite_only team_dto.visibility = TeamVisibility(team.visibility).name team_dto.description = team.description team_dto.logo = team.organisation.logo team_dto.organisation = team.organisation.name team_dto.organisation_id = team.organisation.id team_dto.members = [] is_team_member = TeamService.is_user_an_active_team_member( team.id, user_id) # Skip if members are not included if not omit_members: team_members = team.members team_dto.members = [ team.as_dto_team_member(member) for member in team_members ] if team_dto.visibility == "PRIVATE" and not is_admin: if is_team_member: teams_list_dto.teams.append(team_dto) else: teams_list_dto.teams.append(team_dto) return teams_list_dto
def post(self): """ Creates a new team --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - in: body name: body required: true description: JSON object for creating team schema: properties: name: type: string default: HOT - Mappers organisation_id: type: integer default: 1 description: type: string visibility: type: string default: PUBLIC inviteOnly: type: boolean default: false responses: 201: description: Team created successfully 400: description: Client Error - Invalid Request 401: description: Unauthorized - Invalid credentials 403: description: Unauthorized - Forbidden 500: description: Internal Server Error """ user_id = token_auth.current_user() try: team_dto = NewTeamDTO(request.get_json()) team_dto.creator = user_id team_dto.validate() except DataError as e: current_app.logger.error(f"error validating request: {str(e)}") return str(e), 400 try: organisation_id = team_dto.organisation_id is_org_manager = OrganisationService.is_user_an_org_manager( organisation_id, user_id) is_admin = UserService.is_user_an_admin(user_id) if is_admin or is_org_manager: team_id = TeamService.create_team(team_dto) return {"teamId": team_id}, 201 else: error_msg = ( "Team POST - User not permitted to create team for the Organisation" ) return {"Error": error_msg}, 403 except TeamServiceError as e: return str(e), 400 except NotFound: error_msg = "Team POST - Organisation does not exist" return {"Error": error_msg}, 400 except Exception as e: error_msg = f"Team POST - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def get(self): """ List all organisations --- tags: - organisations produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token type: string default: Token sessionTokenHere== - name: manager_user_id in: query description: Filter projects on managers with this user_id required: false type: integer responses: 200: description: Organisations found 400: description: Client Error - Invalid Request 401: description: Unauthorized - Invalid credentials 403: description: Unauthorized - Not allowed 404: description: Organisations not found 500: description: Internal Server Error """ # Restrict some of the parameters to some permissions try: manager_user_id = int(request.args.get("manager_user_id")) except Exception: manager_user_id = None if manager_user_id is not None: try: # Verify login verify_token( request.environ.get("HTTP_AUTHORIZATION").split(None, 1)[1]) # Check whether user is admin (can do any query) or user is checking for own projects if (not UserService.is_user_an_admin(tm.authenticated_user_id) and tm.authenticated_user_id != manager_user_id): raise ValueError except Exception: return {"Error": "Unauthorized - Not allowed"}, 403 # Obtain organisations try: results_dto = OrganisationService.get_organisations_as_dto( manager_user_id, tm.authenticated_user_id) return results_dto.to_primitive(), 200 except NotFound: return {"Error": "No projects found"}, 404 except Exception as e: error_msg = f"Organisations GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def get_all_teams( user_id: int = None, team_name_filter: str = None, team_role_filter: str = None, member_filter: int = None, member_request_filter: int = None, manager_filter: int = None, organisation_filter: int = None, ) -> TeamsListDTO: query = db.session.query(Team).outerjoin(TeamMembers).outerjoin( ProjectTeams) orgs_query = None is_admin = UserService.is_user_an_admin(user_id) if organisation_filter: orgs_query = query.filter( Team.organisation_id.in_(organisation_filter)) if manager_filter and not (manager_filter == user_id and is_admin): query = query.filter( TeamMembers.user_id == manager_filter, TeamMembers.active == True, # noqa TeamMembers.function == TeamMemberFunctions.MANAGER.value, ) if team_name_filter: query = query.filter(Team.name.contains(team_name_filter)) if team_role_filter: try: role = TeamRoles[team_role_filter.upper()].value query = query.filter(ProjectTeams.role == role) except KeyError: pass if member_filter: query = query.filter( TeamMembers.user_id == member_filter, TeamMembers.active == True # noqa ) if member_request_filter: query = query.filter( TeamMembers.user_id == member_request_filter, TeamMembers.active == False, # noqa ) if orgs_query: query = query.union(orgs_query) teams_list_dto = TeamsListDTO() for team in query.all(): team_dto = TeamDTO() team_dto.team_id = team.id team_dto.name = team.name team_dto.invite_only = team.invite_only team_dto.visibility = TeamVisibility(team.visibility).name team_dto.description = team.description team_dto.logo = team.organisation.logo team_dto.organisation = team.organisation.name team_dto.organisation_id = team.organisation.id team_dto.members = [] team_members = TeamService._get_team_members(team.id) is_team_manager = False is_team_member = False for member in team_members: user = UserService.get_user_by_id(member.user_id) member_dto = TeamMembersDTO() member_dto.username = user.username member_dto.function = TeamMemberFunctions(member.function).name if member.user_id == user_id: is_team_member = True if member_dto.function == "MANAGER": is_team_manager = True member_dto.picture_url = user.picture_url member_dto.active = member.active team_dto.members.append(member_dto) if team_dto.visibility == "PRIVATE" and not is_admin: if is_team_manager or is_team_member: teams_list_dto.teams.append(team_dto) else: teams_list_dto.teams.append(team_dto) return teams_list_dto
def get_organisations_managed_by_user(user_id: int): """ Get all organisations a user manages """ if UserService.is_user_an_admin(user_id): return Organisation.get_all_organisations() return Organisation.get_organisations_managed_by_user(user_id)
def post_message( chat_dto: ChatMessageDTO, project_id: int, authenticated_user_id: int ) -> ProjectChatDTO: """ Save message to DB and return latest chat""" current_app.logger.debug("Posting Chat Message") if UserService.is_user_blocked(authenticated_user_id): return ValueError("User is on read only mode") project = ProjectService.get_project_by_id(project_id) if project.private: author_id = project.author_id allowed_roles = [ TeamRoles.PROJECT_MANAGER.value, TeamRoles.VALIDATOR.value, TeamRoles.MAPPER.value, ] is_admin = UserService.is_user_an_admin(authenticated_user_id) is_author = UserService.is_user_the_project_author( authenticated_user_id, author_id ) is_org_manager = False if hasattr(project, "organisation_id") and project.organisation_id: org_id = project.organisation_id org = OrganisationService.get_organisation_by_id_as_dto( org_id, authenticated_user_id ) if org.is_manager: is_org_manager = True is_team_member = None if hasattr(project, "project_teams") and project.project_teams: teams_dto = TeamService.get_project_teams_as_dto(project_id) if teams_dto.teams: teams_allowed = [ team_dto for team_dto in teams_dto.teams if team_dto.role in allowed_roles ] user_membership = [ team_dto.team_id for team_dto in teams_allowed if TeamService.is_user_member_of_team( team_dto.team_id, authenticated_user_id ) ] if user_membership: is_team_member = True for user in project.allowed_users: if user.id == authenticated_user_id: is_allowed_user = True break if ( is_admin or is_author or is_org_manager or is_team_member or is_allowed_user ): chat_message = ProjectChat.create_from_dto(chat_dto) MessageService.send_message_after_chat( chat_dto.user_id, chat_message.message, chat_dto.project_id ) db.session.commit() # Ensure we return latest messages after post return ProjectChat.get_messages(chat_dto.project_id, 1) else: raise ValueError("User not permitted to post Comment") else: chat_message = ProjectChat.create_from_dto(chat_dto) MessageService.send_message_after_chat( chat_dto.user_id, chat_message.message, chat_dto.project_id ) db.session.commit() # Ensure we return latest messages after post return ProjectChat.get_messages(chat_dto.project_id, 1)
def get(self): """ List all organisations --- tags: - organisations produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token type: string default: Token sessionTokenHere== - name: manager_user_id in: query description: Filter projects on managers with this user_id required: false type: integer - in: query name: omitManagerList type: boolean description: Set it to true if you don't want the managers list on the response. default: False responses: 200: description: Organisations found 400: description: Client Error - Invalid Request 401: description: Unauthorized - Invalid credentials 403: description: Unauthorized - Not allowed 404: description: Organisations not found 500: description: Internal Server Error """ # Restrict some of the parameters to some permissions authenticated_user_id = token_auth.current_user() try: manager_user_id = int(request.args.get("manager_user_id")) except Exception: manager_user_id = None if manager_user_id is not None: try: # Check whether user is admin (can do any query) or user is checking for own projects if (not UserService.is_user_an_admin(authenticated_user_id) and authenticated_user_id != manager_user_id): raise ValueError except Exception: return {"Error": "Unauthorized - Not allowed"}, 403 # Validate abbreviated. omit_managers = strtobool(request.args.get("omitManagerList", "false")) # Obtain organisations try: results_dto = OrganisationService.get_organisations_as_dto( manager_user_id, authenticated_user_id, omit_managers) return results_dto.to_primitive(), 200 except NotFound: return {"Error": "No projects found"}, 404 except Exception as e: error_msg = f"Organisations GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500