Skip to content

Commit 3da922a

Browse files
committed
support for custom email templates
1 parent f15ce99 commit 3da922a

File tree

7 files changed

+39
-13
lines changed

7 files changed

+39
-13
lines changed

docs/source/usage/alerts.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ After that you can receive e-mails on job finish/failure.
3737

3838
|alert_email|
3939

40+
You can modify the email templates by setting the :code:`Template Directory` in your system config. If you want to do so - copy `the existing templates <https://github.com/ansibleguy/webui/tree/latest/src/ansibleguy-webui/aw/templates/email>`_ and modify them as needed. Note: the `Django template syntax <https://docs.djangoproject.com/en/5.0/ref/templates/language/>`_ is required.
41+
4042
----
4143

4244
Plugins
@@ -63,7 +65,7 @@ There is a generic alert-plugin interface for custom solutions.
6365
"name": "ansible",
6466
"first_name": "",
6567
"last_name": "",
66-
"email": "[email protected]",
68+
"email": "ansible@localhost",
6769
"phone": null,
6870
"description": "test",
6971
"is_active": true,

src/ansibleguy-webui/aw/config/defaults.py

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def _get_defaults_docker(var: str) -> any:
4141
'path_run': '/tmp/ansible-webui',
4242
'path_play': getcwd(),
4343
'path_log': f"{environ['HOME']}/.local/share/ansible-webui",
44+
'path_template': None, # only for custom overrides
4445
'db': f"{environ['HOME']}/.config/ansible-webui",
4546
'timezone': datetime.now().astimezone().tzname(),
4647
'secret': ''.join(random_choice(ascii_letters + digits + punctuation) for _ in range(50)),

src/ansibleguy-webui/aw/config/form_metadata.py

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
'path_run': 'Runtime directory',
7474
'path_play': 'Playbook base-directory',
7575
'path_log': 'Directory for execution-logs',
76+
'path_template': 'Directory for templates',
7677
'run_timeout': 'Timeout for playbook execution',
7778
'session_timeout': 'Timeout for WebUI login-sessions',
7879
'path_ansible_config': 'Ansible Config-File',
@@ -200,6 +201,7 @@
200201
'path_play': 'Path to the <a href="https://docs.ansible.com/ansible/2.8/user_guide/'
201202
'playbooks_best_practices.html#directory-layout">Ansible base/playbook directory</a>',
202203
'path_log': 'Define the path where full job-logs are saved',
204+
'path_template': 'Define the path where custom templates are placed',
203205
'path_ansible_config': 'Path to a <a href="https://docs.ansible.com/ansible/latest/installation_guide'
204206
'/intro_configuration.html#configuration-file">Ansible config-file</a> to use',
205207
'path_ssh_known_hosts': 'Path to a <a href="https://en.wikibooks.org/wiki/OpenSSH/'

src/ansibleguy-webui/aw/execute/alert_plugin/plugin_email.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from django.template.loader import get_template
88

