Skip to content

Commit e763843

Browse files
Corrected URL encoding in the email template and updated unit tests and documentation
1 parent 010170c commit e763843

File tree

4 files changed

+24
-2
lines changed

4 files changed

+24
-2
lines changed

docs/customization.qmd

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,16 @@ Best practices dictate implementing thorough client-side validation via JavaScri
138138

139139
Server-side validation remains essential as a security measure against malicious requests that bypass client-side validation, but it should rarely be encountered during normal user interaction. See `templates/authentication/register.html` for a client-side form validation example involving both JavaScript and HTML regex `pattern` matching.
140140

141+
#### Email templating
142+
143+
Password reset and other transactional emails are also handled through Jinja2 templates, located in the `templates/emails` directory. The email templates follow the same inheritance pattern as web templates, with `base_email.html` providing the common layout and styling.
144+
145+
Here's how the default password reset email template looks:
146+
147+
![Default Password Reset Email Template](static/reset_email.png)
148+
149+
The email templates use inline CSS styles to ensure consistent rendering across email clients. Like web templates, they can receive context variables from the Python code (such as `reset_url` in the password reset template).
150+
141151
### Writing type annotated code
142152

143153
Pydantic is used for data validation and serialization. It ensures that the data received in requests meets the expected format and constraints. Pydantic models are used to define the structure of request and response data, making it easy to validate and parse JSON payloads.

docs/static/documentation.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,16 @@ Best practices dictate implementing thorough client-side validation via JavaScri
790790

791791
Server-side validation remains essential as a security measure against malicious requests that bypass client-side validation, but it should rarely be encountered during normal user interaction. See `templates/authentication/register.html` for a client-side form validation example involving both JavaScript and HTML regex `pattern` matching.
792792

793+
#### Email templating
794+
795+
Password reset and other transactional emails are also handled through Jinja2 templates, located in the `templates/emails` directory. The email templates follow the same inheritance pattern as web templates, with `base_email.html` providing the common layout and styling.
796+
797+
Here's how the default password reset email template looks:
798+
799+
![Default Password Reset Email Template](static/reset_email.png)
800+
801+
The email templates use inline CSS styles to ensure consistent rendering across email clients. Like web templates, they can receive context variables from the Python code (such as `reset_url` in the password reset template).
802+
793803
### Writing type annotated code
794804

795805
Pydantic is used for data validation and serialization. It ensures that the data received in requests meets the expected format and constraints. Pydantic models are used to define the structure of request and response data, making it easy to validate and parse JSON payloads.

docs/static/reset_email.png

55.4 KB
Loading

tests/test_authentication.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from unittest.mock import patch
77
import resend
88
from urllib.parse import urlparse, parse_qs
9+
from html import unescape
910

1011
from main import app
1112
from utils.models import User, PasswordResetToken
@@ -321,12 +322,13 @@ def test_password_reset_email_url(unauth_client: TestClient, session: Session, t
321322
mock_resend_send.assert_called_once()
322323
call_args = mock_resend_send.call_args[0][0]
323324
html_content = call_args["html"]
325+
print(html_content)
324326

325327
# Extract URL from HTML
326328
import re
327-
url_match = re.search(r'href=[\'"]([^\'"]*)[\'"]', html_content)
329+
url_match = re.search(r'<a[^>]*href=[\'"]([^\'"]*)[\'"]', html_content)
328330
assert url_match is not None
329-
reset_url = url_match.group(1)
331+
reset_url = unescape(url_match.group(1))
330332

331333
# Parse and verify the URL
332334
parsed = urlparse(reset_url)

0 commit comments

Comments
 (0)