Beispiel #1
0
def remove_organization_member(org, user_obj):
    org_admins = [u.username for u in __get_org_admin_users(org)]
    if len(org_admins) == 1 and user_obj.username in org_admins:
        raise DataModelException(
            "Cannot remove user as they are the only organization admin")

    with db_transaction():
        # Find and remove the user from any repositories under the org.
        permissions = list(
            RepositoryPermission.select(
                RepositoryPermission.id).join(Repository).where(
                    Repository.namespace_user == org,
                    RepositoryPermission.user == user_obj))

        if permissions:
            RepositoryPermission.delete().where(
                RepositoryPermission.id << permissions).execute()

        # Find and remove the user from any teams under the org.
        members = list(
            TeamMember.select(TeamMember.id).join(Team).where(
                Team.organization == org, TeamMember.user == user_obj))

        if members:
            TeamMember.delete().where(TeamMember.id << members).execute()
Beispiel #2
0
def _delete_user_linked_data(user):
  if user.organization:
    # Delete the organization's teams.
    with db_transaction():
      for team in Team.select().where(Team.organization == user):
        team.delete_instance(recursive=True)

    # Delete any OAuth approvals and tokens associated with the user.
    with db_transaction():
      for app in OAuthApplication.select().where(OAuthApplication.organization == user):
        app.delete_instance(recursive=True)
  else:
    # Remove the user from any teams in which they are a member.
    TeamMember.delete().where(TeamMember.user == user).execute()

  # Delete any repository buildtriggers where the user is the connected user.
  with db_transaction():
    triggers = RepositoryBuildTrigger.select().where(RepositoryBuildTrigger.connected_user == user)
    for trigger in triggers:
      trigger.delete_instance(recursive=True, delete_nullable=False)

  # Delete any mirrors with robots owned by this user.
  with db_transaction():
    robots = list(list_namespace_robots(user.username))
    RepoMirrorConfig.delete().where(RepoMirrorConfig.internal_robot << robots).execute()

  # Delete any robots owned by this user.
  with db_transaction():
    robots = list(list_namespace_robots(user.username))
    for robot in robots:
      robot.delete_instance(recursive=True, delete_nullable=True)

  # Null out any service key approvals. We technically lose information here, but its better than
  # falling and only occurs if a superuser is being deleted.
  ServiceKeyApproval.update(approver=None).where(ServiceKeyApproval.approver == user).execute()
Beispiel #3
0
def get_solely_admined_organizations(user_obj):
    """ Returns the organizations admined solely by the given user. """
    orgs = (
        User.select()
        .where(User.organization == True)
        .join(Team)
        .join(TeamRole)
        .where(TeamRole.name == "admin")
        .switch(Team)
        .join(TeamMember)
        .where(TeamMember.user == user_obj)
        .distinct()
    )

    # Filter to organizations where the user is the sole admin.
    solely_admined = []
    for org in orgs:
        admin_user_count = (
            TeamMember.select()
            .join(Team)
            .join(TeamRole)
            .where(Team.organization == org, TeamRole.name == "admin")
            .switch(TeamMember)
            .join(User)
            .where(User.robot == False)
            .distinct()
            .count()
        )

        if admin_user_count == 1:
            solely_admined.append(org)

    return solely_admined
Beispiel #4
0
def add_or_invite_to_team(inviter,
                          team,
                          user_obj=None,
                          email=None,
                          requires_invite=True):
    # If the user is a member of the organization, then we simply add the
    # user directly to the team. Otherwise, an invite is created for the user/email.
    # We return None if the user was directly added and the invite object if the user was invited.
    if user_obj and requires_invite:
        orgname = team.organization.username

        # If the user is part of the organization (or a robot), then no invite is required.
        if user_obj.robot:
            requires_invite = False
            if not user_obj.username.startswith(orgname + "+"):
                raise InvalidTeamMemberException(
                    "Cannot add the specified robot to this team, " +
                    "as it is not a member of the organization")
        else:
            query = (TeamMember.select().where(
                TeamMember.user == user_obj).join(Team).join(User).where(
                    User.username == orgname, User.organization == True))
            requires_invite = not any(query)

    # If we have a valid user and no invite is required, simply add the user to the team.
    if user_obj and not requires_invite:
        add_user_to_team(user_obj, team)
        return None

    email_address = email if not user_obj else None
    return TeamMemberInvite.create(user=user_obj,
                                   email=email_address,
                                   team=team,
                                   inviter=inviter)
