Commit e86caf56 authored by Sveinung Gundersen's avatar Sveinung Gundersen Committed by Cage, Gregory
Browse files

Merge 'Shortened all interactive tool URLs incl encoded ids of entry points' into branch

parent 3e697423
Loading
Loading
Loading
Loading
+10 −15
Original line number Diff line number Diff line
@@ -320,24 +320,19 @@ class InteractiveToolManager:

    def target_if_active(self, trans, entry_point):
        if entry_point.active and not entry_point.deleted:
            use_it_proxy_host_cfg = (
                not self.app.config.interactivetools_upstream_proxy and self.app.config.interactivetools_proxy_host
            )

            url_parts = urlsplit(trans.request.host_url)
            url_host = self.app.config.interactivetools_proxy_host if use_it_proxy_host_cfg else trans.request.host
            url_path = url_parts.path

            request_host = trans.request.host
            if not self.app.config.interactivetools_upstream_proxy and self.app.config.interactivetools_proxy_host:
                request_host = self.app.config.interactivetools_proxy_host
            protocol = trans.request.host_url.split("//", 1)[0]
            if entry_point.requires_domain:
                url_host = f"{self.get_entry_point_subdomain(trans, entry_point)}.{url_host}"
                rval = f"{protocol}//{self.get_entry_point_subdomain(trans, entry_point)}.{request_host}/"
                if entry_point.entry_url:
                    url_path = f"{url_path.rstrip('/')}/{entry_point.entry_url.lstrip('/')}"
                    rval = "{}/{}".format(rval.rstrip("/"), entry_point.entry_url.lstrip("/"))
            else:
                url_path = self.get_entry_point_path(trans, entry_point)
                if not use_it_proxy_host_cfg:
                    return url_path

            return urlunsplit((url_parts.scheme, url_host, url_path, "", ""))
                rval = self.get_entry_point_path(trans, entry_point)
                if not self.app.config.interactivetools_upstream_proxy and self.app.config.interactivetools_proxy_host:
                    rval = f"{protocol}//{request_host}{rval}"
            return rval

    def _get_entry_point_url_elements(self, trans, entry_point):
        encoder = IdAsLowercaseAlphanumEncodingHelper(trans.security)
+38 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ from collections import defaultdict
from collections.abc import Callable
from datetime import timedelta
from enum import Enum
from secrets import token_hex
from string import Template
from typing import (
    Any,
@@ -2705,17 +2706,21 @@ class InteractiveToolEntryPoint(Base, Dictifiable, RepresentById):
    protocol = Column(TEXT)
    entry_url = Column(TEXT)
    requires_domain = Column(Boolean, default=True)
    requires_path_in_url = Column(Boolean, default=False)
    requires_path_in_header_named = Column(TEXT)
    info = Column(MutableJSONType, nullable=True)
    configured = Column(Boolean, default=False)
    deleted = Column(Boolean, default=False)
    created_time = Column(DateTime, default=now)
    modified_time = Column(DateTime, default=now, onupdate=now)
    label = Column(TEXT)
    job = relationship("Job", back_populates="interactivetool_entry_points", uselist=False)

    dict_collection_visible_keys = [
        "id",
        "job_id",
        "name",
        "label",
        "active",
        "created_time",
        "modified_time",
@@ -2725,15 +2730,25 @@ class InteractiveToolEntryPoint(Base, Dictifiable, RepresentById):
        "id",
        "job_id",
        "name",
        "label",
        "active",
        "created_time",
        "modified_time",
        "output_datasets_ids",
    ]

    def __init__(self, requires_domain=True, configured=False, deleted=False, short_token=False, **kwd):
    def __init__(
        self,
        requires_domain=True,
        requires_path_in_url=False,
        configured=False,
        deleted=False,
        short_token=False,
        **kwd,
    ):
        super().__init__(**kwd)
        self.requires_domain = requires_domain
        self.requires_path_in_url = requires_path_in_url
        self.configured = configured
        self.deleted = deleted
        if short_token:
@@ -2749,6 +2764,10 @@ class InteractiveToolEntryPoint(Base, Dictifiable, RepresentById):
            return not self.job.finished
        return False

    @property
    def class_id(self):
        return "ep"

    @property
    def output_datasets_ids(self):
        return [da.dataset.id for da in self.job.output_datasets]
@@ -10458,6 +10477,24 @@ class CleanupEventImplicitlyConvertedDatasetAssociationAssociation(Base):
    icda_id = Column(Integer, ForeignKey("implicitly_converted_dataset_association.id"), index=True)


class CeleryUserRateLimit(Base):
    """
    For each user stores the last time a task was scheduled for execution.
    Used to limit the number of tasks allowed per user per second.
    """

    __tablename__ = "celery_user_rate_limit"

    user_id = Column(Integer, ForeignKey("galaxy_user.id", ondelete="CASCADE"), primary_key=True)
    last_scheduled_time = Column(DateTime, nullable=False)

    def __repr__(self):
        return (
            f"CeleryUserRateLimit(id_type={self.id_type!r}, "
            f"id={self.id!r}, last_scheduled_time={self.last_scheduled_time!r})"
        )


# The following models (HDA, LDDA) are mapped imperatively (for details see discussion in PR #12064)
# TLDR: there are issues ('metadata' property, Galaxy object wrapping) that need to be addressed separately
# before these models can be mapped declaratively. Keeping them in the mapping module breaks the auth package
+2 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@ from galaxy.util import (
    lowercase_alphanum_to_hex,
    smart_str,
    unicodify,
    hex_to_lowercase_alphanum,
    lowercase_alphanum_to_hex,
)

log = logging.getLogger(__name__)
+1 −3
Original line number Diff line number Diff line
@@ -1890,7 +1890,6 @@ def hex_to_lowercase_alphanum(hex_string: str) -> str:
    characters a-z and 0-9
    """
    import numpy as np

    return np.base_repr(int(hex_string, 16), 36).lower()


@@ -1900,5 +1899,4 @@ def lowercase_alphanum_to_hex(lowercase_alphanum: str) -> str:
    hexadecimal string
    """
    import numpy as np

    return np.base_repr(int(lowercase_alphanum, 36), 16).lower()
 No newline at end of file
+12 −5
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ from galaxy.model import (
    InteractiveToolEntryPoint,
    Job,
)
from galaxy.security.idencoding import IdAsLowercaseAlphanumEncodingHelper
from galaxy.structured_app import StructuredApp
from galaxy.web import expose_api_anonymous_and_sessionless
from . import BaseGalaxyAPIController
@@ -51,7 +52,7 @@ class ToolEntryPointsAPIController(BaseGalaxyAPIController):
            )

        if job_id is not None:
            job = trans.sa_session.query(Job).get(self.decode_id(job_id))
            job = trans.sa_session.get(Job, self.decode_id(job_id))
            if not self.interactivetool_manager.can_access_job(trans, job):
                raise exceptions.ItemAccessibilityException()
            entry_points = job.interactivetool_entry_points
