diff --git a/lib/galaxy/managers/base.py b/lib/galaxy/managers/base.py index 298ebc0b2b3..10b507250c7 100644 --- a/lib/galaxy/managers/base.py +++ b/lib/galaxy/managers/base.py @@ -576,8 +576,6 @@ class ModelSerializer(HasAModelManager[T]): keys_to_serialize = [ 'id', 'name', 'attr1', 'attr2', ... ] item_dict = MySerializer.serialize( my_item, keys_to_serialize ) """ - #: 'service' to use for getting urls - use class var to allow overriding when testing - url_for = staticmethod(gx_url_for) default_view: Optional[str] views: Dict[str, List[str]] @@ -604,6 +602,12 @@ class ModelSerializer(HasAModelManager[T]): self.views = {} self.default_view = None + @staticmethod + def url_for(*args, context=None, **kwargs): + trans = context and context.get('trans') + url_for = trans and trans.url_builder or gx_url_for + return url_for(*args, **kwargs) + def add_serializers(self): """ Register a map of attribute keys -> serializing functions that will serialize diff --git a/lib/galaxy/managers/datasets.py b/lib/galaxy/managers/datasets.py index cf3bd0128bf..08358d9d49b 100644 --- a/lib/galaxy/managers/datasets.py +++ b/lib/galaxy/managers/datasets.py @@ -527,10 +527,11 @@ class _UnflattenedMetadataDatasetAssociationSerializer(base.ModelSerializer[T], if getattr(dataset_assoc.metadata, meta_type, None): meta_files.append( dict(file_type=meta_type, - download_url=self.url_for('history_contents_metadata_file', + download_url=self.url_for('get_metadata_file', history_id=self.app.security.encode_id(dataset_assoc.history_id), history_content_id=self.app.security.encode_id(dataset_assoc.id), - metadata_file=meta_type))) + query_params={'metadata_file': meta_type}, + context=context))) return meta_files def serialize_metadata(self, item, key, excluded=None, **context): diff --git a/lib/galaxy/managers/hdas.py b/lib/galaxy/managers/hdas.py index fd59c1585a9..4eca4e0d202 100644 --- a/lib/galaxy/managers/hdas.py +++ b/lib/galaxy/managers/hdas.py @@ -427,13 +427,15 @@ class HDASerializer( # datasets._UnflattenedMetadataDatasetAssociationSerialize # see also: https://sentry.galaxyproject.org/galaxy/galaxy-main/group/20769/events/9352883/ 'url': lambda item, key, **context: self.url_for('history_content', history_id=self.app.security.encode_id(item.history_id), - id=self.app.security.encode_id(item.id)), + id=self.app.security.encode_id(item.id), + context=context), 'urls': self.serialize_urls, # TODO: backwards compat: need to go away 'download_url': lambda item, key, **context: self.url_for('history_contents_display', history_id=self.app.security.encode_id(item.history.id), - history_content_id=self.app.security.encode_id(item.id)), + history_content_id=self.app.security.encode_id(item.id), + context=context), 'parent_id': self.serialize_id, # TODO: to DatasetAssociationSerializer 'accessible': lambda item, key, user=None, **c: self.manager.is_accessible(item, user, **c), diff --git a/lib/galaxy/webapps/base/webapp.py b/lib/galaxy/webapps/base/webapp.py index 9a99007f1af..e16a0aaba4b 100644 --- a/lib/galaxy/webapps/base/webapp.py +++ b/lib/galaxy/webapps/base/webapp.py @@ -192,7 +192,8 @@ def config_allows_origin(origin_raw, config): def url_builder(*args, **kwargs) -> str: - """Wrapper around the uWSGI version of the function for reversing URLs.""" + """Wrapper around the WSGI version of the function for reversing URLs.""" + kwargs.update(kwargs.pop('query_params', {})) return url_for(*args, **kwargs) diff --git a/lib/galaxy/webapps/galaxy/api/__init__.py b/lib/galaxy/webapps/galaxy/api/__init__.py index bc08740bc52..49ea15124b5 100644 --- a/lib/galaxy/webapps/galaxy/api/__init__.py +++ b/lib/galaxy/webapps/galaxy/api/__init__.py @@ -10,6 +10,7 @@ from typing import ( Type, TypeVar, ) +from urllib.parse import urlencode from fastapi import ( Cookie, @@ -149,12 +150,20 @@ class UrlBuilder: def __call__(self, name: str, **path_params): qualified = path_params.pop("qualified", False) + # starlette does not support query parameters in url_path_for: https://github.com/encode/starlette/issues/560 + query_params = path_params.pop('query_params', None) try: if qualified: - return self.request.url_for(name, **path_params) - return self.request.app.url_path_for(name, **path_params) + url = self.request.url_for(name, **path_params) + else: + url = self.request.app.url_path_for(name, **path_params) + if query_params: + url = f"{url}?{urlencode(query_params)}" + return url except NoMatchFound: # Fallback to legacy url_for + if query_params: + path_params.update(query_params) return web.url_for(name, **path_params) diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index 7a1f3989a00..44b08ca5c8b 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -297,7 +297,7 @@ def populate_api_routes(webapp, app): controller='datasets', action='show_inheritance_chain', conditions=dict(method=["GET"])) - webapp.mapper.connect("history_contents_metadata_file", + webapp.mapper.connect("get_metadata_file", "/api/histories/{history_id}/contents/{history_content_id}/metadata_file", controller="datasets", action="get_metadata_file",