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 test_add_team_project(self): team_id = 1 user_id = 123 function = 1 active = True with self.assertRaises(TeamServiceError): TeamService.add_team_member(team_id, user_id, function, active)
def test_get_team_as_dto(self): team_id = 1 user_id = 123 abbreviated = False result = TeamService.get_team_as_dto(team_id, user_id, abbreviated) self.assertEqual(result.team_id, 1)
def evaluate_mapping_permission( project_id: int, user_id: int, mapping_permission: int ): allowed_roles = [ TeamRoles.MAPPER.value, TeamRoles.VALIDATOR.value, TeamRoles.PROJECT_MANAGER.value, ] is_team_member = TeamService.check_team_membership( project_id, allowed_roles, user_id ) # mapping_permission = 1(level),2(teams),3(teamsAndLevel) if mapping_permission == MappingPermission.TEAMS.value: if not is_team_member: return False, MappingNotAllowed.USER_NOT_TEAM_MEMBER elif mapping_permission == MappingPermission.LEVEL.value: if not ProjectService._is_user_intermediate_or_advanced(user_id): return False, MappingNotAllowed.USER_NOT_CORRECT_MAPPING_LEVEL elif mapping_permission == MappingPermission.TEAMS_LEVEL.value: if not ProjectService._is_user_intermediate_or_advanced(user_id): return False, MappingNotAllowed.USER_NOT_CORRECT_MAPPING_LEVEL if not is_team_member: return False, MappingNotAllowed.USER_NOT_TEAM_MEMBER
def get_project_dto_for_mapper( project_id, current_user_id, locale="en", abbrev=False ) -> ProjectDTO: """ Get the project DTO for mappers :param project_id: ID of the Project mapper has requested :param locale: Locale the mapper has requested :raises ProjectServiceError, NotFound """ project = ProjectService.get_project_by_id(project_id) # if project is public and is not draft, we don't need to check permissions if not project.private and not project.status == ProjectStatus.DRAFT.value: return project.as_dto_for_mapping(current_user_id, locale, abbrev) is_allowed_user = True is_team_member = None is_manager_permission = False if current_user_id: is_manager_permission = ProjectAdminService.is_user_action_permitted_on_project( current_user_id, project_id ) # Draft Projects - admins, authors, org admins & team managers permitted if project.status == ProjectStatus.DRAFT.value: if not is_manager_permission: is_allowed_user = False raise ProjectServiceError("Unable to fetch project") # Private Projects - allowed_users, admins, org admins & # assigned teams (mappers, validators, project managers), authors permitted if project.private and not is_manager_permission: is_allowed_user = False if current_user_id: is_allowed_user = ( len( [ user for user in project.allowed_users if user.id == current_user_id ] ) > 0 ) if not (is_allowed_user or is_manager_permission): if current_user_id: allowed_roles = [ TeamRoles.MAPPER.value, TeamRoles.VALIDATOR.value, TeamRoles.PROJECT_MANAGER.value, ] is_team_member = TeamService.check_team_membership( project_id, allowed_roles, current_user_id ) if is_allowed_user or is_manager_permission or is_team_member: return project.as_dto_for_mapping(current_user_id, locale, abbrev) else: raise ProjectServiceError("Unable to fetch project")
def delete(self, team_id, project_id): """ Deletes the specified team project assignment --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: message_id in: path description: Unique message ID required: true type: integer default: 1 responses: 200: description: Team unassigned of the project 401: description: Forbidden, if user is not a manager of the project 403: description: Forbidden, if user is not authenticated 404: description: Not found 500: description: Internal Server Error """ if not TeamService.is_user_team_manager(team_id, token_auth.current_user()): return { "Error": "User is not an admin or a manager for the team" }, 401 try: TeamService.delete_team_project(team_id, project_id) return {"Success": True}, 200 except NotFound: return {"Error": "No team found"}, 404 except Exception as e: error_msg = f"TeamMembers DELETE - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def check_team_membership( project_id: int, allowed_roles: list, user_id: int, action: str ): teams_dto = TeamService.get_project_teams_as_dto(project_id) 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, user_id) ] if len(user_membership) == 0: if action == "MAP": return False, MappingNotAllowed.USER_NOT_TEAM_MEMBER elif action == "VALIDATE": return False, ValidatingNotAllowed.USER_NOT_TEAM_MEMBER
def delete(self, team_id): """ Deletes a Team --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: team_id in: path description: The unique team ID required: true type: integer default: 1 responses: 200: description: Team deleted 401: description: Unauthorized - Invalid credentials 403: description: Forbidden - Team has associated projects 404: description: Team not found 500: description: Internal Server Error """ if not TeamService.is_user_team_manager(team_id, token_auth.current_user()): return {"Error": "User is not a manager for the team"}, 401 try: TeamService.delete_team(team_id) return {"Success": "Team deleted"}, 200 except NotFound: return {"Error": "Team Not Found"}, 404 except Exception as e: error_msg = f"Team DELETE - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def evaluate_mapping_permission(project_id: int, user_id: int, mapping_permission: int): allowed_roles = [ TeamRoles.MAPPER.value, TeamRoles.VALIDATOR.value, TeamRoles.PROJECT_MANAGER.value, ] # mapping_permission = 1(level),2(teams),3(teamsAndLevel) if mapping_permission == MappingPermission.TEAMS.value: teams_dto = TeamService.get_project_teams_as_dto(project_id) 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, user_id) ] if len(user_membership) == 0: return False, MappingNotAllowed.USER_NOT_TEAM_MEMBER elif mapping_permission == MappingPermission.LEVEL.value: if not ProjectService._is_user_intermediate_or_advanced(user_id): return False, MappingNotAllowed.USER_NOT_CORRECT_MAPPING_LEVEL elif mapping_permission == MappingPermission.TEAMS_LEVEL.value: if not ProjectService._is_user_intermediate_or_advanced(user_id): return False, MappingNotAllowed.USER_NOT_CORRECT_MAPPING_LEVEL teams_dto = TeamService.get_project_teams_as_dto(project_id) 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, user_id) ] if len(user_membership) == 0: return False, MappingNotAllowed.USER_NOT_TEAM_MEMBER
def test_search_team(self): filters = { "user_id": 123, "team_name_filter": "TM3-validators", "team_role_filter": "MAPPER", "member_filter": 123, "member_request_filter": 123, "manager_filter": 123, "organisation_filter": 1, "omit_members": False, } result = TeamService.get_all_teams(**filters) self.assertEqual(result.to_primitive(), {"teams": []})
def get(self, team_id): """ Retrieves a Team --- tags: - teams produces: - application/json parameters: - name: team_id in: path description: Unique team ID required: true type: integer default: 1 - in: query name: omitMemberList type: boolean description: Set it to true if you don't want the members list on the response. default: False responses: 200: description: Team found 401: description: Unauthorized - Invalid credentials 404: description: Team not found 500: description: Internal Server Error """ try: authenticated_user_id = token_auth.current_user() omit_members = strtobool( request.args.get("omitMemberList", "false")) if authenticated_user_id is None: user_id = 0 else: user_id = authenticated_user_id team_dto = TeamService.get_team_as_dto(team_id, user_id, omit_members) return team_dto.to_primitive(), 200 except NotFound: return {"Error": "Team Not Found"}, 404 except Exception as e: error_msg = f"Team GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
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): raise ValueError("User is on read only mode") project = ProjectService.get_project_by_id(project_id) is_allowed_user = True is_manager_permission = ProjectAdminService.is_user_action_permitted_on_project( authenticated_user_id, project_id) is_team_member = False # Draft (public/private) accessible only for is_manager_permission if (ProjectStatus(project.status) == ProjectStatus.DRAFT and not is_manager_permission): raise ValueError("User not permitted to post Comment") if project.private: is_allowed_user = False if not is_manager_permission: allowed_roles = [ TeamRoles.PROJECT_MANAGER.value, TeamRoles.VALIDATOR.value, TeamRoles.MAPPER.value, ] is_team_member = TeamService.check_team_membership( project_id, allowed_roles, authenticated_user_id) if not is_team_member: is_allowed_user = (len([ user for user in project.allowed_users if user.id == authenticated_user_id ]) > 0) if is_manager_permission 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")
def evaluate_validation_permission( project_id: int, user_id: int, validation_permission: int ): allowed_roles = [TeamRoles.VALIDATOR.value, TeamRoles.PROJECT_MANAGER.value] is_team_member = TeamService.check_team_membership( project_id, allowed_roles, user_id ) # validation_permission = 1(level),2(teams),3(teamsAndLevel) if validation_permission == ValidationPermission.TEAMS.value: if not is_team_member: return False, ValidatingNotAllowed.USER_NOT_TEAM_MEMBER elif validation_permission == ValidationPermission.LEVEL.value: if not ProjectService._is_user_intermediate_or_advanced(user_id): return False, ValidatingNotAllowed.USER_IS_BEGINNER elif validation_permission == ValidationPermission.TEAMS_LEVEL.value: if not ProjectService._is_user_intermediate_or_advanced(user_id): return False, ValidatingNotAllowed.USER_IS_BEGINNER if not is_team_member: return False, ValidatingNotAllowed.USER_NOT_TEAM_MEMBER
def get(self, team_id): """ Retrieves a Team --- tags: - teams produces: - application/json parameters: - name: team_id in: path description: Unique team ID required: true type: integer default: 1 responses: 200: description: Team found 401: description: Unauthorized - Invalid credentials 404: description: Team not found 500: description: Internal Server Error """ try: authenticated_user_id = token_auth.current_user() if authenticated_user_id is None: user_id = 0 else: user_id = authenticated_user_id team_dto = TeamService.get_team_as_dto(team_id, user_id) return team_dto.to_primitive(), 200 except NotFound: return {"Error": "Team Not Found"}, 404 except Exception as e: error_msg = f"Team GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
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(self, project_id): """ Get teams assigned with a project --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: project_id in: path description: Unique project ID required: true type: integer default: 1 responses: 200: description: Teams listed successfully 403: description: Forbidden, if user is not authenticated 404: description: Not found 500: description: Internal Server Error """ try: teams_dto = TeamService.get_project_teams_as_dto(project_id) return teams_dto.to_primitive(), 200 except Exception as e: error_msg = f"Team GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def patch(self, team_id, project_id): """ Update role of a team on a project --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: project_id in: path description: Unique project ID required: true type: integer default: 1 - name: team_id in: path description: Unique team ID required: true type: integer default: 1 - in: body name: body required: true description: The role that the team will have on the project schema: properties: role: type: string responses: 201: description: Team project assignment created 401: description: Forbidden, if user is not a manager of the project 403: description: Forbidden, if user is not authenticated 404: description: Not found 500: description: Internal Server Error """ if not TeamService.is_user_team_manager(team_id, token_auth.current_user()): return { "Error": "User is not an admin or a manager for the team" }, 401 try: role = request.get_json(force=True)["role"] except DataError as e: current_app.logger.error(f"Error validating request: {str(e)}") return str(e), 400 try: TeamService.change_team_role(team_id, project_id, role) return {"Status": "Team role updated successfully."}, 200 except NotFound as e: return {"Error": str(e)}, 404 except TeamServiceError as e: return str(e), 402 except Exception as e: error_msg = f"Team-Project PATCH - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def post(self, team_id): """ Updates a team information --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: team_id in: path description: Unique team ID required: true type: integer default: 1 - in: body name: body required: true description: JSON object for updating a team schema: properties: name: type: string default: HOT - Mappers logo: type: string default: https://tasks.hotosm.org/assets/img/hot-tm-logo.svg members: type: array items: schema: $ref: "#/definitions/TeamMembers" organisation: type: string default: HOT description: type: string default: HOT's mapping editors inviteOnly: type: boolean default: false responses: 201: description: Team updated successfully 400: description: Client Error - Invalid Request 401: description: Unauthorized - Invalid credentials 500: description: Internal Server Error """ try: team_dto = TeamDTO(request.get_json()) team_dto.team_id = team_id team_dto.validate() authenticated_user_id = token_auth.current_user() team_details_dto = TeamService.get_team_as_dto( team_id, authenticated_user_id) org = TeamService.assert_validate_organisation( team_dto.organisation_id) TeamService.assert_validate_members(team_details_dto) if not TeamService.is_user_team_manager( team_id, authenticated_user_id ) and not OrganisationService.can_user_manage_organisation( org.id, authenticated_user_id): return { "Error": "User is not a admin or a manager for the team" }, 401 except DataError as e: current_app.logger.error(f"error validating request: {str(e)}") return str(e), 400 try: TeamService.update_team(team_dto) return {"Status": "Updated"}, 200 except NotFound as e: return {"Error": str(e)}, 404 except TeamServiceError as e: return str(e), 402 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 post(self, team_id, project_id): """ Assign a team to a project --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: project_id in: path description: Unique project ID required: true type: integer default: 1 - name: team_id in: path description: Unique team ID required: true type: integer default: 1 - in: body name: body required: true description: The role that the team will have on the project schema: properties: role: type: string responses: 201: description: Team project assignment created 401: description: Forbidden, if user is not a manager of the project 403: description: Forbidden, if user is not authenticated 404: description: Not found 500: description: Internal Server Error """ if not TeamService.user_is_manager(team_id, token_auth.current_user()): return {"Error": "User is not an admin or a manager for the team"}, 401 try: role = request.get_json(force=True)["role"] except DataError as e: current_app.logger.error(f"Error validating request: {str(e)}") return str(e), 400 try: TeamService.add_team_project(team_id, project_id, role) return ( { "Success": "Team {} assigned to project {} with role {}".format( team_id, project_id, role ) }, 201, ) except Exception as e: error_msg = f"Project Team POST - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def test_leave_team(self): team_id = 1 username = "******" with self.assertRaises(NotFound): TeamService.leave_team(team_id, username)
def post(self, team_id): """ Message all team members --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: team_id in: path description: Unique team ID required: true type: integer default: 1 - in: body name: body required: true description: JSON object for creating message schema: properties: subject: type: string default: Thanks required: true message: type: string default: Thanks for your contribution required: true responses: 200: description: Message sent successfully 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 500: description: Internal Server Error """ try: authenticated_user_id = token_auth.current_user() team_id = request.view_args["team_id"] message_dto = MessageDTO(request.get_json()) # Validate if team is present try: team = TeamService.get_team_by_id(team_id) except NotFound: return {"Error": "Team not found"}, 404 is_manager = TeamService.is_user_team_manager( team_id, authenticated_user_id) if not is_manager: raise ValueError message_dto.from_user_id = authenticated_user_id message_dto.validate() if not message_dto.message.strip( ) or not message_dto.subject.strip(): raise DataError({"Validation": "Empty message not allowed"}) except DataError as e: current_app.logger.error(f"Error validating request: {str(e)}") return {"Error": "Request payload did not match validation"}, 400 except ValueError: return { "Error": "Unauthorised to send message to team members" }, 403 try: threading.Thread( target=TeamService.send_message_to_all_team_members, args=(team_id, team.name, message_dto), ).start() return {"Success": "Message sent successfully"}, 200 except ValueError as e: return {"Error": str(e)}, 403 except Exception as e: error_msg = f"Send message all - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to send messages to team members"}, 500
def post(self, team_id): """ Removes a user from a team --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: team_id in: path description: Unique team ID required: true type: integer default: 1 - in: body name: body required: true description: JSON object to remove user from team schema: properties: username: type: string default: 1 required: true responses: 200: description: Member deleted 403: description: Forbidden, if user attempting to ready other messages 404: description: Not found 500: description: Internal Server Error """ try: authenticated_user_id = token_auth.current_user() username = request.get_json(force=True)["username"] request_user = User.get_by_id(authenticated_user_id) if (TeamService.is_user_team_manager(team_id, authenticated_user_id) or request_user.username == username): TeamService.leave_team(team_id, username) return {"Success": "User removed from the team"}, 200 else: return ( { "Error": "You don't have permissions to remove {} from this team." .format(username) }, 403, ) except NotFound: return {"Error": "No team member found"}, 404 except Exception as e: error_msg = f"TeamMembers DELETE - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def get(self): """ Gets all teams --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - in: query name: team_name description: name of the team to filter by type: str default: null - in: query name: member description: user ID to filter teams that the users belongs to, user must be active. type: str default: null - in: query name: manager description: user ID to filter teams that the users has MANAGER role type: str default: null - in: query name: member_request description: user ID to filter teams that the user has send invite request to type: str default: null - in: query name: team_role description: team role for project type: str default: null - in: query name: organisation description: organisation ID to filter teams type: str default: null responses: 201: description: Team list returned successfully 400: description: Client Error - Invalid Request 401: description: Unauthorized - Invalid credentials 500: description: Internal Server Error """ try: user_id = token_auth.current_user() except Exception as e: error_msg = f"Teams GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500 filters = {} filters["user_id"] = user_id filters["team_name_filter"] = request.args.get("team_name") try: member_filter = request.args.get("member") filters["member_filter"] = int( member_filter) if member_filter else None manager_filter = request.args.get("manager") filters["manager_filter"] = int( manager_filter) if manager_filter else None role_filter = request.args.get("team_role") filters["team_role_filter"] = role_filter member_request_filter = request.args.get("member_request") filters["member_request_filter"] = ( int(member_request_filter) if member_request_filter else None) organisation_filter = request.args.get("organisation") filters["organisation_filter"] = (int(organisation_filter) if organisation_filter else None) teams = TeamService.get_all_teams(**filters) return teams.to_primitive(), 200 except Exception as e: error_msg = f"User GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def patch(self, team_id): """ Take action on a team invite --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: team_id in: path description: Unique team ID required: true type: integer default: 1 - in: body name: body required: true description: JSON object to accept or reject a request to join team schema: properties: username: type: string required: true type: type: string default: join-response required: true role: type: string default: member required: false action: type: string default: accept required: true responses: 200: description: Member added 403: description: Forbidden 404: description: Not found 500: description: Internal Server Error """ try: json_data = request.get_json(force=True) username = json_data["username"] request_type = json_data.get("type", "join-response") action = json_data["action"] role = json_data.get("role", "member") except DataError as e: current_app.logger.error(f"error validating request: {str(e)}") return str(e), 400 try: authenticated_user_id = token_auth.current_user() if request_type == "join-response": if TeamService.is_user_team_manager(team_id, authenticated_user_id): TeamService.accept_reject_join_request( team_id, authenticated_user_id, username, role, action) return {"Success": "True"}, 200 else: return ( { "Error": "You don't have permissions to approve this join team request" }, 403, ) elif request_type == "invite-response": TeamService.accept_reject_invitation_request( team_id, authenticated_user_id, username, role, action) return {"Success": "True"}, 200 except Exception as e: raise error_msg = f"Team Join PUT - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
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 test_delete_team_project(self): team_id = 1 with self.assertRaises(TeamServiceError): TeamService.delete_team(team_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 post(self, team_id): """ Request to join a team --- tags: - teams produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: team_id in: path description: Unique team ID required: true type: integer default: 1 - in: body name: body required: true description: JSON object to join team schema: properties: username: type: string required: true role: type: string required: false responses: 200: description: Member added 403: description: Forbidden 404: description: Not found 500: description: Internal Server Error """ try: post_data = request.get_json(force=True) username = post_data["username"] role = post_data.get("role", None) except (DataError, KeyError) as e: current_app.logger.error(f"error validating request: {str(e)}") return str(e), 400 try: authenticated_user_id = token_auth.current_user() TeamService.join_team(team_id, authenticated_user_id, username, role) if TeamService.is_user_team_manager(team_id, authenticated_user_id): return {"Success": "User added to the team"}, 200 else: return { "Success": "Request to join the team sent successfully." }, 200 except TeamJoinNotAllowed as e: return {"Error": str(e)}, 403 except Exception as e: error_msg = f"User POST - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500