Merge pull request #15557 from jdavcs/dev_emailfrom

Handle "email_from" config option consistently, as per schema description
This commit is contained in:
Marius van den Beek
2023-02-16 10:58:19 +01:00
committed by GitHub
5 changed files with 41 additions and 38 deletions
+26 -13
View File
@@ -30,6 +30,7 @@ from typing import (
TypeVar,
Union,
)
from urllib.parse import urlparse
import yaml
@@ -135,6 +136,7 @@ LOGGING_CONFIG_DEFAULT: Dict[str, Any] = {
"""Default value for logging configuration, passed to :func:`logging.config.dictConfig`"""
VERSION_JSON_FILE = "version.json"
DEFAULT_EMAIL_FROM_LOCAL_PART = "galaxy-no-reply"
def configure_logging(config, facts=None):
@@ -612,16 +614,6 @@ class CommonConfigurationMixin:
class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
deprecated_options = (
"database_file",
"track_jobs_in_database",
"blacklist_file",
"whitelist_file",
"sanitize_whitelist_file",
"user_library_import_symlink_whitelist",
"fetch_url_whitelist",
"containers_resolvers_config_file",
)
renamed_options = {
"blacklist_file": "email_domain_blocklist_file",
"whitelist_file": "email_domain_allowlist_file",
@@ -629,7 +621,14 @@ class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
"user_library_import_symlink_whitelist": "user_library_import_symlink_allowlist",
"fetch_url_whitelist": "fetch_url_allowlist",
"containers_resolvers_config_file": "container_resolvers_config_file",
"activation_email": "email_from",
}
deprecated_options = list(renamed_options.keys()) + [
"database_file",
"track_jobs_in_database",
]
default_config_file_name = "galaxy.yml"
deprecated_dirs = {"config_dir": "config", "data_dir": "database"}
@@ -895,8 +894,6 @@ class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
self.nodejs_path = kwargs.get("nodejs_path")
self.container_image_cache_path = self._in_data_dir(kwargs.get("container_image_cache_path", "container_cache"))
self.output_size_limit = int(kwargs.get("output_size_limit", 0))
# activation_email was used until release_15.03
self.email_from = self.email_from or kwargs.get("activation_email")
self.email_domain_blocklist_content = (
self._load_list_from_file(self._in_config_dir(self.email_domain_blocklist_file))
@@ -1046,7 +1043,7 @@ class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
if section.startswith("server:"):
self.server_names.append(section.replace("server:", "", 1))
self._set_galaxy_infrastructure_url(kwargs)
self._set_host_related_options(kwargs)
# Asynchronous execution process pools - limited functionality for now, attach_to_pools is designed to allow
# webless Galaxy server processes to attach to arbitrary message queues (e.g. as job handlers) so they do not
@@ -1209,6 +1206,12 @@ class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
with open(filepath) as f:
return [line.strip() for line in f]
def _set_host_related_options(self, kwargs):
# The following 3 method calls must be made in sequence
self._set_galaxy_infrastructure_url(kwargs)
self._set_hostname()
self._set_email_from()
def _set_galaxy_infrastructure_url(self, kwargs):
# indicate if this was not set explicitly, so dependending on the context a better default
# can be used (request url in a web thread, Docker parent in IE stuff, etc.)
@@ -1227,6 +1230,16 @@ class GalaxyAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
if "UWSGI_PORT" in self.galaxy_infrastructure_url:
raise Exception("UWSGI_PORT is not supported anymore")
def _set_hostname(self):
if self.galaxy_infrastructure_url_set:
self.hostname = urlparse(self.galaxy_infrastructure_url).hostname
else:
self.hostname = socket.getfqdn()
def _set_email_from(self):
if not self.email_from:
self.email_from = f"{DEFAULT_EMAIL_FROM_LOCAL_PART}@{self.hostname}"
def reload_sanitize_allowlist(self, explicit=True):
self.sanitize_allowlist = []
if not os.path.exists(self.sanitize_allowlist_file):
+1 -9
View File
@@ -3,7 +3,6 @@ Actions to be run at job completion (or output hda creation, as in the case of
immediate_actions listed below.
"""
import datetime
import socket
from markupsafe import escape
@@ -53,7 +52,6 @@ class EmailAction(DefaultJobAction):
@classmethod
def execute(cls, app, sa_session, action, job, replacement_dict, final_job_state=None):
try:
frm = app.config.email_from
history_id_encoded = app.security.encode_id(job.history_id)
link_invocation = None
if job.workflow_invocation_step:
@@ -62,19 +60,13 @@ class EmailAction(DefaultJobAction):
f"{app.config.galaxy_infrastructure_url}/workflows/invocations/report?id={invocation_id_encoded}"
)
link = f"{app.config.galaxy_infrastructure_url}/histories/view?id={history_id_encoded}"
if frm is None:
if action.action_arguments and "host" in action.action_arguments:
host = action.action_arguments["host"]
else:
host = socket.getfqdn()
frm = f"galaxy-no-reply@{host}"
to = job.get_user_email()
subject = f"Galaxy job completion notification from history '{job.history.name}'"
outdata = ",\n".join(ds.dataset.display_name() for ds in job.output_datasets)
body = f"Your Galaxy job generating dataset(s):\n\n{outdata}\n\nis complete as of {datetime.datetime.now().strftime('%I:%M')}. Click the link below to access your data: \n{link}"
if link_invocation:
body += f"\n\nWorkflow Invocation Report:\n{link_invocation}"
send_mail(frm, to, subject, body, app.config)
send_mail(app.config.email_from, to, subject, body, app.config)
except Exception as e:
log.error("EmailAction PJA Failed, exception: %s", unicodify(e))
+3 -14
View File
@@ -5,7 +5,6 @@ import hashlib
import logging
import random
import re
import socket
import time
from datetime import datetime
from typing import Optional
@@ -484,7 +483,6 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
activation_link = url_for(
controller="user", action="activate", activation_token=activation_token, email=escape(email), qualified=True
)
host = self.__get_host(trans)
template_context = {
"name": escape(username),
"user_email": escape(email),
@@ -500,10 +498,9 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
body = templates.render(TXT_ACTIVATION_EMAIL_TEMPLATE_RELPATH, template_context, self.app.config.templates_dir)
html = templates.render(HTML_ACTIVATION_EMAIL_TEMPLATE_RELPATH, template_context, self.app.config.templates_dir)
to = email
frm = self.app.config.email_from or f"galaxy-no-reply@{host}"
subject = "Galaxy Account Activation"
try:
util.send_mail(frm, to, subject, body, self.app.config, html=html)
util.send_mail(self.app.config.email_from, to, subject, body, self.app.config, html=html)
return True
except Exception:
log.debug(body)
@@ -536,18 +533,16 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
else:
reset_user, prt = self.get_reset_token(trans, email)
if prt:
host = self.__get_host(trans)
reset_url = url_for(controller="login", action="start", token=prt.token)
body = PASSWORD_RESET_TEMPLATE % (
host,
trans.app.config.hostname,
prt.expiration_time.strftime(trans.app.config.pretty_datetime_format),
trans.request.host,
reset_url,
)
frm = trans.app.config.email_from or f"galaxy-no-reply@{host}"
subject = "Galaxy Password Reset"
try:
util.send_mail(frm, email, subject, body, self.app.config)
util.send_mail(trans.app.config.email_from, email, subject, body, self.app.config)
trans.sa_session.add(reset_user)
trans.sa_session.flush()
trans.log_event(f"User reset password: {email}")
@@ -574,12 +569,6 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
return reset_user, prt
return None, None
def __get_host(self, trans):
host = trans.request.host.split(":")[0]
if host in ["localhost", "127.0.0.1", "0.0.0.0"]:
host = socket.getfqdn()
return host
def send_subscription_email(self, email):
if self.app.config.smtp_server is None:
return "Subscribing to the mailing list has failed because mail is not configured for this Galaxy instance. Please contact your local Galaxy administrator."
+3 -2
View File
@@ -243,7 +243,6 @@ class EmailErrorReporter(ErrorReporter):
to = self.app.config.error_email_to
assert to, ValueError("Error reporting has been disabled for this Galaxy instance")
frm = self.app.config.email_from
error_msg = validate_email_str(email)
if not error_msg and self._can_access_dataset(user):
to += f", {email.strip()}"
@@ -255,4 +254,6 @@ class EmailErrorReporter(ErrorReporter):
except Exception:
pass
return util.send_mail(frm, to, subject, self.report, self.app.config, html=self.html_report)
return util.send_mail(
self.app.config.email_from, to, subject, self.report, self.app.config, html=self.html_report
)
+8
View File
@@ -3,6 +3,7 @@ import os
import pytest
from galaxy import config
from galaxy.config import DEFAULT_EMAIL_FROM_LOCAL_PART
from galaxy.util.properties import running_from_source
@@ -42,3 +43,10 @@ def test_base_config_if_running_not_from_source(monkeypatch):
assert appconfig.config_dir == os.getcwd()
assert appconfig.data_dir == os.path.join(appconfig.config_dir, "data")
assert appconfig.managed_config_dir == os.path.join(appconfig.data_dir, "config")
def test_assign_email_from(monkeypatch):
appconfig = config.GalaxyAppConfiguration(
override_tempdir=False, galaxy_infrastructure_url="http://myhost:8080/galaxy/"
)
assert appconfig.email_from == f"{DEFAULT_EMAIL_FROM_LOCAL_PART}@myhost"