99
from aw.base import USERS
10-
from aw.utils.util import valid_email
10+
from aw.utils.util import valid_email, is_set
1111
from aw.utils.debug import log
1212
from aw.config.main import config
1313
from aw.model.job import JobExecution
@@ -22,9 +22,20 @@ def _email_send(server: SMTP, user: USERS, stats: dict, execution: JobExecution,
2222
msg['From'] = config['mail_sender']
2323
msg['To'] = user.email
2424

25+
tmpl_html, tmpl_text = 'email/alert.html', 'email/alert.txt'
26+
if is_set(config['path_template']):
27+
_tmpl_base = Path(config['path_template'])
28+
_tmpl_html = _tmpl_base / 'alert.html'
29+
_tmpl_text = _tmpl_base / 'alert.txt'
30+
if _tmpl_html.is_file():
31+
tmpl_html = str(_tmpl_html)
32+
33+
if _tmpl_text.is_file():
34+
tmpl_text = str(_tmpl_text)
35+
2536
tmpl_ctx = {'execution': execution, 'stats': stats, 'web_addr': get_main_web_address(), 'error_msgs': error_msgs}
26-
text_content = get_template('email/alert.txt').render(tmpl_ctx)
27-
html_content = get_template('email/alert.html').render(tmpl_ctx)
37+
text_content = get_template(tmpl_text).render(tmpl_ctx)
38+
html_content = get_template(tmpl_html).render(tmpl_ctx)
2839

2940
msg.attach(MIMEText(text_content, 'plain'))
3041
msg.attach(MIMEText(html_content, 'html'))

src/ansibleguy-webui/aw/model/system.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
class SystemConfig(BaseModel):
2525
SECRET_ATTRS = ['mail_pass']
2626
api_fields_read = [
27-
'path_run', 'path_play', 'path_log', 'timezone', 'run_timeout', 'session_timeout', 'path_ansible_config',
28-
'path_ssh_known_hosts', 'debug', 'logo_url', 'ara_server', 'global_environment_vars',
27+
'path_run', 'path_play', 'path_log', 'path_template', 'timezone', 'run_timeout', 'session_timeout',
28+
'path_ansible_config', 'path_ssh_known_hosts', 'debug', 'logo_url', 'ara_server', 'global_environment_vars',
2929
'mail_server', 'mail_transport', 'mail_ssl_verify', 'mail_sender', 'mail_user',
3030
]
3131

@@ -38,6 +38,7 @@ class SystemConfig(BaseModel):
3838
path_run = models.CharField(max_length=500, default='/tmp/ansible-webui')
3939
path_play = models.CharField(max_length=500, default=None)
4040
path_log = models.CharField(max_length=500, default=None)
41+
path_template = models.CharField(max_length=500, **DEFAULT_NONE)
4142
timezone = models.CharField(max_length=300, default='UTC') # UTC to keep model migrations static
4243
run_timeout = models.PositiveIntegerField(default=CONFIG_DEFAULTS['run_timeout'])
4344
session_timeout = models.PositiveIntegerField(default=CONFIG_DEFAULTS['session_timeout'])

src/ansibleguy-webui/aw/templates/settings/alert.html

+1-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ <h2>Group Alerts</h2>
5353
</tr>
5454
<tr>
5555
<td colspan="100%">
56-
{% include "../button/refresh.html" %}
5756
<a href="/ui/settings/alerts/group/0">
5857
<button class="btn btn-success aw-btn-action" title="Add Group Alert">
5958
{% include "../button/icon/add.html" %}
@@ -86,7 +85,6 @@ <h2>Global Alerts</h2>
8685
</tr>
8786
<tr>
8887
<td colspan="100%">
89-
{% include "../button/refresh.html" %}
9088
<a href="/ui/settings/alerts/global/0">
9189
<button class="btn btn-success aw-btn-action" title="Add Global Alert">
9290
{% include "../button/icon/add.html" %}
@@ -117,12 +115,12 @@ <h2>Alert Plugins</h2>
117115
</tr>
118116
<tr>
119117
<td colspan="100%">
120-
{% include "../button/refresh.html" %}
121118
<a href="/ui/settings/alerts/plugin/0">
122119
<button class="btn btn-success aw-btn-action" title="Add Alert-Plugin">
123120
{% include "../button/icon/add.html" %}
124121
</button>
125122
</a>
123+
{% include "../button/refresh.html" %}
126124
</td>
127125
</tr>
128126
<tr id="aw-api-data-tmpl-row2" hidden="hidden">

src/ansibleguy-webui/aw/views/forms/system.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,31 @@ class Meta:
2222
labels = FORM_LABEL['system']['config']
2323
help_texts = FORM_HELP['system']['config']
2424

25-
path_run = forms.CharField(max_length=500, initial=CONFIG_DEFAULTS['path_run'], required=True)
26-
path_play = forms.CharField(max_length=500, initial=CONFIG_DEFAULTS['path_play'], required=True)
27-
path_log = forms.CharField(max_length=500, initial=CONFIG_DEFAULTS['path_log'], required=True)
25+
path_run = forms.CharField(
26+
max_length=500, initial=CONFIG_DEFAULTS['path_run'], required=True,
27+
label=Meta.labels['path_run'],
28+
)
29+
path_play = forms.CharField(
30+
max_length=500, initial=CONFIG_DEFAULTS['path_play'], required=True,
31+
label=Meta.labels['path_play'],
32+
)
33+
path_log = forms.CharField(
34+
max_length=500, initial=CONFIG_DEFAULTS['path_log'], required=True,
35+
label=Meta.labels['path_log'],
36+
)
2837
path_ansible_config = forms.CharField(
2938
max_length=500, initial=CONFIG_DEFAULTS['path_ansible_config'], required=False,
39+
label=Meta.labels['path_ansible_config'],
3040
)
3141
path_ssh_known_hosts = forms.CharField(
3242
max_length=500, initial=CONFIG_DEFAULTS['path_ssh_known_hosts'], required=False,
43+
label=Meta.labels['path_ssh_known_hosts'],
3344
)
3445
timezone = forms.ChoiceField(
3546
required=False,
3647
widget=forms.Select,
3748
choices=[(tz, tz) for tz in sorted(all_timezones)],
38-
label=FORM_LABEL['system']['config']['timezone'],
49+
label=Meta.labels['timezone'],
3950
)
4051
debug = forms.ChoiceField(
4152
initial=CONFIG_DEFAULTS['debug'] or deployment_dev(), choices=CHOICES_BOOL,

0 commit comments

Comments
 (0)