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()
def create_repository( namespace, name, creating_user, visibility="private", repo_kind="image", description=None ): namespace_user = User.get(username=namespace) yesterday = datetime.now() - timedelta(days=1) with db_transaction(): repo = Repository.create( name=name, visibility=Repository.visibility.get_id(visibility), namespace_user=namespace_user, kind=Repository.kind.get_id(repo_kind), description=description, ) RepositoryActionCount.create(repository=repo, count=0, date=yesterday) RepositorySearchScore.create(repository=repo, score=0) # Note: We put the admin create permission under the transaction to ensure it is created. if creating_user and not creating_user.organization: admin = Role.get(name="admin") RepositoryPermission.create(user=creating_user, repository=repo, role=admin) # Apply default permissions (only occurs for repositories under organizations) if creating_user and not creating_user.organization and creating_user.username != namespace: permission.apply_default_permissions(repo, creating_user) return repo
def create_repository(namespace, name, creating_user, visibility="private", repo_kind="image", description=None): namespace_user = User.get(username=namespace) yesterday = datetime.now() - timedelta(days=1) try: with db_transaction(): # Check if the repository exists to avoid an IntegrityError if possible. existing = get_repository(namespace, name) if existing is not None: return None try: repo = Repository.create( name=name, visibility=Repository.visibility.get_id(visibility), namespace_user=namespace_user, kind=Repository.kind.get_id(repo_kind), description=description, ) except IntegrityError as ie: raise _RepositoryExistsException(ie) RepositoryActionCount.create(repository=repo, count=0, date=yesterday) RepositorySearchScore.create(repository=repo, score=0) # Note: We put the admin create permission under the transaction to ensure it is created. if creating_user and not creating_user.organization: admin = Role.get(name="admin") RepositoryPermission.create(user=creating_user, repository=repo, role=admin) except _RepositoryExistsException as ree: try: return Repository.get(namespace_user=namespace_user, name=name) except Repository.DoesNotExist: logger.error( "Got integrity error when trying to create repository %s/%s: %s", namespace, name, ree.internal_exception, ) return None # Apply default permissions (only occurs for repositories under organizations) if creating_user and not creating_user.organization and creating_user.username != namespace: permission.apply_default_permissions(repo, creating_user) return repo
def ensure_admin(user, repos, dry_run=False): repos = [repo for repo in repos if not has_admin(user, repo)] for repo in repos: print("User {} missing admin on: {}".format(user.username, repo.name)) if not dry_run: RepositoryPermission.create(user=user, repository=repo, role=ADMIN) print("Granted {} admin on: {}".format(user.username, repo.name)) return len(repos)
def convert_user_to_organization(user_obj, admin_user): if user_obj.robot: raise DataModelException("Cannot convert a robot into an organization") with db_transaction(): # Change the user to an organization and disable this account for login. user_obj.organization = True user_obj.password_hash = None user_obj.save() # Clear any federated auth pointing to this user. FederatedLogin.delete().where( FederatedLogin.user == user_obj).execute() # Delete any user-specific permissions on repositories. (RepositoryPermission.delete().where( RepositoryPermission.user == user_obj).execute()) # Create a team for the owners owners_team = team.create_team("owners", user_obj, "admin") # Add the user who will admin the org to the owners team team.add_user_to_team(admin_user, owners_team) return user_obj
def _get_user_repo_permissions(user, limit_to_repository_obj=None, limit_namespace=None, limit_repo_name=None): UserThroughTeam = User.alias() base_query = (RepositoryPermission.select( RepositoryPermission, Role, Repository, Namespace).join(Role).switch(RepositoryPermission).join( Repository).join(Namespace, on=(Repository.namespace_user == Namespace.id )).switch(RepositoryPermission)) if limit_to_repository_obj is not None: base_query = base_query.where( RepositoryPermission.repository == limit_to_repository_obj) elif limit_namespace and limit_repo_name: base_query = base_query.where(Repository.name == limit_repo_name, Namespace.username == limit_namespace) direct = base_query.clone().join(User).where(User.id == user) team = (base_query.clone().join(Team).join(TeamMember).join( UserThroughTeam, on=(UserThroughTeam.id == TeamMember.user)).where( UserThroughTeam.id == user)) return direct | team
def __set_entity_repo_permission(entity, permission_entity_property, namespace_name, repository_name, role_name): repo = _basequery.get_existing_repository(namespace_name, repository_name) new_role = Role.get(Role.name == role_name) # Fetch any existing permission for this entity on the repo try: entity_attr = getattr(RepositoryPermission, permission_entity_property) perm = RepositoryPermission.get(entity_attr == entity, RepositoryPermission.repository == repo) perm.role = new_role perm.save() return perm except RepositoryPermission.DoesNotExist: set_entity_kwargs = {permission_entity_property: entity} new_perm = RepositoryPermission.create(repository=repo, role=new_role, **set_entity_kwargs) return new_perm
def get_all_repo_users(namespace_name, repository_name): return (RepositoryPermission.select( User, Role, RepositoryPermission).join(User).switch(RepositoryPermission).join( Role).switch(RepositoryPermission).join(Repository).join( Namespace, on=(Repository.namespace_user == Namespace.id)).where( Namespace.username == namespace_name, Repository.name == repository_name))
def _get_visible_repositories_for_user(user, repo_kind="image", include_public=False, namespace=None): """ Returns all repositories directly visible to the given user, by either repo permission, or the user being the admin of a namespace. """ for repo in Repository.select(): if repo_kind is not None and repo.kind.name != repo_kind: continue if namespace is not None and repo.namespace_user.username != namespace: continue if include_public and repo.visibility.name == "public": yield repo continue # Direct repo permission. try: RepositoryPermission.get(repository=repo, user=user).get() yield repo continue except RepositoryPermission.DoesNotExist: pass # Team permission. found_in_team = False for perm in RepositoryPermission.select().where( RepositoryPermission.repository == repo): if perm.team and _is_team_member(perm.team, user): found_in_team = True break if found_in_team: yield repo continue # Org namespace admin permission. if user in get_admin_users(repo.namespace_user): yield repo continue
def list_organization_member_permissions(organization, limit_to_user=None): query = (RepositoryPermission.select( RepositoryPermission, Repository, User).join(Repository).switch(RepositoryPermission).join(User).where( Repository.namespace_user == organization)) if limit_to_user is not None: query = query.where(RepositoryPermission.user == limit_to_user) else: query = query.where(User.robot == False) return query
def __entity_permission_repo_query(entity_id, entity_table, entity_id_property, namespace_name, repository_name): """ This method works for both users and teams. """ return (RepositoryPermission.select( entity_table, Repository, Namespace, Role, RepositoryPermission).join(entity_table).switch(RepositoryPermission). join(Role).switch(RepositoryPermission).join(Repository).join( Namespace, on=(Repository.namespace_user == Namespace.id)).where( Repository.name == repository_name, Namespace.username == namespace_name, entity_id_property == entity_id, ))
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())]
def list_robot_permissions(robot_name): return (RepositoryPermission.select( RepositoryPermission, User, Repository).join(Repository).join(Visibility).switch( RepositoryPermission).join(Role).switch(RepositoryPermission).join( User).where(User.username == robot_name, User.robot == True))
def create_user_permission(user, repo, role): # The creating user always gets admin anyway if user.username == creating_user_obj.username: return RepositoryPermission.create(user=user, repository=repo, role=role)
def create_team_permission(team, repo, role): RepositoryPermission.create(team=team, repository=repo, role=role)
def list_team_permissions(team): return (RepositoryPermission.select(RepositoryPermission).join(Repository). join(Visibility).switch(RepositoryPermission).join(Role).switch( RepositoryPermission).where(RepositoryPermission.team == team))