Beispiel #5
0
def filter_to_repos_for_user(query,
                             user_id=None,
                             namespace=None,
                             repo_kind="image",
                             include_public=True,
                             start_id=None):
    if not include_public and not user_id:
        return Repository.select().where(Repository.id == "-1")

    # Filter on the type of repository.
    if repo_kind is not None:
        try:
            query = query.where(
                Repository.kind == Repository.kind.get_id(repo_kind))
        except RepositoryKind.DoesNotExist:
            raise DataModelException("Unknown repository kind")

    # Add the start ID if necessary.
    if start_id is not None:
        query = query.where(Repository.id >= start_id)

    # Add a namespace filter if necessary.
    if namespace:
        query = query.where(Namespace.username == namespace)

    # Build a set of queries that, when unioned together, return the full set of visible repositories
    # for the filters specified.
    queries = []

    if include_public:
        queries.append(
            query.where(Repository.visibility == get_public_repo_visibility()))

    if user_id is not None:
        AdminTeam = Team.alias()
        AdminTeamMember = TeamMember.alias()

        # Add repositories in which the user has permission.
        queries.append(
            query.switch(RepositoryPermission).where(
                RepositoryPermission.user == user_id))

        # Add repositories in which the user is a member of a team that has permission.
        queries.append(
            query.switch(RepositoryPermission).join(Team).join(
                TeamMember).where(TeamMember.user == user_id))

        # Add repositories under namespaces in which the user is the org admin.
        queries.append(
            query.switch(Repository).join(
                AdminTeam,
                on=(Repository.namespace_user == AdminTeam.organization)).join(
                    AdminTeamMember,
                    on=(AdminTeam.id == AdminTeamMember.team)).where(
                        AdminTeam.role == _lookup_team_role("admin")).where(
                            AdminTeamMember.user == user_id))

    return reduce(lambda l, r: l | r, queries)
Beispiel #6
0
def list_notifications(user,
                       kind_name=None,
                       id_filter=None,
                       include_dismissed=False,
                       page=None,
                       limit=None):

    base_query = Notification.select(
        Notification.id,
        Notification.uuid,
        Notification.kind,
        Notification.metadata_json,
        Notification.dismissed,
        Notification.lookup_path,
        Notification.created,
        Notification.created.alias("cd"),
        Notification.target,
    ).join(NotificationKind)

    if kind_name is not None:
        base_query = base_query.where(NotificationKind.name == kind_name)

    if id_filter is not None:
        base_query = base_query.where(Notification.uuid == id_filter)

    if not include_dismissed:
        base_query = base_query.where(Notification.dismissed == False)

    # Lookup directly for the user.
    user_direct = base_query.clone().where(Notification.target == user)

    # Lookup via organizations admined by the user.
    Org = User.alias()
    AdminTeam = Team.alias()
    AdminTeamMember = TeamMember.alias()
    AdminUser = User.alias()

    via_orgs = (base_query.clone().join(
        Org, on=(Org.id == Notification.target)).join(
            AdminTeam, on=(Org.id == AdminTeam.organization)).join(
                TeamRole,
                on=(AdminTeam.role == TeamRole.id)).switch(AdminTeam).join(
                    AdminTeamMember,
                    on=(AdminTeam.id == AdminTeamMember.team)).join(
                        AdminUser, on=(AdminTeamMember.user == AdminUser.id
                                       )).where((AdminUser.id == user)
                                                & (TeamRole.name == "admin")))

    query = user_direct | via_orgs

    if page:
        query = query.paginate(page, limit)
    elif limit:
        query = query.limit(limit)

    return query.order_by(SQL("cd desc"))
Beispiel #7
0
def delete_members_not_present(team, member_id_set):
    """ Deletes all members of the given team that are not found in the member ID set. """
    with db_transaction():
        user_ids = set([u.id for u in list_team_users(team)])
        to_delete = list(user_ids - member_id_set)
        if to_delete:
            query = TeamMember.delete().where(TeamMember.team == team,
                                              TeamMember.user << to_delete)
            return query.execute()

    return 0
