diff --git a/client/src/components/LibraryFolder/TopToolbar/FolderTopBar.vue b/client/src/components/LibraryFolder/TopToolbar/FolderTopBar.vue
index 9508c54f2be..202205ddbcf 100644
--- a/client/src/components/LibraryFolder/TopToolbar/FolderTopBar.vue
+++ b/client/src/components/LibraryFolder/TopToolbar/FolderTopBar.vue
@@ -21,7 +21,6 @@
@@ -201,7 +200,6 @@ export default {
data() {
return {
is_admin: false,
- multiple_add_dataset_options: false,
user_library_import_dir: false,
library_import_dir: false,
allow_library_path_paste: false,
@@ -227,13 +225,6 @@ export default {
this.user_library_import_dir = Galaxy.config.user_library_import_dir;
this.library_import_dir = Galaxy.config.library_import_dir;
this.allow_library_path_paste = Galaxy.config.allow_library_path_paste;
- if (
- this.user_library_import_dir !== null ||
- this.allow_library_path_paste !== false ||
- this.library_import_dir !== null
- ) {
- this.multiple_add_dataset_options = true;
- }
this.fetchExtAndGenomes();
},
diff --git a/client/src/components/Upload/UploadBoxMixin.js b/client/src/components/Upload/UploadBoxMixin.js
index 09b2eb981e9..8904c84b29b 100644
--- a/client/src/components/Upload/UploadBoxMixin.js
+++ b/client/src/components/Upload/UploadBoxMixin.js
@@ -259,7 +259,7 @@ export default {
return $(this.$refs.uploadTable);
},
extensionDetails(extension) {
- return findExtension(this.effectiveExtensions, extension);
+ return findExtension(this.app.effectiveExtensions, extension);
},
initExtensionInfo() {
$(this.$refs.footerExtensionInfo)
diff --git a/lib/galaxy/jobs/__init__.py b/lib/galaxy/jobs/__init__.py
index 704506030ef..df1a9e6a074 100644
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -1940,10 +1940,13 @@ class JobWrapper(HasResourceParameters):
return self.output_paths
def get_output_path(self, dataset):
+ if getattr(dataset, "fake_dataset_association", False):
+ return dataset.file_name
+ assert dataset.id is not None, "{} needs to be flushed to find output path".format(dataset)
if self.output_paths is None:
self.compute_outputs()
for (hda, dataset_path) in self.output_hdas_and_paths.values():
- if hda == dataset:
+ if hda.id == dataset.id:
return dataset_path
raise KeyError(f"Couldn't find job output for [{dataset}] in [{self.output_hdas_and_paths.values()}]")
diff --git a/lib/galaxy/managers/users.py b/lib/galaxy/managers/users.py
index 7d0058ff189..183eca0629f 100644
--- a/lib/galaxy/managers/users.py
+++ b/lib/galaxy/managers/users.py
@@ -21,6 +21,7 @@ from galaxy.managers import (
deletable
)
from galaxy.security.validate_user_input import (
+ VALID_EMAIL_RE,
validate_email,
validate_password,
validate_publicname
@@ -278,6 +279,22 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
raise exceptions.AuthenticationFailed(msg, **kwargs)
return user
+ def get_user_by_identity(self, identity):
+ """Get user by username or email."""
+ user = None
+ if VALID_EMAIL_RE.match(identity):
+ # VALID_PUBLICNAME and VALID_EMAIL do not overlap, so 'identity' here is an email address
+ user = self.session().query(self.model_class).filter(
+ self.model_class.table.c.email == identity).first()
+ if not user:
+ # Try a case-insensitive match on the email
+ user = self.session().query(self.model_class).filter(
+ func.lower(self.model_class.table.c.email) == identity.lower()).first()
+ else:
+ user = self.session().query(self.model_class).filter(
+ self.model_class.table.c.username == identity).first()
+ return user
+
# ---- current
def current_user(self, trans):
# define here for single point of change and make more readable
diff --git a/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py b/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py
index 682c6755830..a5fd21bf284 100644
--- a/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py
+++ b/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py
@@ -15,9 +15,9 @@ from .mulled_build import (
add_build_arguments,
add_single_image_arguments,
args_to_mull_targets_kwds,
- build_target,
mull_targets,
)
+from .util import build_target
def main(argv=None):
diff --git a/lib/galaxy/tool_util/deps/mulled/util.py b/lib/galaxy/tool_util/deps/mulled/util.py
index 9535c400561..b3e68824dea 100644
--- a/lib/galaxy/tool_util/deps/mulled/util.py
+++ b/lib/galaxy/tool_util/deps/mulled/util.py
@@ -83,7 +83,7 @@ def mulled_tags_for(namespace, image, tag_prefix=None, resolution_cache=None):
# Following check is pretty expensive against biocontainers... don't even bother doing it
# if can't cache the response.
if not _namespace_has_repo_name(namespace, image, resolution_cache):
- log.debug("skipping mulled_tags_for [%s] no repository" % image)
+ log.info("skipping mulled_tags_for [%s] no repository" % image)
return []
cache_key = "galaxy.tool_util.deps.container_resolvers.mulled.util:tag_cache"
@@ -158,7 +158,8 @@ def build_target(package_name, version=None, build=None, tag=None):
assert build is None
version, build = split_tag(tag)
- return Target(package_name, version, build, package_name)
+ # conda package and quay image names are lowercase
+ return Target(package_name.lower(), version, build, package_name)
def conda_build_target_str(target):
diff --git a/lib/galaxy/webapps/galaxy/api/authenticate.py b/lib/galaxy/webapps/galaxy/api/authenticate.py
index 570ad83cc52..7b6d56a1757 100644
--- a/lib/galaxy/webapps/galaxy/api/authenticate.py
+++ b/lib/galaxy/webapps/galaxy/api/authenticate.py
@@ -15,7 +15,10 @@ from base64 import b64decode
from urllib.parse import unquote
from galaxy import exceptions
-from galaxy.managers import api_keys
+from galaxy.managers import (
+ api_keys,
+ users,
+)
from galaxy.util import (
smart_str,
unicodify
@@ -30,6 +33,7 @@ class AuthenticationController(BaseAPIController):
def __init__(self, app):
super().__init__(app)
+ self.user_manager = users.UserManager(app)
self.api_keys_manager = api_keys.ApiKeyManager(app)
@expose_api_anonymous_and_sessionless
@@ -58,18 +62,12 @@ class AuthenticationController(BaseAPIController):
:raises: ObjectNotFound, HTTPBadRequest
"""
- email, password = self._decode_baseauth(trans.environ.get('HTTP_AUTHORIZATION'))
-
- user = trans.sa_session.query(trans.app.model.User).filter(trans.app.model.User.table.c.email == email).all()
-
- if len(user) == 0:
+ identity, password = self._decode_baseauth(trans.environ.get('HTTP_AUTHORIZATION'))
+ # check if this is an email address or username
+ user = self.user_manager.get_user_by_identity(identity)
+ if not user:
raise exceptions.ObjectNotFound('The user does not exist.')
- elif len(user) > 1:
- # DB is inconsistent and we have more users with the same email.
- raise exceptions.InconsistentDatabase('An error occurred, please contact your administrator.')
- else:
- user = user[0]
- is_valid_user = self.app.auth_manager.check_password(user, password)
+ is_valid_user = self.app.auth_manager.check_password(user, password)
if is_valid_user:
key = self.api_keys_manager.get_or_create_api_key(user)
return dict(api_key=key)
diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py
index 84de563132b..2e7114c5f2c 100644
--- a/lib/galaxy/webapps/galaxy/controllers/user.py
+++ b/lib/galaxy/webapps/galaxy/controllers/user.py
@@ -7,10 +7,6 @@ from datetime import datetime, timedelta
from urllib.parse import unquote
from markupsafe import escape
-from sqlalchemy import (
- func,
- or_
-)
from sqlalchemy.orm.exc import NoResultFound
from galaxy import (
@@ -134,15 +130,7 @@ class User(BaseUIController, UsesFormDefinitionsMixin, CreatesApiKeysMixin):
status = None
if not login or not password:
return self.message_exception(trans, "Please specify a username and password.")
- user = trans.sa_session.query(trans.app.model.User).filter(or_(
- trans.app.model.User.table.c.email == login,
- trans.app.model.User.table.c.username == login
- )).first()
- if not user:
- # Try a case-insensitive match on the email
- user = trans.sa_session.query(trans.app.model.User).filter(
- func.lower(trans.app.model.User.table.c.email) == login.lower()
- ).first()
+ user = self.user_manager.get_user_by_identity(login)
log.debug("trans.app.config.auth_config_file: %s" % trans.app.config.auth_config_file)
if user is None:
message, user = self.__autoregistration(trans, login, password)
diff --git a/test/unit/managers/test_UserManager.py b/test/unit/managers/test_UserManager.py
index a65315040c8..f79274ca0c9 100644
--- a/test/unit/managers/test_UserManager.py
+++ b/test/unit/managers/test_UserManager.py
@@ -23,6 +23,8 @@ changed_password = '654321'
user2_data = dict(email='user2@user2.user2', username='user2', password=default_password)
user3_data = dict(email='user3@user3.user3', username='user3', password=default_password)
user4_data = dict(email='user4@user4.user4', username='user4', password=default_password)
+uppercase_email_user = dict(email='USER5@USER5.USER5', username='USER5', password=default_password)
+lowercase_email_user = dict(email='user5@user5.user5', username='user5', password=default_password)
# =============================================================================
@@ -192,6 +194,31 @@ class UserManagerTestCase(BaseTestCase):
self.assertFalse(check_password("", user.password))
self.assertFalse(check_password(None, user.password))
+ def test_get_user_by_identity(self):
+ # return None if username/email not found
+ assert self.user_manager.get_user_by_identity('xyz') is None
+ uppercase_user = self.user_manager.create(**uppercase_email_user)
+ assert uppercase_user.email == uppercase_email_user['email']
+ assert uppercase_user.username == uppercase_email_user['username']
+ assert self.user_manager.get_user_by_identity(uppercase_user.email) == uppercase_user
+ assert self.user_manager.get_user_by_identity(uppercase_user.username) == uppercase_user
+ # Create another user with the same email just differently capitalized.
+ # This is not normally allowed now, since registration goes through user_manager.register(),
+ # which checks for that, but was possible in earlier releases of Galaxy
+ lowercase_user = self.user_manager.create(**lowercase_email_user)
+ assert lowercase_user.email == lowercase_email_user['email']
+ assert lowercase_user.username == lowercase_email_user['username']
+ assert self.user_manager.get_user_by_identity(lowercase_user.email) == lowercase_user
+ assert self.user_manager.get_user_by_identity(lowercase_user.username) == lowercase_user
+ # assert uppercase user can still be retrieved
+ assert self.user_manager.get_user_by_identity(uppercase_user.email) == uppercase_user
+ assert self.user_manager.get_user_by_identity(uppercase_user.username) == uppercase_user
+ # username matches need to be exact
+ assert self.user_manager.get_user_by_identity(uppercase_user.username.capitalize()) is None
+ # email matches can ignore capitalization
+ ignore_email_capitalization_user = self.user_manager.create(email='user123@nopassword.com', username='someusername123')
+ assert self.user_manager.get_user_by_identity(ignore_email_capitalization_user.email.capitalize()) == ignore_email_capitalization_user
+
# =============================================================================
class UserSerializerTestCase(BaseTestCase):