#!/bin/python3 import sqlite3 from pathlib import Path DB_NAME = Path(__file__).parent / "calendar.db" conn = sqlite3.connect(DB_NAME) conn.execute("PRAGMA foreign_keys = ON;") cur = conn.cursor() cur.execute(""" CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, email TEXT UNIQUE, email_verified INTEGER NOT NULL DEFAULT 0, password_hash TEXT NOT NULL ); """) cur.execute(""" CREATE TABLE IF NOT EXISTS email_verifications ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, token_hash TEXT NOT NULL UNIQUE, expires_at TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ); """) cur.execute(""" CREATE TABLE IF NOT EXISTS password_reset_tokens ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, token_hash TEXT NOT NULL UNIQUE, expires_at TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ); """) cur.execute(""" CREATE TABLE IF NOT EXISTS rooms ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, owner_id INTEGER NOT NULL, invite_code TEXT NOT NULL UNIQUE, FOREIGN KEY (owner_id) REFERENCES users(id) ); """) cur.execute(""" CREATE TABLE IF NOT EXISTS room_members ( room_id INTEGER NOT NULL, user_id INTEGER NOT NULL, role TEXT NOT NULL DEFAULT 'member' CHECK(role IN ('owner', 'admin', 'member')), PRIMARY KEY (room_id, user_id), FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ); """) cur.execute(""" CREATE TABLE IF NOT EXISTS events ( id INTEGER PRIMARY KEY AUTOINCREMENT, room_id INTEGER NOT NULL, creator_id INTEGER NOT NULL, type TEXT NOT NULL CHECK(type IN ('private', 'busy', 'proposal')), title TEXT NOT NULL, description TEXT, start_time TEXT NOT NULL, end_time TEXT NOT NULL, visibility TEXT NOT NULL CHECK(visibility IN ('private', 'busy_only', 'room')), status TEXT NOT NULL DEFAULT 'draft' CHECK(status IN ('draft', 'proposed', 'confirmed', 'cancelled')), min_people INTEGER DEFAULT 0, invitation_mode TEXT NOT NULL DEFAULT 'room' CHECK(invitation_mode IN ('room', 'custom')), FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE, FOREIGN KEY (creator_id) REFERENCES users(id) ); """) cur.execute(""" CREATE TABLE IF NOT EXISTS event_invitations ( event_id INTEGER NOT NULL, user_id INTEGER NOT NULL, status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'accepted', 'declined')), created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (event_id, user_id), FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ); """) cur.execute(""" CREATE TABLE IF NOT EXISTS event_signups ( event_id INTEGER NOT NULL, user_id INTEGER NOT NULL, status TEXT NOT NULL DEFAULT 'going' CHECK(status IN ('going', 'maybe', 'declined')), PRIMARY KEY (event_id, user_id), FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ); """) cur.execute(""" CREATE INDEX IF NOT EXISTS idx_room_members_user ON room_members(user_id); """) cur.execute(""" CREATE INDEX IF NOT EXISTS idx_events_room ON events(room_id); """) cur.execute(""" CREATE INDEX IF NOT EXISTS idx_event_invitations_user ON event_invitations(user_id); """) cur.execute(""" CREATE INDEX IF NOT EXISTS idx_event_invitations_event ON event_invitations(event_id); """) cur.execute(""" CREATE INDEX IF NOT EXISTS idx_event_signups_user ON event_signups(user_id); """) cur.execute(""" CREATE INDEX IF NOT EXISTS idx_email_verifications_user ON email_verifications(user_id); """) cur.execute(""" CREATE INDEX IF NOT EXISTS idx_password_reset_tokens_user ON password_reset_tokens(user_id); """) conn.commit() print("Database initialized.") print(f"Database: {DB_NAME}") print("Tables:") for row in cur.execute(""" SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name; """): print(" -", row[0]) conn.close()