Loading client/src/components/Form/FormElement.vue +6 −1 Original line number Diff line number Diff line Loading @@ -3,9 +3,12 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faCaretSquareDown, faCaretSquareUp } from "@fortawesome/free-regular-svg-icons"; import { faArrowsAltH, faExclamation, faTimes } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { sanitize } from "dompurify"; import type { ComputedRef } from "vue"; import { computed, ref, useAttrs } from "vue"; import { linkify } from "@/utils/utils"; import type { FormParameterAttributes, FormParameterTypes, FormParameterValue } from "./parameterTypes"; import FormBoolean from "./Elements/FormBoolean.vue"; Loading Loading @@ -181,7 +184,9 @@ const isOptional = computed(() => !isRequired.value && attrs.value["optional"] ! :class="{ alert: hasAlert, 'alert-info': hasAlert }"> <div v-if="hasAlert" class="ui-form-error"> <FontAwesomeIcon class="mr-1" icon="fa-exclamation" /> <span class="ui-form-error-text" v-html="props.error || props.warning" /> <span class="ui-form-error-text" v-html="linkify(sanitize(props.error || props.warning, { USE_PROFILES: { html: true } }))" /> </div> <div class="ui-form-title"> Loading lib/galaxy/managers/users.py +8 −6 Original line number Diff line number Diff line Loading @@ -144,15 +144,13 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin): else: # Activation is off, every new user is active by default. user.active = True self.session().add(user) try: session = self.session() with transaction(session): session.commit() # TODO:?? flush needed for permissions below? If not, make optional session.add(user) try: # Creating a private role will commit the session self.app.security_agent.create_user_role(user, self.app) except exc.IntegrityError as db_err: raise exceptions.Conflict(str(db_err)) self.app.security_agent.create_user_role(user, self.app) return user def delete(self, user, flush=True): Loading Loading @@ -197,6 +195,10 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin): if not user.deleted: raise exceptions.MessageException(f"User '{user.email}' has not been deleted, so they cannot be purged.") private_role = self.app.security_agent.get_private_user_role(user) if private_role is None: raise exceptions.InconsistentDatabase( "User '%s' private role is missing while attempting to purge deleted user." % user.email ) # Delete History for active_history in user.active_histories: self.session().refresh(active_history) Loading lib/galaxy/model/security.py +3 −0 Original line number Diff line number Diff line Loading @@ -765,6 +765,9 @@ WHERE history.user_id != :user_id and history_dataset_association.dataset_id = : return self.get_private_user_role(user) def get_private_user_role(self, user, auto_create=False): if auto_create and user.id is None: # New user, directly create private role return self.create_private_user_role(user) stmt = ( select(Role) .where( Loading lib/galaxy/tool_util/lint.py +10 −1 Original line number Diff line number Diff line Loading @@ -102,12 +102,21 @@ class Linter(ABC): return cls.__name__ @classmethod def list_listers(cls) -> List[str]: def list_linters(cls) -> List[str]: """ list the names of all linter derived from Linter """ submodules.import_submodules(galaxy.tool_util.linters) return [s.__name__ for s in cls.__subclasses__()] list_listers: Callable[[], List[str]] # deprecated alias # Define the `list_listers` alias outside of the `Linter` class so that # @classmethod's change to `list_linters`s signature has taken effect and mypy # doesn't report an [assignment] error Linter.list_listers = Linter.list_linters class LintMessage: """ Loading lib/galaxy/webapps/galaxy/api/workflows.py +4 −6 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ from fastapi import ( status, ) from gxformat2._yaml import ordered_dump from markupsafe import escape from pydantic import ( UUID1, UUID4, Loading Loading @@ -86,7 +85,6 @@ from galaxy.tool_shed.galaxy_install.install_manager import InstallRepositoryMan from galaxy.tools import recommendations from galaxy.tools.parameters import populate_state from galaxy.tools.parameters.workflow_utils import workflow_building_modes from galaxy.util.sanitize_html import sanitize_html from galaxy.web import ( expose_api, expose_api_raw_anonymous_and_sessionless, Loading Loading @@ -268,7 +266,7 @@ class WorkflowsAPIController( ) import_source = "URL" except Exception: raise exceptions.MessageException(f"Failed to open URL '{escape(archive_source)}'.") raise exceptions.MessageException(f"Failed to open URL '{archive_source}'.") elif hasattr(archive_file, "file"): uploaded_file = archive_file.file uploaded_file_name = uploaded_file.name Loading Loading @@ -448,7 +446,7 @@ class WorkflowsAPIController( name_updated = new_workflow_name and new_workflow_name != stored_workflow.name steps_updated = "steps" in workflow_dict if name_updated and not steps_updated: sanitized_name = sanitize_html(new_workflow_name or old_workflow.name) sanitized_name = new_workflow_name or old_workflow.name if not sanitized_name: raise exceptions.MessageException("Workflow must have a valid name.") workflow = old_workflow.copy(user=trans.user) Loading @@ -472,7 +470,7 @@ class WorkflowsAPIController( require_flush = True if "annotation" in workflow_dict and not steps_updated: newAnnotation = sanitize_html(workflow_dict["annotation"]) newAnnotation = workflow_dict["annotation"] self.add_item_annotation(trans.sa_session, trans.user, stored_workflow, newAnnotation) require_flush = True Loading Loading @@ -599,7 +597,7 @@ class WorkflowsAPIController( workflow = workflow.latest_workflow response = { "message": f"Workflow '{escape(workflow.name)}' imported successfully.", "message": f"Workflow '{workflow.name}' imported successfully.", "status": "success", "id": trans.security.encode_id(workflow_id), } Loading Loading
client/src/components/Form/FormElement.vue +6 −1 Original line number Diff line number Diff line Loading @@ -3,9 +3,12 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faCaretSquareDown, faCaretSquareUp } from "@fortawesome/free-regular-svg-icons"; import { faArrowsAltH, faExclamation, faTimes } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { sanitize } from "dompurify"; import type { ComputedRef } from "vue"; import { computed, ref, useAttrs } from "vue"; import { linkify } from "@/utils/utils"; import type { FormParameterAttributes, FormParameterTypes, FormParameterValue } from "./parameterTypes"; import FormBoolean from "./Elements/FormBoolean.vue"; Loading Loading @@ -181,7 +184,9 @@ const isOptional = computed(() => !isRequired.value && attrs.value["optional"] ! :class="{ alert: hasAlert, 'alert-info': hasAlert }"> <div v-if="hasAlert" class="ui-form-error"> <FontAwesomeIcon class="mr-1" icon="fa-exclamation" /> <span class="ui-form-error-text" v-html="props.error || props.warning" /> <span class="ui-form-error-text" v-html="linkify(sanitize(props.error || props.warning, { USE_PROFILES: { html: true } }))" /> </div> <div class="ui-form-title"> Loading
lib/galaxy/managers/users.py +8 −6 Original line number Diff line number Diff line Loading @@ -144,15 +144,13 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin): else: # Activation is off, every new user is active by default. user.active = True self.session().add(user) try: session = self.session() with transaction(session): session.commit() # TODO:?? flush needed for permissions below? If not, make optional session.add(user) try: # Creating a private role will commit the session self.app.security_agent.create_user_role(user, self.app) except exc.IntegrityError as db_err: raise exceptions.Conflict(str(db_err)) self.app.security_agent.create_user_role(user, self.app) return user def delete(self, user, flush=True): Loading Loading @@ -197,6 +195,10 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin): if not user.deleted: raise exceptions.MessageException(f"User '{user.email}' has not been deleted, so they cannot be purged.") private_role = self.app.security_agent.get_private_user_role(user) if private_role is None: raise exceptions.InconsistentDatabase( "User '%s' private role is missing while attempting to purge deleted user." % user.email ) # Delete History for active_history in user.active_histories: self.session().refresh(active_history) Loading
lib/galaxy/model/security.py +3 −0 Original line number Diff line number Diff line Loading @@ -765,6 +765,9 @@ WHERE history.user_id != :user_id and history_dataset_association.dataset_id = : return self.get_private_user_role(user) def get_private_user_role(self, user, auto_create=False): if auto_create and user.id is None: # New user, directly create private role return self.create_private_user_role(user) stmt = ( select(Role) .where( Loading
lib/galaxy/tool_util/lint.py +10 −1 Original line number Diff line number Diff line Loading @@ -102,12 +102,21 @@ class Linter(ABC): return cls.__name__ @classmethod def list_listers(cls) -> List[str]: def list_linters(cls) -> List[str]: """ list the names of all linter derived from Linter """ submodules.import_submodules(galaxy.tool_util.linters) return [s.__name__ for s in cls.__subclasses__()] list_listers: Callable[[], List[str]] # deprecated alias # Define the `list_listers` alias outside of the `Linter` class so that # @classmethod's change to `list_linters`s signature has taken effect and mypy # doesn't report an [assignment] error Linter.list_listers = Linter.list_linters class LintMessage: """ Loading
lib/galaxy/webapps/galaxy/api/workflows.py +4 −6 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ from fastapi import ( status, ) from gxformat2._yaml import ordered_dump from markupsafe import escape from pydantic import ( UUID1, UUID4, Loading Loading @@ -86,7 +85,6 @@ from galaxy.tool_shed.galaxy_install.install_manager import InstallRepositoryMan from galaxy.tools import recommendations from galaxy.tools.parameters import populate_state from galaxy.tools.parameters.workflow_utils import workflow_building_modes from galaxy.util.sanitize_html import sanitize_html from galaxy.web import ( expose_api, expose_api_raw_anonymous_and_sessionless, Loading Loading @@ -268,7 +266,7 @@ class WorkflowsAPIController( ) import_source = "URL" except Exception: raise exceptions.MessageException(f"Failed to open URL '{escape(archive_source)}'.") raise exceptions.MessageException(f"Failed to open URL '{archive_source}'.") elif hasattr(archive_file, "file"): uploaded_file = archive_file.file uploaded_file_name = uploaded_file.name Loading Loading @@ -448,7 +446,7 @@ class WorkflowsAPIController( name_updated = new_workflow_name and new_workflow_name != stored_workflow.name steps_updated = "steps" in workflow_dict if name_updated and not steps_updated: sanitized_name = sanitize_html(new_workflow_name or old_workflow.name) sanitized_name = new_workflow_name or old_workflow.name if not sanitized_name: raise exceptions.MessageException("Workflow must have a valid name.") workflow = old_workflow.copy(user=trans.user) Loading @@ -472,7 +470,7 @@ class WorkflowsAPIController( require_flush = True if "annotation" in workflow_dict and not steps_updated: newAnnotation = sanitize_html(workflow_dict["annotation"]) newAnnotation = workflow_dict["annotation"] self.add_item_annotation(trans.sa_session, trans.user, stored_workflow, newAnnotation) require_flush = True Loading Loading @@ -599,7 +597,7 @@ class WorkflowsAPIController( workflow = workflow.latest_workflow response = { "message": f"Workflow '{escape(workflow.name)}' imported successfully.", "message": f"Workflow '{workflow.name}' imported successfully.", "status": "success", "id": trans.security.encode_id(workflow_id), } Loading