@@ -60,7 +61,11 @@ class ToolEntryPointsAPIController(BaseGalaxyAPIController):

        rval = []
        for entry_point in entry_points:
            as_dict = self.encode_all_ids(trans, entry_point.to_dict(), True)
            entrypoint_id_encoder = IdAsLowercaseAlphanumEncodingHelper(trans.security)
            as_dict = entry_point.to_dict()
            as_dict["id"] = entrypoint_id_encoder.encode_id(as_dict["id"])
            as_dict_no_id = {k: v for k, v in as_dict.items() if k != "id"}
            as_dict.update(self.encode_all_ids(trans, as_dict_no_id, True))
            target = self.interactivetool_manager.target_if_active(trans, entry_point)
            if target:
                as_dict["target"] = target
@@ -82,7 +87,8 @@ class ToolEntryPointsAPIController(BaseGalaxyAPIController):
        # Because of auto id encoding needed for link from grid, the item.id keyword must be 'id'
        if not id:
            raise exceptions.RequestParameterMissingException("Must supply entry point ID.")
        entry_point_id = self.decode_id(id)
        entrypoint_id_encoder = IdAsLowercaseAlphanumEncodingHelper(trans.security)
        entry_point_id = entrypoint_id_encoder.decode_id(id)
        return {"target": self.interactivetool_manager.access_entry_point_target(trans, entry_point_id)}

    @expose_api_anonymous_and_sessionless
@@ -93,8 +99,9 @@ class ToolEntryPointsAPIController(BaseGalaxyAPIController):
        if not id:
            raise exceptions.RequestParameterMissingException("Must supply entry point id")
        try:
            entry_point_id = self.decode_id(id)
            entry_point = trans.sa_session.query(InteractiveToolEntryPoint).get(entry_point_id)
            entrypoint_id_encoder = IdAsLowercaseAlphanumEncodingHelper(trans.security)
            entry_point_id = entrypoint_id_encoder.decode_id(id)
            entry_point = trans.sa_session.get(InteractiveToolEntryPoint, entry_point_id)
        except Exception:
            raise exceptions.RequestParameterInvalidException("entry point invalid")
        if self.app.interactivetool_manager.can_access_entry_point(trans, entry_point):