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_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_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 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 assert_validate_members(team_dto: TeamDTO): """ Validates that the users exist""" if len(team_dto.members) == 0: raise TeamServiceError("Must have at least one member") members = [] managers = 0 for member in team_dto.members: try: UserService.get_user_by_username(member["name"]) except NotFound: raise NotFound(f'User {member["name"]} does not exist') if member["function"] == TeamMemberFunctions.MANAGER.name: managers += 1 members.append(member) if managers == 0: raise TeamServiceError( "Must have at least one manager in team") team_dto.members = members
def assert_validate_users(organisation_dto: OrganisationDTO): """ Validates that the users exist""" if organisation_dto.managers and len(organisation_dto.managers) == 0: raise OrganisationServiceError("Must have at least one admin") managers = [] for user in organisation_dto.managers: try: admin = UserService.get_user_by_username(user) except NotFound: raise NotFound(f"User {user} does not exist") managers.append(admin.username) organisation_dto.managers = managers
def get_user_invalidated_tasks( as_validator, username: str, preferred_locale: str, closed=None, project_id=None, page=1, page_size=10, sort_by="updated_date", sort_direction="desc", ) -> InvalidatedTasks: """ Get invalidated tasks either mapped or invalidated by the user """ user = UserService.get_user_by_username(username) query = ( TaskInvalidationHistory.query.filter_by(invalidator_id=user.id) if as_validator else TaskInvalidationHistory.query.filter_by(mapper_id=user.id) ) if closed is not None: query = query.filter_by(is_closed=closed) if project_id is not None: query = query.filter_by(project_id=project_id) results = query.order_by(text(sort_by + " " + sort_direction)).paginate( page, page_size, True ) project_names = {} invalidated_tasks_dto = InvalidatedTasks() for entry in results.items: dto = InvalidatedTask() dto.task_id = entry.task_id dto.project_id = entry.project_id dto.history_id = entry.invalidation_history_id dto.closed = entry.is_closed dto.updated_date = entry.updated_date if dto.project_id not in project_names: project_names[dto.project_id] = ProjectInfo.get_dto_for_locale( dto.project_id, preferred_locale ).name dto.project_name = project_names[dto.project_id] invalidated_tasks_dto.invalidated_tasks.append(dto) invalidated_tasks_dto.pagination = Pagination(results) return invalidated_tasks_dto
def transfer_project_to(project_id: int, transfering_user_id: int, username: str): """ Transfers project from old owner (transfering_user_id) to new owner (username) """ project = Project.get(project_id) # Check permissions for the user (transferring_user_id) who initiatied the action if not ProjectAdminService.is_user_action_permitted_on_project( transfering_user_id, project_id): raise ValueError("User action not permitted") new_owner = UserService.get_user_by_username(username) # Check permissions for the new owner - must be an admin or project's org manager or a PM team member if not ProjectAdminService.is_user_action_permitted_on_project( new_owner.id, project_id): raise ValueError("User action not permitted") else: project.save()
def _validate_allowed_users(project_dto: ProjectDTO): """ Ensures that all usernames are known and returns their user ids """ if len(project_dto.allowed_usernames) == 0: raise ProjectAdminServiceError( "Must have at least one allowed user on a private project") try: allowed_users = [] for username in project_dto.allowed_usernames: user = UserService.get_user_by_username(username) allowed_users.append(user) # Dynamically attach the user object to the DTO for more efficient persistence project_dto.allowed_users = allowed_users except NotFound: raise ProjectAdminServiceError( f"allowedUsers contains an unknown username {user}")
def authenticate_email_token(username: str, token: str): """ Validate that the email token is valid """ try: user = UserService.get_user_by_username(username) except NotFound: raise AuthServiceError("Unable to authenticate") is_valid, tokenised_email = AuthenticationService.is_valid_token(token, 86400) if not is_valid: raise AuthServiceError("Unable to authenticate") if user.email_address != tokenised_email: raise AuthServiceError("Unable to authenticate") # Token is valid so update DB and return user.set_email_verified_status(is_verified=True) return AuthenticationService._get_email_validated_url(True)
def join_team(team_id: int, requesting_user: int, username: str, role: str = None): is_manager = TeamService.is_user_team_manager(team_id, requesting_user) team = TeamService.get_team_by_id(team_id) user = UserService.get_user_by_username(username) if TeamService.is_user_team_member(team.id, user.id): raise TeamJoinNotAllowed( "User is already a member of this team or has already requested to join" ) if is_manager: if role: try: role = TeamMemberFunctions[role.upper()].value except KeyError: raise Exception("Invalid TeamMemberFunction") else: role = TeamMemberFunctions.MEMBER.value TeamService.add_team_member(team_id, user.id, role, True) else: if user.id != requesting_user: raise TeamJoinNotAllowed("User not allowed to join team") role = TeamMemberFunctions.MEMBER.value # active if the team is open if team.invite_only: active = False else: active = True TeamService.add_team_member(team_id, user.id, role, active) if team.invite_only: team_managers = team.get_team_managers() for member in team_managers: MessageService.send_request_to_join_team( user.id, user.username, member.user_id, team.name, team_id)
def accept_reject_invitation_request(team_id, from_user_id, username, function, action): from_user = UserService.get_user_by_id(from_user_id) to_user = UserService.get_user_by_username(username) team = TeamService.get_team_by_id(team_id) team_members = TeamService._get_team_managers(team_id) for member in team_members: MessageService.accept_reject_invitation_request_for_team( from_user_id, from_user.username, member.user_id, to_user.username, team.name, action, ) if action == "accept": TeamService.add_team_member( team_id, from_user_id, TeamMemberFunctions[function.upper()].value)
def get(self, username): """ Get interests by username --- tags: - interests 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 responses: 200: description: User interests returned 404: description: User not found 500: description: Internal Server Error """ try: user = UserService.get_user_by_username(username) interests_dto = UserService.get_interests(user) return interests_dto.to_primitive(), 200 except NotFound: return {"Error": "User not found"}, 404 except Exception as e: error_msg = f"UserInterests GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def leave_team(team_id, username): user = UserService.get_user_by_username(username) team_member = TeamMembers.query.filter( TeamMembers.team_id == team_id, TeamMembers.user_id == user.id).one() team_member.delete()
def get_project_user_stats(project_id: int, username: str) -> ProjectUserStatsDTO: """ Gets the user stats for a specific project """ project = ProjectService.get_project_by_id(project_id) user = UserService.get_user_by_username(username) return project.get_project_user_stats(user.id)
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 """ # Because message-all run on background thread it needs it's own app context app = create_app() with app.app_context(): usernames = MessageService._parse_message_for_username( chat, project_id) if len(usernames) != 0: 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""" favorited_users_results = db.engine.execute(text(query), project_id=project_id) favorited_users = [r[0] for r in favorited_users_results] # Notify all contributors except the user that created the comment. contributed_users_results = (TaskHistory.query.with_entities( TaskHistory.user_id.distinct() ).filter(TaskHistory.project_id == project_id).filter( TaskHistory.user_id != chat_from).filter( TaskHistory.action == TaskAction.STATE_CHANGE.name).all()) contributed_users = [r[0] for r in contributed_users_results] users_to_notify = list(set(contributed_users + favorited_users)) if len(users_to_notify) != 0: from_user = User.query.get(chat_from) from_user_link = MessageService.get_user_link( from_user.username) project_link = MessageService.get_project_link( project_id, include_chat_section=True) messages = [] for user_id in users_to_notify: 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.from_user_id = chat_from message.to_user_id = user.id message.subject = ( f"{from_user_link} 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)