chore: include authentication services
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
import resend
|
||||
from flask import current_app
|
||||
|
||||
|
||||
class EmailConfigurationError(RuntimeError):
|
||||
"""Raised when transactional email has not been configured."""
|
||||
|
||||
|
||||
class EmailDeliveryError(RuntimeError):
|
||||
"""Raised when Resend rejects or cannot deliver an email request."""
|
||||
|
||||
|
||||
def send_transactional_email(*, to: str, subject: str, html: str) -> dict[str, Any]:
|
||||
"""Send one application-generated email through Resend."""
|
||||
api_key = current_app.config["RESEND_API_KEY"]
|
||||
from_email = current_app.config["RESEND_FROM_EMAIL"]
|
||||
if not api_key or not from_email:
|
||||
raise EmailConfigurationError(
|
||||
"邮件服务尚未配置,请设置 RESEND_API_KEY 和 RESEND_FROM_EMAIL。"
|
||||
)
|
||||
|
||||
resend.api_key = api_key
|
||||
try:
|
||||
return resend.Emails.send(
|
||||
{
|
||||
"from": from_email,
|
||||
"to": [to],
|
||||
"subject": subject,
|
||||
"html": html,
|
||||
}
|
||||
)
|
||||
except Exception as exc:
|
||||
logging.exception("Resend 邮件发送失败: %s", exc)
|
||||
raise EmailDeliveryError("邮件发送失败,请稍后重试。") from exc
|
||||
@@ -0,0 +1,22 @@
|
||||
"""Small, dependency-free schema migrations for the deployed SQLite database."""
|
||||
from sqlalchemy import inspect, text
|
||||
|
||||
from .extensions import db
|
||||
|
||||
|
||||
def upgrade_schema() -> None:
|
||||
"""Create new tables and add authentication columns without losing existing data."""
|
||||
db.create_all()
|
||||
inspector = inspect(db.engine)
|
||||
columns = {item["name"] for item in inspector.get_columns("users")}
|
||||
additions = {
|
||||
"email": "VARCHAR(254)",
|
||||
"email_verified_at": "DATETIME",
|
||||
"is_active_account": "BOOLEAN NOT NULL DEFAULT 0",
|
||||
"auth_version": "INTEGER NOT NULL DEFAULT 1",
|
||||
}
|
||||
for name, sql_type in additions.items():
|
||||
if name not in columns:
|
||||
db.session.execute(text(f"ALTER TABLE users ADD COLUMN {name} {sql_type}"))
|
||||
db.session.execute(text("CREATE UNIQUE INDEX IF NOT EXISTS ix_users_email_unique ON users (email) WHERE email IS NOT NULL"))
|
||||
db.session.commit()
|
||||
Reference in New Issue
Block a user