from __future__ import annotations from datetime import datetime import pytest from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from backend.models import Base, User from backend.services.email_service import EmailService from backend.services.email_templates import ( EmailTemplate, EmailTemplateRenderError, SafeHtml, render_email_template, ) def test_registration_template_escapes_dynamic_values_and_uses_shared_layout() -> None: html = render_email_template( EmailTemplate.NEW_USER_REGISTRATION, { "user_alias": "", "user_id": "42", "created_time": "2026-05-05 10:00:00", "admin_url": "https://example.test/admin/users?x=1&y=2", }, ) assert '
" not in html assert "https://example.test/admin/users?x=1&y=2" in html def test_template_renderer_fails_clearly_when_context_is_missing() -> None: with pytest.raises(EmailTemplateRenderError, match="created_time"): render_email_template( EmailTemplate.NEW_USER_REGISTRATION, { "user_alias": "Alice", "user_id": "42", "admin_url": "https://example.test/admin/users", }, ) def test_template_renderer_allows_trusted_html_snippets() -> None: html = render_email_template( EmailTemplate.USER_REJECTED, { "user_alias": "Alice", "processed_time": "2026-05-05 10:00:00", "reason_section": SafeHtml("

拒绝原因:资料不完整

"), }, ) assert "拒绝原因:资料不完整" in html def test_template_renderer_defaults_footer_year_to_current_year() -> None: html = render_email_template( EmailTemplate.TOKEN_EXPIRED, { "user_alias": "Alice", "login_url": "https://example.test/login", }, ) assert str(datetime.now().year) in html @pytest.mark.parametrize( ("template", "context", "expected"), [ ( EmailTemplate.USER_APPROVED, { "user_alias": "Alice", "user_role": "user", "created_time": "2026-05-01 09:00:00", "approved_time": "2026-05-05 10:00:00", "login_url": "https://example.test/login", }, "账户审批通过", ), ( EmailTemplate.USER_REJECTED, { "user_alias": "Alice", "processed_time": "2026-05-05 10:00:00", "reason_section": "

拒绝原因:资料不完整

", }, "未通过", ), ( EmailTemplate.TOKEN_EXPIRING, { "user_alias": "Alice", "minutes_left": "25", }, "25 分钟", ), ( EmailTemplate.TOKEN_EXPIRED, { "user_alias": "Alice", "login_url": "https://example.test/login", }, "登录凭证已过期", ), ( EmailTemplate.CHECK_IN_RESULT, { "user_alias": "Alice", "executed_time": "2026-05-05 10:00:00", "thread_id": "thread-1", "status_text": "失败", "status_color": "#b91c1c", "message_row": "失败原因Token 失效", "guidance_section": "

请刷新 Token。

", }, "thread-1", ), ], ) def test_supported_notification_templates_render_shared_layout( template: EmailTemplate, context: dict[str, str], expected: str ) -> None: html = render_email_template(template, context) assert '