From e95270d67a558310933634c91f62ff24363632be Mon Sep 17 00:00:00 2001 From: Ghanshyam Singh Date: Wed, 3 Jun 2026 21:26:38 +0530 Subject: [PATCH 1/2] Apply email verification schema migration to D1 --- migrations/0003_add_email_verification.sql | 27 ++++++++++++++++++++++ src/worker.py | 11 --------- 2 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 migrations/0003_add_email_verification.sql diff --git a/migrations/0003_add_email_verification.sql b/migrations/0003_add_email_verification.sql new file mode 100644 index 0000000..8d589bd --- /dev/null +++ b/migrations/0003_add_email_verification.sql @@ -0,0 +1,27 @@ +-- Migration 0003: Add email verification support + +-- Add email_verified column to users (existing users are grandfathered as verified) +ALTER TABLE users ADD COLUMN email_verified INTEGER NOT NULL DEFAULT 0; +UPDATE users SET email_verified = 1; + +-- Email verification tokens table +CREATE TABLE IF NOT EXISTS email_verification_tokens ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL, + token_hash TEXT NOT NULL UNIQUE, + expires_at TEXT NOT NULL, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +); + +CREATE INDEX IF NOT EXISTS idx_evtoken_user ON email_verification_tokens(user_id); + +CREATE TABLE IF NOT EXISTS password_reset_tokens ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL, + token_hash TEXT NOT NULL UNIQUE, + expires_at TEXT NOT NULL, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS idx_prtoken_user ON password_reset_tokens(user_id); \ No newline at end of file diff --git a/src/worker.py b/src/worker.py index f274a07..51174a3 100644 --- a/src/worker.py +++ b/src/worker.py @@ -726,17 +726,6 @@ async def send_password_reset_email(to_email: str, _username: str, token: str, e async def init_db(env): for sql in _DDL: await env.DB.prepare(sql).run() - # Idempotent migration: add email_verified to existing users table. - # Fails silently when the column already exists (second run is a no-op). - try: - await env.DB.prepare( - "ALTER TABLE users ADD COLUMN email_verified INTEGER NOT NULL DEFAULT 0" - ).run() - # Pre-existing accounts are treated as verified (registered before this feature). - await env.DB.prepare("UPDATE users SET email_verified=1").run() - print("[init_db] email_verified column added successfully") - except Exception as e: - print(f"[init_db] email_verified migration skipped (likely already exists): {e}") _NO_SUCH_TABLE_RE = re.compile(r"\bno such table\b", re.IGNORECASE) From b79ccd852e45409e0b633b1f3bdb1269579e3243 Mon Sep 17 00:00:00 2001 From: Ghanshyam Singh Date: Wed, 3 Jun 2026 21:33:34 +0530 Subject: [PATCH 2/2] Apply email verification schema migration to D1 --- src/worker.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/worker.py b/src/worker.py index 51174a3..f274a07 100644 --- a/src/worker.py +++ b/src/worker.py @@ -726,6 +726,17 @@ async def send_password_reset_email(to_email: str, _username: str, token: str, e async def init_db(env): for sql in _DDL: await env.DB.prepare(sql).run() + # Idempotent migration: add email_verified to existing users table. + # Fails silently when the column already exists (second run is a no-op). + try: + await env.DB.prepare( + "ALTER TABLE users ADD COLUMN email_verified INTEGER NOT NULL DEFAULT 0" + ).run() + # Pre-existing accounts are treated as verified (registered before this feature). + await env.DB.prepare("UPDATE users SET email_verified=1").run() + print("[init_db] email_verified column added successfully") + except Exception as e: + print(f"[init_db] email_verified migration skipped (likely already exists): {e}") _NO_SUCH_TABLE_RE = re.compile(r"\bno such table\b", re.IGNORECASE)