def delete_helper(self, team_name, user_id) -> ResponseTuple: """ Permanently delete a team. :param team_name: Name of team to be deleted :param user_id: Slack ID of user who called command :return: error message if user has insufficient permission level or team deleted unsuccessfully, otherwise return success message """ try: command_user = self.facade.retrieve(User, user_id) teams = self.facade.query(Team, [('github_team_name', team_name)]) if len(teams) != 1: return self.lookup_error, 200 team = teams[0] if not check_permissions(command_user, team): return self.permission_error, 200 self.facade.delete(Team, team.github_team_id) self.gh.org_delete_team(int(team.github_team_id)) return f"Team {team_name} deleted", 200 except LookupError: return self.lookup_error, 200 except GithubAPIException as e: logging.error("team delete unsuccessful") return f"Team delete was unsuccessful with " \ f"the following error: {e.data}", 200
def team_delete(self, caller_id: str, gh_team_name: str) -> None: """ Permanently delete a team. :param gh_team_name: Github team name of the team to delete :param caller_id: Slack ID of user who called command :raises: LookupError if the calling user or the team to delete could not be found :raises: RuntimeError if more than one team has the specified team name :raises: PermissionError if the calling user does not have sufficient permissions to delete the specified team """ logging.info("Team delete command API called") command_user = self._db_facade.retrieve(User, caller_id) logging.debug(f"Calling user: {command_user.__str__()}") team = db_utils.get_team_by_name(self._db_facade, gh_team_name) if not check_permissions(command_user, team): msg = f"User with ID {caller_id} has insufficient permissions" \ f" to delete team {gh_team_name}" logging.error(msg) raise PermissionError(msg) self._gh_interface.org_delete_team(int(team.github_team_id)) self._db_facade.delete(Team, team.github_team_id) logging.info(f"{gh_team_name} successfully deleted")
def edit_helper(self, param_list, user_id) -> ResponseTuple: """ Edit the properties of a specific team. Team leads can only edit the teams that they are a part of, but admins can edit any teams. :param param_list: List of parameters for editing team :param user_id: Slack ID of user who called command :return: error message if user has insufficient permission level or team edited unsuccessfully, otherwise return success message """ try: command_user = self.facade.retrieve(User, user_id) command_team = param_list['team_name'] team = get_team_by_name(self.facade, command_team) if not check_permissions(command_user, team): return self.permission_error, 200 msg = f"Team edited: {command_team}, " if param_list['name'] is not None: msg += f"name: {param_list['name']}, " team.display_name = param_list['name'] if param_list['platform'] is not None: msg += f"platform: {param_list['platform']}" team.platform = param_list['platform'] if param_list['folder'] is not None: msg += f"folder: {param_list['folder']}" team.folder = param_list['folder'] self.facade.store(team) ret = {'attachments': [team.get_attachment()], 'text': msg} return ret, 200 except LookupError: return self.lookup_error, 200
def team_lead(self, caller_id: str, lead_id: str, gh_team_name: str, remove: bool = False) -> bool: """ Add a user as a team lead, and add them to team if not already added. :param caller_id: Slack ID of user who called command :param lead_id: Slack ID of user to declare as team lead :param gh_team_name: Github team name of team to add a lead to :param remove: if True, removes the user as team lead of the team :raises: LookupError if the calling user, the team to add a lead to could not be found, the user is not on the team, or the user is not a lead on the team :raises: RuntimeError if more than one team has the specified team name :raises: PermissionError if the calling user does not have sufficient permissions to add a lead to the specified team :returns: True if removal was successful, False otherwise """ logging.info("Team lead command API called") command_user = self._db_facade.retrieve(User, caller_id) logging.debug(f"Calling user: {command_user.__str__()}") team = db_utils.get_team_by_name(self._db_facade, gh_team_name) if not check_permissions(command_user, team): msg = f"User with ID {caller_id} has insufficient permissions" \ f" to add lead to team {gh_team_name}" logging.error(msg) raise PermissionError(msg) lead_user = self._db_facade.retrieve(User, lead_id) logging.debug(f"User to add as lead: {lead_user.__str__()}") if remove: if not team.has_member(lead_user.github_id): msg = f"User with Github ID {lead_user.github_id} not a " \ "member of specified team" logging.error(msg) raise LookupError(msg) if team.has_team_lead(lead_user.github_id): team.discard_team_lead(lead_user.github_id) discarded = self._db_facade.store(team) return discarded else: msg = f"User with Github ID {lead_user.github_id} not a " \ "lead of specified team" logging.error(msg) raise LookupError(msg) else: if not team.has_member(lead_user.github_id): team.add_member(lead_user.github_id) self._gh_interface.add_team_member(lead_user.github_username, team.github_team_id) team.add_team_lead(lead_user.github_id) added = self._db_facade.store(team) return added
def test_check_credentials_not_lead(self): """Test checking to see if user is lead for certain team.""" user = User("USFAS689") user.github_id = "IDGithub" team = Team("brussels", "team", "id") team.add_member(user.github_id) user.permissions_level = Permissions.team_lead self.assertFalse(util.check_permissions(user, team))
def add_helper(self, args: Namespace, user_id: str) -> ResponseTuple: """ Add user to team. If user is not admin or team lead of specified team, the user will not be added and an error message is returned. :param args: Parameters for adding user :param user_id: Slack ID of user who called command :return: error message if user added unsuccessfully or if user has insufficient permission level, otherwise returns success message """ try: command_user = self.facade.retrieve(User, user_id) command_team = args.team_name team = get_team_by_name(self.facade, command_team) if not check_permissions(command_user, team): return self.permission_error, 200 user = self.facade.retrieve(User, args.username) if len(user.github_id) == 0: return self.no_ghusername_error, 200 team.add_member(user.github_id) self.gh.add_team_member(user.github_username, team.github_team_id) self.facade.store(team) msg = "Added User to " + command_team # Update drive shares sync_team_email_perms(self.gcp, self.facade, team) # If this team is a team with special permissions, promote the # user to the appropriate permission promoted_level = Permissions.member if command_team == self.config.github_team_admin: promoted_level = Permissions.admin elif command_team == self.config.github_team_leads: promoted_level = Permissions.team_lead # Only perform promotion if it is actually a promotion. if promoted_level > user.permissions_level: logging.info(f"Promoting {command_user} to {promoted_level}") user.permissions_level = promoted_level self.facade.store(user) msg += f" and promoted user to {promoted_level}" ret = {'attachments': [team.get_attachment()], 'text': msg} return ret, 200 except LookupError: return self.lookup_error, 200 except GithubAPIException as e: logging.error("user added unsuccessfully to team") return f"User added unsuccessfully with the " \ f"following error: {e.data}", 200
def team_remove(self, caller_id: str, gh_team_name: str, rem_user_id: str) -> bool: """ Remove the specified user from a team. If the user is also a team lead, removes team lead status from Team. :param caller_id: Slack ID of user who called command :param gh_team_name: Github team name of the team to remove user from :param rem_user_id: Slack ID of user to remove from team :raises: LookupError if the calling user, user to remove, or specified team cannot be found in the database :raises: RuntimeError if more than one team has the specified team name :raises: PermissionError if the calling user has insufficient permission to remove members to the specified team :raises: GithubAPIException if an error occured removing the user from the Github team :return: True if user was removed from team successfully, False otherwise """ logging.info("Team remove command API called") command_user = self._db_facade.retrieve(User, caller_id) logging.debug(f"Calling user: {command_user.__str__()}") team = db_utils.get_team_by_name(self._db_facade, gh_team_name) if not check_permissions(command_user, team): msg = f"User with ID {caller_id} has insufficient permissions" \ f" to remove members to team {gh_team_name}" logging.error(msg) raise PermissionError(msg) rem_user = self._db_facade.retrieve(User, rem_user_id) logging.debug(f"User to remove: {rem_user.__str__()}") if not self._gh_interface.has_team_member(rem_user.github_username, team.github_team_id): msg = f"Github user {rem_user.github_username} not a member" \ f" of Github team with ID {team.github_team_id}" logging.error(msg) raise GithubAPIException(msg) self._gh_interface.remove_team_member(rem_user.github_username, team.github_team_id) team.discard_member(rem_user.github_id) if team.has_team_lead(rem_user.github_id): team.discard_team_lead(rem_user.github_id) removed = self._db_facade.store(team) return removed
def lead_helper(self, param_list, user_id) -> ResponseTuple: """ Add a user as team lead, and add them to team if not already added. If ``--remove`` flag is used, user is instead demoted from being a team lead, but not from the team. :param param_list: List of parameters for editing leads :param user_id: Slack ID of user who called command :return: error message if user has insufficient permission level or lead demoted unsuccessfully, otherwise return success message """ try: command_user = self.facade.retrieve(User, user_id) teams = self.facade.query( Team, [('github_team_name', param_list['team_name'])]) if len(teams) != 1: return self.lookup_error, 200 team = teams[0] if not check_permissions(command_user, team): return self.permission_error, 200 user = self.facade.retrieve(User, param_list["slack_id"]) msg = "" if param_list["remove"]: if not team.has_member(user.github_id): return "User not in team!", 200 if team.has_team_lead(user.github_id): team.discard_team_lead(user.github_id) self.facade.store(team) msg = f"User removed as team lead from" \ f" {param_list['team_name']}" else: if not team.has_member(user.github_id): team.add_member(user.github_id) self.gh.add_team_member(user.github_username, team.github_team_id) team.add_team_lead(user.github_id) self.facade.store(team) msg = f"User added as team lead to" \ f" {param_list['team_name']}" ret = {'attachments': [team.get_attachment()], 'text': msg} return ret, 200 except LookupError: return self.lookup_error, 200 except GithubAPIException as e: logging.error("team lead edit unsuccessful") return f"Edit team lead was unsuccessful " \ f"with the following error: {e.data}", 200
def team_edit(self, caller_id: str, gh_team_name: str, display_name: str = None, platform: str = None) -> bool: """ Edit the properties of a specific team. Team leads can only edit the teams that they are a part of, but admins can edit any team. :param caller_id: Slack ID of user who called command :param display_name: display name to change to if not None :param platform: platform to change to if not None :raises: LookupError if the calling user or team to edit could not be found :raises: RuntimeError if more than one team has the specified team name :raises: PermissionError if the calling user does not have sufficient permissions to edit the specified team :return: True if the edit was successful, False otherwise """ logging.info("Team edit command API called") command_user = self._db_facade.retrieve(User, caller_id) logging.debug(f"Calling user: {command_user.__str__()}") team = db_utils.get_team_by_name(self._db_facade, gh_team_name) if not check_permissions(command_user, team): msg = f"User with ID {caller_id} has insufficient permissions" \ f" to edit team {gh_team_name}" logging.error(msg) raise PermissionError(msg) if display_name is not None: logging.debug(f"Attaching display name {display_name} " f"to {gh_team_name}") team.display_name = display_name if platform is not None: logging.debug(f"Attaching platform {platform} to {gh_team_name}") team.platform = platform edited = self._db_facade.store(team) return edited
def remove_helper(self, param_list, user_id) -> ResponseTuple: """ Remove specified user from a team. If the user is also a team lead, removes team lead status from Team. If user is not admin or team lead of specified team, user will not be removed and an error message is returned. :param param_list: List of parameters for removing user :param user_id: Slack ID of user who called command :return: error message if user removed unsuccessfully, if user is not in team, or if user has insufficient permission level, otherwise returns success message """ try: command_user = self.facade.retrieve(User, user_id) teams = self.facade.query( Team, [('github_team_name', param_list['team_name'])]) if len(teams) != 1: return self.lookup_error, 200 team = teams[0] if not check_permissions(command_user, team): return self.permission_error, 200 user = self.facade.retrieve(User, param_list['slack_id']) if not self.gh.has_team_member(user.github_username, team.github_team_id): return "User not in team!", 200 team.discard_member(user.github_id) if team.has_team_lead(user.github_id): team.discard_team_lead(user.github_id) self.gh.remove_team_member(user.github_username, team.github_team_id) self.facade.store(team) msg = "Removed User from " + param_list['team_name'] ret = {'attachments': [team.get_attachment()], 'text': msg} return ret, 200 except LookupError: return self.lookup_error, 200 except GithubAPIException as e: logging.error("user removed unsuccessfully from team") return f"User removed unsuccessfully with " \ f"the following error: {e.data}", 200
def edit_helper(self, args: Namespace, user_id: str) -> ResponseTuple: """ Edit the properties of a specific team. Team leads can only edit the teams that they are a part of, but admins can edit any teams. :param args: Parameters for editing team :param user_id: Slack ID of user who called command :return: error message if user has insufficient permission level or team edited unsuccessfully, otherwise return success message """ try: command_user = self.facade.retrieve(User, user_id) command_team = args.team_name team = get_team_by_name(self.facade, command_team) if not check_permissions(command_user, team): return self.permission_error, 200 msg = f"Team edited: {command_team}, " if args.displayname is not None: msg += f"displayname: {args.displayname}, " team.displayname = args.displayname if args.platform is not None: msg += f"platform: {args.platform}" team.platform = args.platform if args.folder is not None: msg += f"folder: {args.folder}" team.folder = args.folder if args.github is not None: msg += f"new github team name: {args.github}" team.github_team_name = args.github self.gh.org_edit_team( int(team.github_team_id), team.github_team_name) self.facade.store(team) # Update drive shares if folder was changed if args.folder: sync_team_email_perms(self.gcp, self.facade, team) ret = {'attachments': [team.get_attachment()], 'text': msg} return ret, 200 except LookupError: return self.lookup_error, 200
def team_add(self, caller_id: str, add_user_id: str, gh_team_name: str) -> bool: """ Add a user to a team. :param caller_id: Slack ID of user who called the API :param add_user_id: Slack ID of user to add to a team :param gh_team_name: Github team name of the team to add a user to :raises: LookupError if the calling user, user to add, or specified team cannot be found in the database :raises: RuntimeError if more than one team has the specified team name :raises: PermissionError if the calling user has insufficient permission to add members to the specified team :raises: GithubAPIException if an error occurs when adding the user to the Github team :return: True if adding the member to the team was successful, False otherwise """ logging.info("Team add command API called") command_user = self._db_facade.retrieve(User, caller_id) logging.debug(f"Calling user: {command_user.__str__()}") team = db_utils.get_team_by_name(self._db_facade, gh_team_name) if not check_permissions(command_user, team): msg = f"User with ID {caller_id} has insufficient permissions" \ f" to add members to team {gh_team_name}" logging.error(msg) raise PermissionError(msg) add_user = self._db_facade.retrieve(User, add_user_id) logging.debug(f"User to add: {add_user.__str__()}") self._gh_interface.add_team_member(add_user.github_username, team.github_team_id) team.add_member(add_user.github_id) added = self._db_facade.store(team) return added
def add_helper(self, param_list, user_id) -> ResponseTuple: """ Add user to team. If user is not admin or team lead of specified team, the user will not be added and an error message is returned. :param param_list: List of parameters for adding user :param user_id: Slack ID of user who called command :return: error message if user added unsuccessfully or if user has insufficient permission level, otherwise returns success message """ try: command_user = self.facade.retrieve(User, user_id) teams = self.facade.query( Team, [('github_team_name', param_list['team_name'])]) if len(teams) != 1: return self.lookup_error, 200 team = teams[0] if not check_permissions(command_user, team): return self.permission_error, 200 user = self.facade.retrieve(User, param_list['slack_id']) team.add_member(user.github_id) self.gh.add_team_member(user.github_username, team.github_team_id) self.facade.store(team) msg = "Added User to " + param_list['team_name'] ret = {'attachments': [team.get_attachment()], 'text': msg} return ret, 200 except LookupError: return self.lookup_error, 200 except GithubAPIException as e: logging.error("user added unsuccessfully to team") return f"User added unsuccessfully with the " \ f"following error: {e.data}", 200
def handle(self, command: str, user_id: str) -> ResponseTuple: """Handle command by splitting into substrings and giving to parser.""" logging.debug("Handling ExportCommand") command_arg = shlex.split(command) args = None try: args = self.parser.parse_args(command_arg) except SystemExit: all_subcommands = list(self.subparser.choices.keys()) present_subcommands = [ subcommand for subcommand in all_subcommands if subcommand in command_arg ] present_subcommand = None if len(present_subcommands) == 1: present_subcommand = present_subcommands[0] return self.get_help(subcommand=present_subcommand), 200 if args.which == "emails": try: command_user = self.facade.retrieve(User, user_id) if not check_permissions(command_user, None): return self.permission_error, 200 # Check if team name is provided if args.team is not None: users = self.get_team_users(args.team) return self.export_emails_helper(users) else: # if team name is not provided, export all emails users = self.facade.query(User) return self.export_emails_helper(users) except LookupError: return self.lookup_error, 200 else: return self.get_help(), 200
def refresh_helper(self, user_id) -> ResponseTuple: """ Ensure that the local team database is the same as GitHub's. In the event that our local team database is outdated compared to the teams on GitHub, this command can be called to fix things. :return: error message if user has insufficient permission level otherwise returns success messages with # of teams changed """ num_changed = 0 num_added = 0 num_deleted = 0 modified = [] try: command_user = self.facade.retrieve(User, user_id) if not check_permissions(command_user, None): return self.permission_error, 200 local_teams: List[Team] = self.facade.query(Team) remote_teams: List[Team] = self.gh.org_get_teams() local_team_dict = dict( (team.github_team_id, team) for team in local_teams) remote_team_dict = dict( (team.github_team_id, team) for team in remote_teams) # remove teams not in github anymore for local_id in local_team_dict: if local_id not in remote_team_dict: self.facade.delete(Team, local_id) num_deleted += 1 modified.append(local_team_dict[local_id].get_attachment()) # add teams to db that are in github but not in local database for remote_id in remote_team_dict: if remote_id not in local_team_dict: self.facade.store(remote_team_dict[remote_id]) num_added += 1 modified.append( remote_team_dict[remote_id].get_attachment()) else: # and finally, if a local team differs, update it old_team = local_team_dict[remote_id] new_team = remote_team_dict[remote_id] if old_team.github_team_name != new_team.github_team_name\ or old_team.members != new_team.members: # update the old team, to retain additional parameters old_team.github_team_name = new_team.github_team_name old_team.members = new_team.members self.facade.store(old_team) num_changed += 1 modified.append(old_team.get_attachment()) # add all members (if not already added) to the 'all' team self.refresh_all_team() # promote members inside special teams self.refresh_all_rocket_permissions() # enforce Drive permissions self.refresh_all_drive_permissions() except GithubAPIException as e: logging.error("team refresh unsuccessful due to github error") return "Refresh teams was unsuccessful with " \ f"the following error: {e.data}", 200 except LookupError: logging.error("team refresh unsuccessful due to lookup error") return self.lookup_error, 200 status = f"{num_changed} teams changed, " \ f"{num_added} added, " \ f"{num_deleted} deleted. Wonderful." ret = {'attachments': modified, 'text': status} return ret, 200
def remove_helper(self, param_list, user_id) -> ResponseTuple: """ Remove specified user from a team. If the user is also a team lead, removes team lead status from Team. If user is not admin or team lead of specified team, user will not be removed and an error message is returned. :param param_list: List of parameters for removing user :param user_id: Slack ID of user who called command :return: error message if user removed unsuccessfully, if user is not in team, or if user has insufficient permission level, otherwise returns success message """ try: command_user = self.facade.retrieve(User, user_id) command_team = param_list['team_name'] team = get_team_by_name(self.facade, command_team) if not check_permissions(command_user, team): return self.permission_error, 200 user = self.facade.retrieve(User, param_list['username']) if not self.gh.has_team_member(user.github_username, team.github_team_id): return "User not in team!", 200 team.discard_member(user.github_id) if team.has_team_lead(user.github_id): team.discard_team_lead(user.github_id) self.gh.remove_team_member(user.github_username, team.github_team_id) self.facade.store(team) msg = "Removed User from " + command_team # If the user is being removed from a team with special # permisisons, figure out a demotion strategy. demoted_level = None if command_team == self.config.github_team_leads: # If the user is currently an admin, we only demote this user # if it is currently NOT and admin team member if user.permissions_level == Permissions.admin \ and len(self.config.github_team_admin) > 0: admins = get_team_by_name(self.facade, self.config.github_team_admin) if not admins.has_member(user.github_id): demoted_level = Permissions.member else: demoted_level = Permissions.member if command_team == self.config.github_team_admin: # If the user is being removed from the admin team, we demote # this user to team_lead if this user is a member of the leads # team, otherwise we demote to member. demoted_level = Permissions.member if len(self.config.github_team_leads) > 0: leads = get_team_by_name(self.facade, self.config.github_team_leads) if leads.has_member(user.github_id): demoted_level = Permissions.team_lead if demoted_level is not None: logging.info(f"Demoting {command_user} to member") user.permissions_level = demoted_level self.facade.store(user) msg += " and demoted user" ret = {'attachments': [team.get_attachment()], 'text': msg} return ret, 200 except LookupError: return self.lookup_error, 200 except GithubAPIException as e: logging.error("user removed unsuccessfully from team") return f"User removed unsuccessfully with " \ f"the following error: {e.data}", 200
def team_refresh(self, caller_id: str) -> bool: """ Ensure that the local team database is the same as Github's. In the event that our local team database is outdated compared to the teams on Github, this command can be called to fix things. :param caller_id: Slack ID of the user calling the command :raises: LookupError if the calling user cannot be found :raises: PermissionError if the calling user has insufficient permissions to refresh the local database :raises: GithubAPIException if there was a failure in fetching Github team information :returns: True if synchronization was successful, False otherwise """ logging.info("Team refresh command API called") num_changed = 0 num_added = 0 num_deleted = 0 command_user = self._db_facade.retrieve(User, caller_id) logging.debug(f"Calling user: {command_user.__str__()}") if not check_permissions(command_user, None): msg = f"User with ID {caller_id} has insufficient permissions" \ " to refresh the local team database" logging.error(msg) raise PermissionError(msg) local_teams: List[Team] = self._db_facade.query(Team) remote_teams: List[Team] = self._gh_interface.org_get_teams() local_team_dict = dict( (team.github_team_id, team) for team in local_teams) remote_team_dict = dict( (team.github_team_id, team) for team in remote_teams) # remove teams not in github anymore for local_id in local_team_dict: if local_id not in remote_team_dict: self._db_facade.delete(Team, local_id) logging.debug(f"Team with Github ID {local_id} deleted") num_deleted += 1 # add teams to db that are in github but not in local database for remote_id in remote_team_dict: remote_team = remote_team_dict[remote_id] if remote_id not in local_team_dict: stored = self._db_facade.store(remote_team) if stored: logging.debug("Created new team with " f"Github ID {remote_id}") num_added += 1 else: logging.error("Failed to create new team with " f"Github ID {remote_id}") return False else: # and finally, if a local team differs, update it local_team = local_team_dict[remote_id] if local_team.github_team_name != \ remote_team.github_team_name \ or local_team.members != remote_team.members: # update the old team, to retain additional parameters local_team.github_team_name = remote_team.github_team_name local_team.members = remote_team.members edited = self._db_facade.store(local_team) if edited: logging.debug("Successfully edited team with " f"Github ID {remote_id}") num_changed += 1 else: logging.error("Failed to edit team with" f"Github ID {remote_id}") return False logging.info(f"{num_changed} teams changed, {num_added} added, " f"{num_deleted} deleted. Wonderful.") return True
def create_helper(self, args: Namespace, user_id: str) -> ResponseTuple: """ Create team and calls GitHub API to create the team in GitHub. If ``args.displayname is not None``, will add a display name. If ``args.channel is not None``, will add all members of channel in which the command was called into the team. :param args: Parameters for creating team :param user_id: Slack ID of user who called command :return: error message if team created unsuccessfully otherwise returns success message """ try: command_user = self.facade.retrieve(User, user_id) if not check_permissions(command_user, None): return self.permission_error, 200 if not command_user.github_id: msg = f"User {command_user.slack_id} has yet to register a"\ f" Github username in this system."\ f" Register with `/rocket user edit --github username`." logging.error(msg) return msg, 200 msg = f"New team created: {args.team_name}, " team_id = str(self.gh.org_create_team(args.team_name)) team = Team(team_id, args.team_name, "") if args.displayname is not None: msg += f"displayname: {args.displayname}, " team.displayname = args.displayname if args.platform is not None: msg += f"platform: {args.platform}, " team.platform = args.platform if args.folder is not None: msg += f"folder: {args.folder}" team.folder = args.folder if args.channel is not None: msg += "added channel" channel_users = self.sc.get_channel_users( args.channel) users_no_ghid = [] for member_id in channel_users: try: member = self.facade.retrieve(User, member_id) if not member.github_username: users_no_ghid.append(member_id) continue self.gh.add_team_member(member.github_username, team_id) team.add_member(member.github_id) except (LookupError, GithubAPIException): users_no_ghid.append(member_id) if users_no_ghid: users_escaped = ' '.join( [f'<@{uid}>' for uid in users_no_ghid]) no_gh_reminder =\ ' (users who forgot to set Github accounts or forgot '\ 'to register into database: ' +\ users_escaped + ')' msg += no_gh_reminder msg += ', ' else: self.gh.add_team_member(command_user.github_username, team_id) team.add_member(command_user.github_id) if args.lead is not None: msg += "added lead" lead_user = self.facade.retrieve(User, args.lead) team.add_team_lead(lead_user.github_id) if not self.gh.has_team_member(lead_user.github_username, team_id): self.gh.add_team_member(lead_user.github_username, team_id) else: team.add_team_lead(command_user.github_id) self.facade.store(team) return msg, 200 except GithubAPIException as e: logging.error(f"Team creation error with {e.data}") return f"Team creation unsuccessful with the" \ f" following error: {e.data}", 200 except LookupError: logging.error(f"User(uid={user_id}) isn't in database") return self.lookup_error, 200 except SlackAPIError as e: logging.error(f"Slack error with {e.error}") return f"Team creation unsuccessful with the" \ f" following error: {e.error}", 200
def test_check_credentials_admin(self): """Test checking to see if user is admin.""" user = User("USFAS689") user.permissions_level = Permissions.admin self.assertTrue(util.check_permissions(user, None))
def test_check_credentials_not_admin(self): """Test checking to see if user is not admin.""" user = User("USFAS689") user.permissions_level = Permissions.member self.assertFalse(util.check_permissions(user, None))
def team_create(self, caller_id: str, gh_team_name: str, display_name: str = None, platform: str = None, channel: str = None, lead_id: str = None) -> bool: """ Create a team both in the Rocket database and Github organization. :param caller_id: Slack ID of the user who is calling the API :param gh_team_name: desired team name to give the team on Github :param display_name: display name to give the team when displayed in various places :param platform: main platform this team's projects are based on :param channel: name of the Slack channel whose channel members are to be added to the team - its members will be added to the team in the Rocket database and added to the Github team as well :param lead_id: Slack ID of the user who will be made the lead of this team :raises: LookupError if the calling user or tech lead cannot be found in the database :raises: PermissionError if the calling user has insufficient permissions to create a team, or if the specified user with lead_id does not have the permission to be a lead :raises: SlackAPIError if a channel name is provided by an error is encountered retrieving the members of that channel :raises: GithubAPIException if an error occurs on team creation or Github team member addition :raises: Exception for any other generic error :return: True if the team creation was successful, False otherwise """ logging.info("Team create command API called") command_user = self._db_facade.retrieve(User, caller_id) logging.debug(f"Calling user: {command_user.__str__()}") if not check_permissions(command_user, None): msg = f"Calling user with Slack ID {caller_id} has permission" \ f" level {str(command_user.permissions_level)}, " \ "insufficient for creating a team!" logging.error(msg) raise PermissionError(msg) if not command_user.github_id: msg = f"User {command_user.slack_id} has yet to register a"\ f" Github username in this system."\ f" Register with `/rocket user edit --github username`." logging.error(msg) raise Exception(msg) gh_team_id = str(self._gh_interface.org_create_team(gh_team_name)) logging.debug(f"Github team {gh_team_name} created with " f"Github team ID {gh_team_id}") team = Team(gh_team_id, gh_team_name, "") if display_name is not None: logging.debug(f"Attaching display name {display_name} " f"to {gh_team_name}") team.display_name = display_name if platform is not None: logging.debug(f"Attaching platform {platform} to {gh_team_name}") team.platform = platform if channel is not None: logging.debug(f"Adding channel members of #{channel} " f"to {gh_team_name}") try: channel_member_ids = \ self._slack_client.get_channel_users(channel) logging.debug(f"Member IDs of members found in #{channel}: " f"{channel_member_ids}") except SlackAPIError as e: msg = f"Channel member query on channel #{channel} failed: " \ f"{e.error}" logging.error(msg) raise SlackAPIError(msg) channel_members = \ self._db_facade.bulk_retrieve(User, list(channel_member_ids.keys())) if len(channel_members) is not len(channel_member_ids): retrieved_members_ids = [ member.slack_id for member in channel_members ] unaccounted_member_ids = [ member_id for member_id in channel_member_ids if member_id not in retrieved_members_ids ] logging.warning("Users not found for following Slack IDs: " f"{unaccounted_member_ids}") for member in channel_members: self._gh_interface.add_team_member(member.github_username, gh_team_id) team.add_member(member.github_id) logging.debug(f"Member with ID {member.slack_id} added " f"to {gh_team_name}") else: self._gh_interface.add_team_member(command_user.github_username, gh_team_id) team.add_member(command_user.github_id) logging.debug(f"Calling user with ID {command_user.slack_id} " f"added to {gh_team_name}") if lead_id is not None: lead = self._db_facade.retrieve(User, lead_id) if check_permissions(lead, None): lead_in_team = self._gh_interface.has_team_member( lead.github_username, gh_team_id) if not lead_in_team: self._gh_interface.add_team_member(lead.github_username, gh_team_id) team.add_member(lead.github_id) team.add_team_lead(lead.github_id) logging.debug(f"User with ID {lead_id} set as tech lead of " f"{gh_team_name}") else: msg = f"User specified with lead ID {lead_id} has" \ f" permission level {str(lead.permissions_level)}, " \ "insufficient to lead a team!" logging.error(msg) raise PermissionError(msg) else: team.add_team_lead(command_user.github_id) logging.debug(f"Calling user with ID {command_user.github_id} set" f" as tech lead of {gh_team_name}") created = self._db_facade.store(team) return created
def create_helper(self, param_list, user_id) -> ResponseTuple: """ Create team and calls GitHub API to create the team in GitHub. If ``param_list[name] is not None``, will add a display name. If ``param_list[channel] is not None``, will add all members of channel in which the command was called into the team. :param param_list: List of parameters for creating team :param user_id: Slack ID of user who called command :return: error message if team created unsuccessfully otherwise returns success message """ try: command_user = self.facade.retrieve(User, user_id) if not check_permissions(command_user, None): return self.permission_error, 200 if not command_user.github_id: msg = f"User {command_user.slack_id} has yet to register a"\ f" Github username in this system."\ f" Register with `/rocket user edit --github username`." logging.error(msg) return msg, 200 msg = f"New team created: {param_list['team_name']}, " team_id = str(self.gh.org_create_team(param_list['team_name'])) team = Team(team_id, param_list['team_name'], "") if param_list["name"] is not None: msg += f"name: {param_list['name']}, " team.display_name = param_list['name'] if param_list["platform"] is not None: msg += f"platform: {param_list['platform']}, " team.platform = param_list['platform'] if param_list["folder"] is not None: msg += f"folder: {param_list['folder']}" team.folder = param_list['folder'] if param_list["channel"] is not None: msg += "added channel, " for member_id in self.sc.get_channel_users( param_list["channel"]): try: member = self.facade.retrieve(User, member_id) self.gh.add_team_member(member.github_username, team_id) team.add_member(member.github_id) except LookupError: pass else: self.gh.add_team_member(command_user.github_username, team_id) team.add_member(command_user.github_id) if param_list["lead"] is not None: msg += "added lead" lead_user = self.facade.retrieve(User, param_list["lead"]) team.add_team_lead(lead_user.github_id) if not self.gh.has_team_member(lead_user.github_username, team_id): self.gh.add_team_member(lead_user.github_username, team_id) else: team.add_team_lead(command_user.github_id) self.facade.store(team) return msg, 200 except GithubAPIException as e: logging.error(f"Team creation error with {e.data}") return f"Team creation unsuccessful with the" \ f" following error: {e.data}", 200 except LookupError: logging.error(f"User(uid={user_id}) isn't in database") return self.lookup_error, 200 except SlackAPIError as e: logging.error(f"Slack error with {e.error}") return f"Team creation unsuccessful with the" \ f" following error: {e.error}", 200