feat: add email-based authentication

This commit is contained in:
2026-08-03 18:49:08 +08:00
parent 82a8b4187a
commit f2209a0e00
19 changed files with 641 additions and 1555 deletions
+58
View File
@@ -0,0 +1,58 @@
from __future__ import annotations
import unittest
from tempfile import TemporaryDirectory
from unittest.mock import patch
from app import create_app
from app.config import Config
from app.email import EmailConfigurationError, send_transactional_email
class TransactionalEmailTest(unittest.TestCase):
def create_test_app(self, temp_dir: str, *, configured: bool):
class TestConfig(Config):
TESTING = True
SECRET_KEY = "test-secret"
SECRET_KEY_GENERATED = False
SQLALCHEMY_DATABASE_URI = f"sqlite:///{temp_dir}/test.db"
ADMIN_PASSWORD = None
RESEND_API_KEY = "re_test_key" if configured else ""
RESEND_FROM_EMAIL = "no-reply@auth.example.com" if configured else ""
return create_app(TestConfig, load_model_on_start=False)
def test_send_requires_resend_configuration(self) -> None:
with TemporaryDirectory() as temp_dir:
app = self.create_test_app(temp_dir, configured=False)
with app.app_context(), self.assertRaises(EmailConfigurationError):
send_transactional_email(
to="user@example.com",
subject="测试",
html="<p>测试</p>",
)
@patch("app.email.resend.Emails.send", return_value={"id": "email_123"})
def test_send_uses_configured_sender(self, send):
with TemporaryDirectory() as temp_dir:
app = self.create_test_app(temp_dir, configured=True)
with app.app_context():
result = send_transactional_email(
to="user@example.com",
subject="密码重置",
html="<p>重置链接</p>",
)
self.assertEqual(result, {"id": "email_123"})
send.assert_called_once_with(
{
"from": "no-reply@auth.example.com",
"to": ["user@example.com"],
"subject": "密码重置",
"html": "<p>重置链接</p>",
}
)
if __name__ == "__main__":
unittest.main()