Beispiel #8
0
def get_teams_within_org(organization, has_external_auth=False):
    """
    Returns a AttrDict of team info (id, name, description), its role under the org, the number of
    repositories on which it has permission, and the number of members.
    """
    query = Team.select().where(
        Team.organization == organization).join(TeamRole)

    def _team_view(team):
        return {
            "id": team.id,
            "name": team.name,
            "description": team.description,
            "role_name": Team.role.get_name(team.role_id),
            "repo_count": 0,
            "member_count": 0,
            "is_synced": False,
        }

    teams = {team.id: _team_view(team) for team in query}
    if not teams:
        # Just in case. Should ideally never happen.
        return []

    # Add repository permissions count.
    permission_tuples = (RepositoryPermission.select(
        RepositoryPermission.team, fn.Count(RepositoryPermission.id)).where(
            RepositoryPermission.team << list(teams.keys())).group_by(
                RepositoryPermission.team).tuples())

    for perm_tuple in permission_tuples:
        teams[perm_tuple[0]]["repo_count"] = perm_tuple[1]

    # Add the member count.
    members_tuples = (TeamMember.select(TeamMember.team, fn.Count(
        TeamMember.id)).where(TeamMember.team << list(teams.keys())).group_by(
            TeamMember.team).tuples())

    for member_tuple in members_tuples:
        teams[member_tuple[0]]["member_count"] = member_tuple[1]

    # Add syncing information.
    if has_external_auth:
        sync_query = TeamSync.select(
            TeamSync.team).where(TeamSync.team << list(teams.keys()))
        for team_sync in sync_query:
            teams[team_sync.team_id]["is_synced"] = True

    return [AttrDict(team_info) for team_info in list(teams.values())]
Beispiel #9
0
def _user_teams(user, resource):
    changed = False
    p_exact_teams = resource["exact_teams"]
    p_add_teams = resource["add_teams"]
    p_remove_teams = resource["remove_teams"]

    team_names = p_exact_teams or p_add_teams or p_remove_teams
    if team_names is None:
        return False

    teams = []
    for name in team_names:
        try:
            teams.append(Team.get(Team.name == name))
        except model.InvalidTeamException:
            abort(400, message="Team '%s' does not exist" % name)
    teams = set(teams)

    current_teams = set(Team.select().join(TeamMember).join(User)).where(
        User.username == user.username)

    teams_to_add = teams - current_teams
    teams_to_remove = current_teams - teams
    if p_add_teams:
        teams_to_remove = []
    elif p_remove_teams:
        teams_to_add = []

    for team in teams_to_add:
        changed = True
        model.team.add_user_to_team(user, team)

    query = TeamMember.select().join(User).switch(TeamMember).join(Team).join(
        TeamRole)
    for team in teams_to_remove:
        changed = True
        found = list(
            query.where(User.username == user.username,
                        Team.name == team.name))
        found[0].delete_instance()

    return changed
Beispiel #10
0
def remove_user_from_team(org_name, team_name, username, removed_by_username):
    Org = User.alias()
    joined = TeamMember.select().join(User).switch(TeamMember).join(Team)
    with_role = joined.join(TeamRole)
    with_org = with_role.switch(Team).join(Org,
                                           on=(Org.id == Team.organization))
    found = list(
        with_org.where(User.username == username, Org.username == org_name,
                       Team.name == team_name))

    if not found:
        raise DataModelException("User %s does not belong to team %s" %
                                 (username, team_name))

    if username == removed_by_username:
        admin_team_query = __get_user_admin_teams(org_name, username)
        admin_team_names = {team.name for team in admin_team_query}
        if team_name in admin_team_names and len(admin_team_names) <= 1:
            msg = "User cannot remove themselves from their only admin team."
            raise DataModelException(msg)

    user_in_team = found[0]
    user_in_team.delete_instance()
Beispiel #11
0
def _is_team_member(team, user):
    return user.id in [
        member.user_id
        for member in TeamMember.select().where(TeamMember.team == team)
    ]
Beispiel #12
0
def add_user_to_team(user_obj, team):
    try:
        return TeamMember.create(user=user_obj, team=team)
    except Exception:
        raise UserAlreadyInTeam("User %s is already a member of team %s" %
                                (user_obj.username, team.name))
Beispiel #13
0
def list_organization_members_by_teams(organization):
    query = (TeamMember.select(
        Team, User).join(Team).switch(TeamMember).join(User).where(
            Team.organization == organization))
    return query
Beispiel #14
0

def fix_ident(ident):
    return str(ident).translate(None, "-/.")


with open("outfile.dot", "w") as outfile:
    outfile.write("digraph relationships {\n")

    for repo in Repository.select():
        ns = fix_ident(repo.namespace_user.username)
        outfile.write("%s_%s -> %s\n" % (ns, fix_ident(repo.name), ns))

    teams_in_orgs = set()

    for member in TeamMember.select():
        if "+" in member.user.username:
            continue

        org_name = fix_ident(member.team.organization.username)

        team_to_org = (member.team.name, member.team.organization.username)
        if not team_to_org in teams_in_orgs:
            teams_in_orgs.add(team_to_org)
            outfile.write("%s_%s -> %s\n" %
                          (org_name, fix_ident(member.team.name), org_name))

        team_name = fix_ident(member.team.name)

        outfile.write("%s -> %s_%s\n" %
                      (fix_ident(member.user.username), org_name, team_name))