Change repo filtering for users to use a user ID reference, rather than the username
While this means we need an additional query for initial lookup, it makes the *filtering* query (which is the heavy part) require far fewer joins, thus making it more efficient. Also adds a new unit test to verify that our filter filters to the correct set of repositories.
This commit is contained in:
parent
f2b9aa4527
commit
7604e9842b
7 changed files with 158 additions and 34 deletions
|
@ -403,11 +403,17 @@ def get_visible_repositories(username, namespace=None, kind_filter='image', incl
|
|||
Namespace.username, Repository.visibility, Repository.kind)
|
||||
.switch(Repository).join(Namespace, on=(Repository.namespace_user == Namespace.id)))
|
||||
|
||||
user_id = None
|
||||
if username:
|
||||
# Note: We only need the permissions table if we will filter based on a user's permissions.
|
||||
query = query.switch(Repository).distinct().join(RepositoryPermission, JOIN_LEFT_OUTER)
|
||||
found_namespace = _get_namespace_user(username)
|
||||
if not found_namespace:
|
||||
return Repository.select(Repository.id.alias('rid')).where(Repository.id == -1)
|
||||
|
||||
query = _basequery.filter_to_repos_for_user(query, username, namespace, kind_filter,
|
||||
user_id = found_namespace.id
|
||||
|
||||
query = _basequery.filter_to_repos_for_user(query, user_id, namespace, kind_filter,
|
||||
include_public, start_id=start_id)
|
||||
|
||||
if limit is not None:
|
||||
|
@ -434,6 +440,13 @@ def get_app_search(lookup, search_fields=None, username=None, limit=50):
|
|||
offset=0, limit=limit)
|
||||
|
||||
|
||||
def _get_namespace_user(username):
|
||||
try:
|
||||
return User.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def get_filtered_matching_repositories(lookup_value, filter_username=None, repo_kind='image',
|
||||
offset=0, limit=25, search_fields=None):
|
||||
""" Returns an iterator of all repositories matching the given lookup value, with optional
|
||||
|
@ -451,8 +464,12 @@ def get_filtered_matching_repositories(lookup_value, filter_username=None, repo_
|
|||
|
||||
# Add a filter to the iterator, if necessary.
|
||||
if filter_username is not None:
|
||||
iterator = _filter_repositories_visible_to_username(unfiltered_query, filter_username, limit,
|
||||
repo_kind)
|
||||
filter_user = _get_namespace_user(filter_username)
|
||||
if filter_user is None:
|
||||
return []
|
||||
|
||||
iterator = _filter_repositories_visible_to_user(unfiltered_query, filter_user.id, limit,
|
||||
repo_kind)
|
||||
if offset > 0:
|
||||
take(offset, iterator)
|
||||
|
||||
|
@ -462,7 +479,7 @@ def get_filtered_matching_repositories(lookup_value, filter_username=None, repo_
|
|||
return list(unfiltered_query.offset(offset).limit(limit))
|
||||
|
||||
|
||||
def _filter_repositories_visible_to_username(unfiltered_query, filter_username, limit, repo_kind):
|
||||
def _filter_repositories_visible_to_user(unfiltered_query, filter_user_id, limit, repo_kind):
|
||||
encountered = set()
|
||||
chunk_count = limit * 2
|
||||
unfiltered_page = 0
|
||||
|
@ -484,11 +501,13 @@ def _filter_repositories_visible_to_username(unfiltered_query, filter_username,
|
|||
encountered.update(new_unfiltered_ids)
|
||||
|
||||
# Filter the repositories found to only those visible to the current user.
|
||||
query = (Repository.select(Repository, Namespace).distinct()
|
||||
query = (Repository
|
||||
.select(Repository, Namespace)
|
||||
.distinct()
|
||||
.join(Namespace, on=(Namespace.id == Repository.namespace_user)).switch(Repository)
|
||||
.join(RepositoryPermission).where(Repository.id << list(new_unfiltered_ids)))
|
||||
|
||||
filtered = _basequery.filter_to_repos_for_user(query, filter_username, repo_kind=repo_kind)
|
||||
filtered = _basequery.filter_to_repos_for_user(query, filter_user_id, repo_kind=repo_kind)
|
||||
|
||||
# Sort the filtered repositories by their initial order.
|
||||
all_filtered_repos = list(filtered)
|
||||
|
|
Reference in a new issue