mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-24 02:04:04 +08:00
Fix SA2.0 usage in managers.folders
This commit is contained in:
@@ -12,10 +12,12 @@ from typing import (
|
||||
|
||||
from sqlalchemy import (
|
||||
and_,
|
||||
exists,
|
||||
false,
|
||||
func,
|
||||
not_,
|
||||
or_,
|
||||
select,
|
||||
)
|
||||
from sqlalchemy.orm import aliased
|
||||
from sqlalchemy.orm.exc import (
|
||||
@@ -36,6 +38,15 @@ from galaxy.exceptions import (
|
||||
MalformedId,
|
||||
RequestParameterInvalidException,
|
||||
)
|
||||
from galaxy.model import (
|
||||
Dataset,
|
||||
DatasetPermissions,
|
||||
LibraryDataset,
|
||||
LibraryDatasetDatasetAssociation,
|
||||
LibraryDatasetPermissions,
|
||||
LibraryFolder,
|
||||
LibraryFolderPermissions,
|
||||
)
|
||||
from galaxy.model.base import transaction
|
||||
from galaxy.model.scoped_session import galaxy_scoped_session
|
||||
from galaxy.schema.fields import LibraryFolderDatabaseIdField
|
||||
@@ -89,11 +100,7 @@ class FolderManager:
|
||||
:raises: InconsistentDatabase, RequestParameterInvalidException, InternalServerError
|
||||
"""
|
||||
try:
|
||||
folder = (
|
||||
trans.sa_session.query(trans.app.model.LibraryFolder)
|
||||
.filter(trans.app.model.LibraryFolder.table.c.id == decoded_folder_id)
|
||||
.one()
|
||||
)
|
||||
folder = get_folder(trans.sa_session, decoded_folder_id)
|
||||
except MultipleResultsFound:
|
||||
raise InconsistentDatabase("Multiple folders found with the same id.")
|
||||
except NoResultFound:
|
||||
@@ -210,7 +217,7 @@ class FolderManager:
|
||||
raise InsufficientPermissionsException(
|
||||
"You do not have proper permission to create folders under given folder."
|
||||
)
|
||||
new_folder = trans.app.model.LibraryFolder(name=new_folder_name, description=new_folder_description)
|
||||
new_folder = LibraryFolder(name=new_folder_name, description=new_folder_description)
|
||||
# We are associating the last used genome build with folders, so we will always
|
||||
# initialize a new folder with the first dbkey in genome builds list which is currently
|
||||
# ? unspecified (?)
|
||||
@@ -386,9 +393,9 @@ class FolderManager:
|
||||
def get_contents(
|
||||
self,
|
||||
trans,
|
||||
folder: model.LibraryFolder,
|
||||
folder: LibraryFolder,
|
||||
payload: LibraryFolderContentsIndexQueryPayload,
|
||||
) -> Tuple[List[Union[model.LibraryFolder, model.LibraryDataset]], int]:
|
||||
) -> Tuple[List[Union[LibraryFolder, LibraryDataset]], int]:
|
||||
"""Retrieves the contents of the given folder that match the provided filters and pagination parameters.
|
||||
Returns a tuple with the list of paginated contents and the total number of items contained in the folder."""
|
||||
limit = payload.limit
|
||||
@@ -400,19 +407,19 @@ class FolderManager:
|
||||
is_admin=trans.user_is_admin,
|
||||
)
|
||||
|
||||
content_items: List[Union[model.LibraryFolder, model.LibraryDataset]] = []
|
||||
sub_folders_query = self._get_sub_folders_query(sa_session, folder, security_params, payload)
|
||||
total_sub_folders: int = sub_folders_query.count()
|
||||
content_items: List[Union[LibraryFolder, LibraryDataset]] = []
|
||||
sub_folders_stmt = self._get_sub_folders_statement(sa_session, folder, security_params, payload)
|
||||
total_sub_folders = get_count(sa_session, sub_folders_stmt)
|
||||
if payload.order_by in FOLDER_SORT_COLUMN_MAP:
|
||||
sort_column = FOLDER_SORT_COLUMN_MAP[payload.order_by](model.LibraryFolder)
|
||||
sub_folders_query = sub_folders_query.order_by(sort_column.desc() if payload.sort_desc else sort_column)
|
||||
sort_column = FOLDER_SORT_COLUMN_MAP[payload.order_by](LibraryFolder)
|
||||
sub_folders_stmt = sub_folders_stmt.order_by(sort_column.desc() if payload.sort_desc else sort_column)
|
||||
else: # Sort by name alphabetically by default
|
||||
sub_folders_query = sub_folders_query.order_by(model.LibraryFolder.name)
|
||||
sub_folders_stmt = sub_folders_stmt.order_by(LibraryFolder.name)
|
||||
if limit is not None and limit > 0:
|
||||
sub_folders_query = sub_folders_query.limit(limit)
|
||||
sub_folders_stmt = sub_folders_stmt.limit(limit)
|
||||
if offset is not None:
|
||||
sub_folders_query = sub_folders_query.offset(offset)
|
||||
folders = sub_folders_query.all()
|
||||
sub_folders_stmt = sub_folders_stmt.offset(offset)
|
||||
folders = sa_session.scalars(sub_folders_stmt).all()
|
||||
content_items.extend(folders)
|
||||
|
||||
# Update pagination
|
||||
@@ -424,77 +431,69 @@ class FolderManager:
|
||||
offset -= num_folders_skipped
|
||||
offset = max(0, offset)
|
||||
|
||||
datasets_query = self._get_contained_datasets_query(sa_session, folder, security_params, payload)
|
||||
total_datasets = datasets_query.count()
|
||||
datasets_stmt = self._get_contained_datasets_statement(sa_session, folder, security_params, payload)
|
||||
total_datasets = get_count(sa_session, datasets_stmt)
|
||||
if limit is not None and limit > 0:
|
||||
datasets_query = datasets_query.limit(limit)
|
||||
datasets_stmt = datasets_stmt.limit(limit)
|
||||
if offset is not None:
|
||||
datasets_query = datasets_query.offset(offset)
|
||||
datasets = datasets_query.all()
|
||||
datasets_stmt = datasets_stmt.offset(offset)
|
||||
datasets = sa_session.scalars(datasets_stmt).all()
|
||||
content_items.extend(datasets)
|
||||
return (content_items, total_sub_folders + total_datasets)
|
||||
|
||||
def _get_sub_folders_query(
|
||||
def _get_sub_folders_statement(
|
||||
self,
|
||||
sa_session: galaxy_scoped_session,
|
||||
folder: model.LibraryFolder,
|
||||
folder: LibraryFolder,
|
||||
security: SecurityParams,
|
||||
payload: LibraryFolderContentsIndexQueryPayload,
|
||||
):
|
||||
"""Builds a query to retrieve all the sub-folders contained in the given folder applying filters."""
|
||||
item_model = model.LibraryFolder
|
||||
item_permission_model = model.LibraryFolderPermissions
|
||||
search_text = payload.search_text
|
||||
query = sa_session.query(item_model)
|
||||
query = query.filter(item_model.parent_id == folder.id)
|
||||
query = self._filter_by_include_deleted(
|
||||
query, item_model, item_permission_model, payload.include_deleted, security
|
||||
stmt = select(LibraryFolder).where(LibraryFolder.parent_id == folder.id)
|
||||
stmt = self._filter_by_include_deleted(
|
||||
stmt, LibraryFolder, LibraryFolderPermissions, payload.include_deleted, security
|
||||
)
|
||||
if search_text:
|
||||
search_text = search_text.lower()
|
||||
query = query.filter(
|
||||
stmt = stmt.where(
|
||||
or_(
|
||||
func.lower(item_model.name).contains(search_text, autoescape=True),
|
||||
func.lower(item_model.description).contains(search_text, autoescape=True),
|
||||
func.lower(LibraryFolder.name).contains(search_text, autoescape=True),
|
||||
func.lower(LibraryFolder.description).contains(search_text, autoescape=True),
|
||||
)
|
||||
)
|
||||
query = query.group_by(item_model.id)
|
||||
return query
|
||||
stmt = stmt.group_by(LibraryFolder.id)
|
||||
return stmt
|
||||
|
||||
def _get_contained_datasets_query(
|
||||
def _get_contained_datasets_statement(
|
||||
self,
|
||||
sa_session: galaxy_scoped_session,
|
||||
folder: model.LibraryFolder,
|
||||
folder: LibraryFolder,
|
||||
security: SecurityParams,
|
||||
payload: LibraryFolderContentsIndexQueryPayload,
|
||||
):
|
||||
"""Builds a query to retrieve all the datasets contained in the given folder applying filters."""
|
||||
search_text = payload.search_text
|
||||
item_model = model.LibraryDataset
|
||||
item_permission_model = model.LibraryDatasetPermissions
|
||||
access_action = security.security_agent.permitted_actions.DATASET_ACCESS.action
|
||||
query = sa_session.query(item_model)
|
||||
query = query.filter(item_model.folder_id == folder.id)
|
||||
query = self._filter_by_include_deleted(
|
||||
query, item_model, item_permission_model, payload.include_deleted, security
|
||||
|
||||
stmt = select(LibraryDataset).where(LibraryDataset.folder_id == folder.id)
|
||||
stmt = self._filter_by_include_deleted(
|
||||
stmt, LibraryDataset, LibraryDatasetPermissions, payload.include_deleted, security
|
||||
)
|
||||
ldda = aliased(model.LibraryDatasetDatasetAssociation)
|
||||
associated_dataset = aliased(model.Dataset)
|
||||
query = query.outerjoin(item_model.library_dataset_dataset_association.of_type(ldda))
|
||||
ldda = aliased(LibraryDatasetDatasetAssociation)
|
||||
associated_dataset = aliased(Dataset)
|
||||
stmt = stmt.outerjoin(LibraryDataset.library_dataset_dataset_association.of_type(ldda))
|
||||
if not security.is_admin: # Non-admin users require ACCESS permission
|
||||
# We check against the actual dataset and not the ldda (for now?)
|
||||
dataset_permission = aliased(model.DatasetPermissions)
|
||||
dataset_permission = aliased(DatasetPermissions)
|
||||
is_public_dataset = not_(
|
||||
sa_session.query(model.DatasetPermissions)
|
||||
.filter(
|
||||
model.DatasetPermissions.dataset_id == associated_dataset.id,
|
||||
model.DatasetPermissions.action == access_action,
|
||||
)
|
||||
.exists()
|
||||
exists()
|
||||
.where(DatasetPermissions.dataset_id == associated_dataset.id)
|
||||
.where(DatasetPermissions.action == access_action)
|
||||
)
|
||||
query = query.outerjoin(ldda.dataset.of_type(associated_dataset))
|
||||
query = query.outerjoin(associated_dataset.actions.of_type(dataset_permission))
|
||||
query = query.filter(
|
||||
stmt = stmt.outerjoin(ldda.dataset.of_type(associated_dataset))
|
||||
stmt = stmt.outerjoin(associated_dataset.actions.of_type(dataset_permission))
|
||||
stmt = stmt.where(
|
||||
or_(
|
||||
# The dataset is public
|
||||
is_public_dataset,
|
||||
@@ -505,30 +504,27 @@ class FolderManager:
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
if search_text:
|
||||
search_text = search_text.lower()
|
||||
query = query.filter(
|
||||
stmt = stmt.where(
|
||||
or_(
|
||||
func.lower(ldda.name).contains(search_text, autoescape=True),
|
||||
func.lower(ldda.message).contains(search_text, autoescape=True),
|
||||
)
|
||||
)
|
||||
sort_column = LDDA_SORT_COLUMN_MAP[payload.order_by](ldda, associated_dataset)
|
||||
query = query.order_by(sort_column.desc() if payload.sort_desc else sort_column)
|
||||
|
||||
query = query.group_by(item_model.id, sort_column)
|
||||
|
||||
return query
|
||||
stmt = stmt.order_by(sort_column.desc() if payload.sort_desc else sort_column)
|
||||
stmt = stmt.group_by(LibraryDataset.id, sort_column)
|
||||
return stmt
|
||||
|
||||
def _filter_by_include_deleted(
|
||||
self, query, item_model, item_permissions_model, include_deleted: Optional[bool], security: SecurityParams
|
||||
self, stmt, item_model, item_permissions_model, include_deleted: Optional[bool], security: SecurityParams
|
||||
):
|
||||
if include_deleted: # Admins or users with MODIFY permissions can see deleted contents
|
||||
if not security.is_admin:
|
||||
item_permission = aliased(item_permissions_model)
|
||||
query = query.outerjoin(item_model.actions.of_type(item_permission))
|
||||
query = query.filter(
|
||||
stmt = stmt.outerjoin(item_model.actions.of_type(item_permission))
|
||||
stmt = stmt.where(
|
||||
or_(
|
||||
item_model.deleted == false(), # Is not deleted
|
||||
# User has MODIFY permission
|
||||
@@ -539,8 +535,8 @@ class FolderManager:
|
||||
)
|
||||
)
|
||||
else:
|
||||
query = query.filter(item_model.deleted == false())
|
||||
return query
|
||||
stmt = stmt.where(item_model.deleted == false())
|
||||
return stmt
|
||||
|
||||
def build_folder_path(
|
||||
self, sa_session: galaxy_scoped_session, folder: model.LibraryFolder
|
||||
@@ -553,7 +549,17 @@ class FolderManager:
|
||||
current_folder = folder
|
||||
path_to_root = [(LibraryFolderDatabaseIdField.encode(current_folder.id), current_folder.name)]
|
||||
while current_folder.parent_id is not None:
|
||||
parent_folder = sa_session.query(model.LibraryFolder).get(current_folder.parent_id)
|
||||
parent_folder = sa_session.get(LibraryFolder, current_folder.parent_id)
|
||||
current_folder = parent_folder
|
||||
path_to_root.insert(0, (LibraryFolderDatabaseIdField.encode(current_folder.id), current_folder.name))
|
||||
return path_to_root
|
||||
|
||||
|
||||
def get_folder(session, folder_id):
|
||||
stmt = select(LibraryFolder).where(LibraryFolder.id == folder_id)
|
||||
return session.execute(stmt).scalar_one()
|
||||
|
||||
|
||||
def get_count(session, statement):
|
||||
stmt = select(func.count()).select_from(statement)
|
||||
return session.scalar(stmt)
|
||||
|
||||
Reference in New Issue
Block a user