Skip to content

Commit fb875ba

Browse files
committed
Added: test email yaml function (#284)
1 parent 580fbd4 commit fb875ba

File tree

2 files changed

+89
-10
lines changed

2 files changed

+89
-10
lines changed

libreforms_fastapi/app/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3272,7 +3272,7 @@ async def api_admin_create_user(
32723272
if config.SMTP_ENABLED:
32733273

32743274
subject, content = render_email_message_from_jinja(
3275-
'user_registered',
3275+
'user_registered_admin',
32763276
config=config,
32773277
username=new_username,
32783278
)

libreforms_fastapi/utils/jinja_emails.py

+88-9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
from jinja2 import Template, UndefinedError, Environment, make_logging_undefined, select_autoescape
1+
import yaml
2+
from jinja2 import Template, Undefined, Environment, make_logging_undefined, select_autoescape
23

34

4-
class RaiseExceptionUndefined(make_logging_undefined(base=UndefinedError)):
5-
"""This exception will raise when admins invoke a context in an email template that is not available"""
6-
def _fail_with_undefined_error(self, *args, **kwargs):
7-
raise UndefinedError(f"{self._undefined_name} is undefined but is required for rendering the email template.")
5+
class RaiseExceptionUndefined(Undefined):
6+
"""This exception will raise when admins invoke a context in an email template that is not available."""
7+
def _fail_with_undefined_error(self):
8+
raise Exception(f"{self._undefined_name} is undefined but is required for rendering the email template.")
9+
10+
# Override the __getattr__ to raise error when accessing undefined attributes
11+
def __getattr__(self, name):
12+
self._fail_with_undefined_error()
13+
14+
# Override other methods that should raise an exception when dealing with undefined
15+
def __str__(self):
16+
self._fail_with_undefined_error()
17+
818

919

1020
# Here we create a jinja env and pass our custom undefined exception
@@ -62,10 +72,14 @@ def _fail_with_undefined_error(self, *args, **kwargs):
6272
'cont': "This email serves to notify you that the user {{ user.username }} has just successfully reset their password at {{ config.DOMAIN }}. If you believe this was a mistake, please contact your system administrator.",
6373
},
6474

65-
'user_registered': {
75+
'user_registered_admin': {
6676
'subj': "{{ config.SITE_NAME }} User Registered",
6777
'cont': "This email serves to notify you that the user {{ username }} has just been registered for this email address at {{ config.DOMAIN }}. Your user has been given the following temporary password:\n\n{{ password }}\n\nPlease login to the system and update this password at your earliest convenience.",
6878
},
79+
'user_registered': {
80+
'subj': "{{ config.SITE_NAME }} User Registered",
81+
'cont': "This email serves to notify you that the user {{ username }} has just been registered for this email address at {{ config.DOMAIN }}.",
82+
},
6983

7084
'user_registered_verification': {
7185
'subj': "{{ config.SITE_NAME }} User Registered",
@@ -79,11 +93,9 @@ def _fail_with_undefined_error(self, *args, **kwargs):
7993
'subj': "Help Request from {{ user.username }}",
8094
'cont': "You are receiving this message because a user has submitted a request for help at {{ config.DOMAIN }}. You can see the request details below.\n\n****\nUser: {{ user.username }}\nEmail: {{ user.email }}\nTime of Submission: {{ time }}\nCategory: {{ category }}\nSubject: {{ subject }}\nMessage: {{ message }}\n****\n\nYou may reply directly to the user who submitted this request by replying to this email."
8195
},
82-
8396
}
8497

8598

86-
8799
EXAMPLE_EMAIL_CONFIG_YAML = '''
88100
transaction_log_error:
89101
subj: "Transaction Log Error"
@@ -137,14 +149,18 @@ def _fail_with_undefined_error(self, *args, **kwargs):
137149
subj: "{{ config.SITE_NAME }} User Password Reset"
138150
cont: |
139151
This email serves to notify you that the user {{ user.username }} has just successfully reset their password at {{ config.DOMAIN }}. If you believe this was a mistake, please contact your system administrator.
140-
user_registered:
152+
user_registered_admin:
141153
subj: "{{ config.SITE_NAME }} User Registered"
142154
cont: |
143155
This email serves to notify you that the user {{ username }} has just been registered for this email address at {{ config.DOMAIN }}. Your user has been given the following temporary password:
144156
145157
{{ password }}
146158
147159
Please login to the system and update this password at your earliest convenience.
160+
user_registered:
161+
subj: "{{ config.SITE_NAME }} User Registered"
162+
cont: |
163+
This email serves to notify you that the user {{ username }} has just been registered for this email address at {{ config.DOMAIN }}.
148164
user_registered_verification:
149165
subj: "{{ config.SITE_NAME }} User Registered"
150166
cont: |
@@ -171,6 +187,8 @@ def _fail_with_undefined_error(self, *args, **kwargs):
171187
'''
172188

173189

190+
191+
174192
def get_message_jinja(message_type):
175193
# Retrieve the unrendered Jinja templates from the dictionary
176194
subj_template_str = default_templates[message_type]['subj']
@@ -195,3 +213,64 @@ def render_email_message_from_jinja(message_type, **kwargs):
195213
rendered_cont = template_cont.render(**kwargs)
196214

197215
return rendered_subj, rendered_cont
216+
217+
218+
def test_email_config(email_config_yaml, **kwargs):
219+
# Load the YAML configuration into a Python dictionary
220+
email_configs = safe_load(email_config_yaml)
221+
222+
# Set default values for parameters
223+
defaults = {
224+
'config': {'SITE_NAME': 'ExampleSite', 'DOMAIN': 'example.com'},
225+
'user': {'username': 'default_user', 'opt_out': False},
226+
'current_time': '2022-07-01 12:00:00',
227+
'endpoint': '/default/endpoint',
228+
'query_params': 'default=query',
229+
'remote_addr': '192.168.0.1',
230+
'document_id': 'default_doc_id',
231+
'form_name': 'default_form_name',
232+
'otp': '123456',
233+
'time': '12:00 PM',
234+
'category': 'General Inquiry',
235+
'subject': 'Default Subject',
236+
'message': 'Default Message',
237+
'key': 'default_key',
238+
'password': 'tempPassword123'
239+
}
240+
241+
# Update defaults with any additional provided parameters
242+
defaults.update(kwargs)
243+
244+
# Iterate through each email type in the configuration
245+
for email_type, template_data in email_configs.items():
246+
247+
# We create a copy of defaults so we can remove some context
248+
# that is not available to certain events
249+
modified_defaults = defaults.copy()
250+
251+
# We remove form details here because
252+
if email_type in ['transaction_log_error', 'api_key_rotation', 'user_password_changed', 'password_reset_instructions', 'password_reset_complete', 'user_registered', 'user_registered_verification', 'suspicious_activity', 'help_request']:
253+
254+
modified_defaults.pop('document_id')
255+
modified_defaults.pop('form_name')
256+
257+
if email_type != 'user_registered_verification':
258+
modified_defaults.pop('key')
259+
260+
if email_type != 'password_reset_instructions':
261+
modified_defaults.pop('otp')
262+
263+
if email_type != 'user_registered_admin':
264+
modified_defaults.pop('password')
265+
266+
267+
268+
subj_template = env.from_string(template_data['subj'])
269+
cont_template = env.from_string(template_data['cont'])
270+
271+
# Render the subject and content templates without try-except block
272+
rendered_subj = subj_template.render(**modified_defaults)
273+
rendered_cont = cont_template.render(**modified_defaults)
274+
# print(f"Successfully rendered '{email_type}':\nSubject: {rendered_subj}\nContent: {rendered_cont[:60]}...")
275+
276+
return True

0 commit comments

Comments
 (0)