def send_message_after_chat(chat_from: int, chat: str, project_id: int): """ Send alert to user if they were @'d in a chat message """ current_app.logger.debug("Sending Message After Chat") usernames = MessageService._parse_message_for_username( chat, project_id) if len(usernames) == 0: return # Nobody @'d so return link = MessageService.get_project_link(project_id, include_chat_section=True) messages = [] for username in usernames: current_app.logger.debug(f"Searching for {username}") try: user = UserService.get_user_by_username(username) except NotFound: current_app.logger.error(f"Username {username} not found") continue # If we can't find the user, keep going no need to fail message = Message() message.message_type = MessageType.MENTION_NOTIFICATION.value message.project_id = project_id message.from_user_id = chat_from message.to_user_id = user.id message.subject = f"You were mentioned in {link} chat" message.message = chat messages.append(dict(message=message, user=user)) MessageService._push_messages(messages) query = ( """ select user_id from project_favorites where project_id = :project_id""" ) result = db.engine.execute(text(query), project_id=project_id) favorited_users = [r[0] for r in result] if len(favorited_users) != 0: project_link = MessageService.get_project_link( project_id, include_chat_section=True) # project_title = ProjectService.get_project_title(project_id) messages = [] for user_id in favorited_users: try: user = UserService.get_user_dto_by_id(user_id) except NotFound: continue # If we can't find the user, keep going no need to fail message = Message() message.message_type = MessageType.PROJECT_CHAT_NOTIFICATION.value message.project_id = project_id message.to_user_id = user.id message.subject = f"{chat_from} left a comment in {project_link}" message.message = chat messages.append(dict(message=message, user=user)) # it's important to keep that line inside the if to avoid duplicated emails MessageService._push_messages(messages)
def send_message_to_all_team_members(team_id: int, team_name: str, message_dto: MessageDTO): """Sends supplied message to all contributors in a team. Message all team members can take over a minute to run, so this method is expected to be called on its own thread""" app = ( create_app() ) # Because message-all run on background thread it needs it's own app context with app.app_context(): team_members = TeamService._get_active_team_members(team_id) sender = UserService.get_user_by_id( message_dto.from_user_id).username message_dto.message = ( "A message from {}, manager of {} team:<br/><br/>{}".format( MessageService.get_user_profile_link(sender), MessageService.get_team_link(team_name, team_id, False), markdown(message_dto.message, output_format="html"), )) messages = [] for team_member in team_members: if team_member.user_id != message_dto.from_user_id: message = Message.from_dto(team_member.user_id, message_dto) message.message_type = MessageType.TEAM_BROADCAST.value message.save() user = UserService.get_user_by_id(team_member.user_id) messages.append(dict(message=message, user=user)) MessageService._push_messages(messages)
def update_stats_after_task_state_change( project_id: int, user_id: int, last_state: TaskStatus, new_state: TaskStatus, action="change", ): """ Update stats when a task has had a state change """ if new_state in [ TaskStatus.READY, TaskStatus.LOCKED_FOR_VALIDATION, TaskStatus.LOCKED_FOR_MAPPING, ]: return # No stats to record for these states project = ProjectService.get_project_by_id(project_id) user = UserService.get_user_by_id(user_id) project, user = StatsService._update_tasks_stats( project, user, last_state, new_state, action ) UserService.upsert_mapped_projects(user_id, project_id) project.last_updated = timestamp() # Transaction will be saved when task is saved return project, user
def accept_reject_join_request(team_id, from_user_id, username, function, action): from_user = UserService.get_user_by_id(from_user_id) to_user_id = UserService.get_user_by_username(username).id team = TeamService.get_team_by_id(team_id) MessageService.accept_reject_request_to_join_team( from_user_id, from_user.username, to_user_id, team.name, team_id, action) is_member = TeamService.is_user_team_member(team_id, to_user_id) if action == "accept": if is_member: TeamService.activate_team_member(team_id, to_user_id) else: TeamService.add_team_member( team_id, to_user_id, TeamMemberFunctions[function.upper()].value, True, ) elif action == "reject": if is_member: TeamService.delete_invite(team_id, to_user_id) else: raise TeamServiceError("Invalid action type")
def send_invite(team_id, from_user_id, username): to_user = UserService.get_user_by_username(username) from_user = UserService.get_user_by_id(from_user_id) team = TeamService.get_team_by_id(team_id) MessageService.send_invite_to_join_team(from_user_id, from_user.username, to_user.id, team.name, team_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 send_message_after_comment(comment_from: int, comment: str, task_id: int, project_id: int): """ Will send a canned message to anyone @'d in a comment """ usernames = MessageService._parse_message_for_username( comment, project_id) if len(usernames) != 0: task_link = MessageService.get_task_link(project_id, task_id) messages = [] for username in usernames: try: user = UserService.get_user_by_username(username) except NotFound: continue # If we can't find the user, keep going no need to fail message = Message() message.message_type = MessageType.MENTION_NOTIFICATION.value message.project_id = project_id message.task_id = task_id message.from_user_id = comment_from message.to_user_id = user.id message.subject = f"You were mentioned in a comment in {task_link} of Project {project_id}" message.message = comment messages.append(dict(message=message, user=user)) MessageService._push_messages(messages) # Notify all contributors except the user that created the comment. results = (TaskHistory.query.with_entities( TaskHistory.user_id.distinct() ).filter(TaskHistory.project_id == project_id).filter( TaskHistory.task_id == task_id).filter( TaskHistory.user_id != comment_from).filter( TaskHistory.action == TaskAction.STATE_CHANGE.name).all()) contributed_users = [r[0] for r in results] if len(contributed_users) != 0: user_from = User.query.get(comment_from) if user_from is None: raise ValueError("Username not found") task_link = MessageService.get_task_link(project_id, task_id) messages = [] for user_id in contributed_users: try: user = UserService.get_user_dto_by_id(user_id) except NotFound: continue # If we can't find the user, keep going no need to fail message = Message() message.message_type = MessageType.TASK_COMMENT_NOTIFICATION.value message.project_id = project_id message.task_id = task_id message.to_user_id = user.id message.subject = f"{user_from.username} left a comment in {task_link} of Project {project_id}" message.message = comment messages.append(dict(message=message, user=user)) MessageService._push_messages(messages)
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 send_favorite_project_activities(user_id: int): current_app.logger.debug("Sending Favorite Project Activities") favorited_projects = UserService.get_projects_favorited(user_id) contributed_projects = UserService.get_projects_mapped(user_id) if contributed_projects is None: contributed_projects = [] for favorited_project in favorited_projects.favorited_projects: contributed_projects.append(favorited_project.project_id) recently_updated_projects = ( Project.query.with_entities( Project.id, func.DATE(Project.last_updated).label("last_updated") ) .filter(Project.id.in_(contributed_projects)) .filter( func.DATE(Project.last_updated) > datetime.date.today() - datetime.timedelta(days=300) ) ) user = UserService.get_user_dto_by_id(user_id) if user.projects_notifications is False: return messages = [] for project in recently_updated_projects: activity_message = [] query_last_active_users = """ select distinct(user_id) from (select user_id from task_history where project_id = :project_id order by action_date desc limit 15 ) t """ last_active_users = db.engine.execute( text(query_last_active_users), project_id=project.id ) for recent_user_id in last_active_users: recent_user_details = UserService.get_user_by_id(recent_user_id) user_profile_link = MessageService.get_user_profile_link( recent_user_details.username ) activity_message.append(user_profile_link) activity_message = str(activity_message)[1:-1] project_link = MessageService.get_project_link(project.id) message = Message() message.message_type = MessageType.PROJECT_ACTIVITY_NOTIFICATION.value message.project_id = project.id message.to_user_id = user.id message.subject = ( "Recent activities from your contributed/favorited Projects" ) message.message = ( f"{activity_message} contributed to Project {project_link} recently" ) messages.append(dict(message=message, user=user)) MessageService._push_messages(messages)
def test_upsert_inserts_project_if_not_exists(self): self.test_project, self.test_user = create_canned_project() # Arrange UserService.upsert_mapped_projects(self.test_user.id, self.test_project.id) # Act projects = UserService.get_mapped_projects(self.test_user.username, "en") # Assert mapped_project = projects.mapped_projects[0] self.assertEqual( mapped_project.project_id, self.test_project.id ) # We should find we've mapped the test project
def patch(self, username, role): """ Allows PMs to set a user's role --- tags: - users produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: username in: path description: Mapper's OpenStreetMap username required: true type: string default: Thinkwhere - name: role in: path description: The role to add required: true type: string default: ADMIN responses: 200: description: Role set 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 404: description: User not found 500: description: Internal Server Error """ try: UserService.add_role_to_user(tm.authenticated_user_id, username, role) return {"Success": "Role Added"}, 200 except UserServiceError: return {"Error": "Not allowed"}, 403 except NotFound: return {"Error": "User or mapping not found"}, 404 except Exception as e: error_msg = f"User GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to update user role"}, 500
def is_user_permitted_to_validate(project_id, user_id): """ Check if the user is allowed to validate on the project in scope """ if UserService.is_user_blocked(user_id): return False, ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST project = ProjectService.get_project_by_id(project_id) if project.license_id: if not UserService.has_user_accepted_license(user_id, project.license_id): return False, ValidatingNotAllowed.USER_NOT_ACCEPTED_LICENSE validation_permission = project.validation_permission # is_admin or is_author or is_org_manager or is_manager_team is_manager_permission = False if ProjectAdminService.is_user_action_permitted_on_project(user_id, project_id): is_manager_permission = True # Draft (public/private) accessible only for is_manager_permission if ( ProjectStatus(project.status) == ProjectStatus.DRAFT and not is_manager_permission ): return False, ValidatingNotAllowed.PROJECT_NOT_PUBLISHED is_restriction = None if not is_manager_permission and validation_permission: is_restriction = ProjectService.evaluate_validation_permission( project_id, user_id, validation_permission ) tasks = Task.get_locked_tasks_for_user(user_id) if len(tasks.locked_tasks) > 0: return False, ValidatingNotAllowed.USER_ALREADY_HAS_TASK_LOCKED is_allowed_user = None if project.private and not is_manager_permission: # Check if user is in allowed user list is_allowed_user = ProjectService.is_user_in_the_allowed_list( project.allowed_users, user_id ) if is_allowed_user: return True, "User allowed to validate" if not is_manager_permission and is_restriction: return is_restriction elif project.private and not ( is_manager_permission or is_allowed_user or not is_restriction ): return False, ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST return True, "User allowed to validate"
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 patch(self, username, level): """ Allows PMs to set a user's mapping level --- tags: - users produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: username in: path description: Mapper's OpenStreetMap username required: true type: string default: Thinkwhere - name: level in: path description: The mapping level that should be set required: true type: string default: ADVANCED responses: 200: description: Level set 400: description: Bad Request - Client Error 401: description: Unauthorized - Invalid credentials 404: description: User not found 500: description: Internal Server Error """ try: UserService.set_user_mapping_level(username, level) return {"Success": "Level set"}, 200 except UserServiceError: return {"Error": "Not allowed"}, 400 except NotFound: return {"Error": "User or mapping not found"}, 404 except Exception as e: error_msg = f"User GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to update mapping level"}, 500
def is_user_permitted_to_validate(project_id, user_id): """ Check if the user is allowed to validate on the project in scope """ if UserService.is_user_blocked(user_id): return False, ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST project = ProjectService.get_project_by_id(project_id) if project.license_id: if not UserService.has_user_accepted_license(user_id, project.license_id): return False, ValidatingNotAllowed.USER_NOT_ACCEPTED_LICENSE validation_permission = project.validation_permission is_manager_permission = False # is_admin or is_author or is_org_manager or is_manager_team if ProjectAdminService.is_user_action_permitted_on_project(user_id, project_id): is_manager_permission = True if ( ProjectStatus(project.status) != ProjectStatus.PUBLISHED and not is_manager_permission ): return False, ValidatingNotAllowed.PROJECT_NOT_PUBLISHED tasks = Task.get_locked_tasks_for_user(user_id) if len(tasks.locked_tasks) > 0: return False, ValidatingNotAllowed.USER_ALREADY_HAS_TASK_LOCKED if project.private and not is_manager_permission: # Check user is in allowed users try: next(user for user in project.allowed_users if user.id == user_id) except StopIteration: return False, ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST is_restriction = ProjectService.evaluate_validation_permission( project_id, user_id, validation_permission ) if is_restriction: return is_restriction if project.validation_permission and not is_manager_permission: is_restriction = ProjectService.evaluate_validation_permission( project_id, user_id, validation_permission ) if is_restriction: return is_restriction return True, "User allowed to validate"
def _is_user_intermediate_or_advanced(user_id): """ Helper method to determine if user level is not beginner """ user_mapping_level = UserService.get_mapping_level(user_id) if user_mapping_level not in [MappingLevel.INTERMEDIATE, MappingLevel.ADVANCED]: return False return True
def send_message_to_all_contributors(project_id: int, message_dto: MessageDTO): """Sends supplied message to all contributors on specified project. Message all contributors can take over a minute to run, so this method is expected to be called on its own thread""" app = ( create_app() ) # Because message-all run on background thread it needs it's own app context with app.app_context(): contributors = Message.get_all_contributors(project_id) message_dto.message = "A message from {} managers:<br/><br/>{}".format( MessageService.get_project_link(project_id), markdown(message_dto.message, output_format="html"), ) messages = [] for contributor in contributors: message = Message.from_dto(contributor[0], message_dto) message.message_type = MessageType.BROADCAST.value message.project_id = project_id user = UserService.get_user_by_id(contributor[0]) messages.append(dict(message=message, user=user)) MessageService._push_messages(messages)
def send_message_to_all_contributors(project_id: int, message_dto: MessageDTO): """ Sends supplied message to all contributors on specified project. Message all contributors can take over a minute to run, so this method is expected to be called on its own thread """ app = ( create_app() ) # Because message-all run on background thread it needs it's own app context with app.app_context(): contributors = Message.get_all_contributors(project_id) project_link = MessageService.get_project_link(project_id) message_dto.message = ( f"{project_link}<br/><br/>" + message_dto.message ) # Append project link to end of message messages = [] for contributor in contributors: message = Message.from_dto(contributor[0], message_dto) message.message_type = MessageType.BROADCAST.value message.project_id = project_id message.save() user = UserService.get_user_by_id(contributor[0]) messages.append(dict(message=message, user=user)) MessageService._push_messages(messages)
def get(self): """ Get projects favorited by a user --- tags: - favorites produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== responses: 200: description: Projects favorited by user 404: description: User not found 500: description: Internal Server Error """ try: favs_dto = UserService.get_projects_favorited( token_auth.current_user()) return favs_dto.to_primitive(), 200 except NotFound: return {"Error": "User not found"}, 404 except Exception as e: error_msg = f"UserFavorites GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
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 get(self): """ Get paged list of all usernames --- tags: - users produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded sesesion token required: true type: string default: Token sessionTokenHere== - in: query name: page description: Page of results user requested type: integer - in: query name: username description: Full or part username type: string - in: query name: role description: Role of User, eg ADMIN, PROJECT_MANAGER type: string - in: query name: level description: Level of User, eg BEGINNER type: string responses: 200: description: Users found 401: description: Unauthorized - Invalid credentials 500: description: Internal Server Error """ try: query = UserSearchQuery() query.page = ( int(request.args.get("page")) if request.args.get("page") else 1 ) query.username = request.args.get("username") query.mapping_level = request.args.get("level") query.role = request.args.get("role") query.validate() except DataError as e: current_app.logger.error(f"Error validating request: {str(e)}") return {"Error": "Unable to fetch user list"}, 400 try: users_dto = UserService.get_all_users(query) return users_dto.to_primitive(), 200 except Exception as e: error_msg = f"User GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to fetch user list"}, 500
def test_user_can_register_with_correct_mapping_level(self, mock_user): # Act test_user = UserService().register_user( 12, "Thinkwhere", 300, "some_picture_url", None ) # Assert self.assertEqual(test_user.mapping_level, MappingLevel.INTERMEDIATE.value)
def test_admin_role_is_recognized_as_a_validator(self, mock_user): # Arrange stub_user = User() stub_user.role = UserRole.ADMIN.value mock_user.return_value = stub_user # Act / Assert self.assertTrue(UserService.is_user_validator(123))
def test_mapper_role_is_not_recognized_as_a_validator(self, mock_user): # Arrange stub_user = User() stub_user.role = UserRole.MAPPER.value mock_user.return_value = stub_user # Act / Assert self.assertFalse(UserService.is_user_validator(123))
def _push_messages(messages): if len(messages) == 0: return messages_objs = [] for i, message in enumerate(messages): user = message.get("user") obj = message.get("message") # Store message in the database only if mentions option are disabled. if (user.mentions_notifications is False and obj.message_type == MessageType.MENTION_NOTIFICATION.value): messages_objs.append(obj) continue if (user.projects_notifications is False and obj.message_type == MessageType.PROJECT_ACTIVITY_NOTIFICATION.value): continue if (user.projects_notifications is False and obj.message_type == MessageType.BROADCAST.value): continue if (user.teams_notifications is False and obj.message_type == MessageType.TEAM_BROADCAST.value): messages_objs.append(obj) continue if user.comments_notifications is False and obj.message_type in ( MessageType.TASK_COMMENT_NOTIFICATION.value, MessageType.PROJECT_CHAT_NOTIFICATION.value, ): continue if user.tasks_notifications is False and obj.message_type in ( MessageType.VALIDATION_NOTIFICATION.value, MessageType.INVALIDATION_NOTIFICATION.value, ): messages_objs.append(obj) continue messages_objs.append(obj) SMTPService.send_email_alert( user.email_address, user.username, message["message"].id, UserService.get_user_by_id( message["message"].from_user_id).username, message["message"].project_id, message["message"].task_id, clean_html(message["message"].subject), message["message"].message, obj.message_type, ) if i + 1 % 10 == 0: time.sleep(0.5) # Flush messages to the database. if len(messages_objs) > 0: db.session.add_all(messages_objs) db.session.flush() db.session.commit()
def test_mapper_level_updates_correctly( self, mock_user, mock_osm, mock_save, mock_message ): # Arrange test_user = User() test_user.username = "******" test_user.mapping_level = MappingLevel.BEGINNER.value mock_user.return_value = test_user test_osm = UserOSMDTO() test_osm.changeset_count = 350 mock_osm.return_value = test_osm # Act UserService.check_and_update_mapper_level(12) # Assert self.assertTrue(test_user.mapping_level, MappingLevel.INTERMEDIATE.value)
def create_or_update_user_interests(user_id, interests): user = UserService.get_user_by_id(user_id) user.create_or_update_interests(interests) # Return DTO. dto = InterestsListDTO() dto.interests = [i.as_dto() for i in user.interests] return dto
def patch(self, is_expert): """ Allows user to enable or disable expert mode --- tags: - users produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: is_expert in: path description: true to enable expert mode, false to disable required: true type: string responses: 200: description: Mode set 400: description: Bad Request - Client Error 401: description: Unauthorized - Invalid credentials 404: description: User not found 500: description: Internal Server Error """ try: UserService.set_user_is_expert(tm.authenticated_user_id, is_expert == "true") return {"Success": "Expert mode updated"}, 200 except UserServiceError: return {"Error": "Not allowed"}, 400 except NotFound: return {"Error": "User not found"}, 404 except Exception as e: error_msg = f"UserSetExpert POST - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to update expert mode"}, 500
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 is_user_an_org_manager(organisation_id: int, user_id: int): """ Check that the user is an manager for the org """ org = Organisation.get(organisation_id) if org is None: raise NotFound() user = UserService.get_user_by_id(user_id) return user in org.managers