Files
conference/init_db.py
T
paul 3b14155594 Fix attendee_types.code uniqueness: per-event not global
Also update generate_type_code() to accept event_id parameter
for proper per-event uniqueness checking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-29 14:45:27 +00:00

306 lines
11 KiB
Python

#!/usr/bin/env python3
"""Database initialization script for NetEvent platform."""
import mysql.connector
from mysql.connector import Error
DB_HOST = 'roast.duckdns.org'
DB_PORT = 33062
DB_USER = 'root'
DB_PASSWORD = 'Tiegl!!!111...'
DB_NAME = 'netevent'
APP_USER = 'netevent_app'
APP_PASSWORD = 'netevent_pass_2024'
def create_database():
"""Create the database and dedicated user."""
try:
conn = mysql.connector.connect(
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASSWORD
)
cursor = conn.cursor()
# Create database if not exists
cursor.execute(f"CREATE DATABASE IF NOT EXISTS {DB_NAME}")
print(f"Database '{DB_NAME}' created or already exists.")
# Create dedicated application user
cursor.execute(f"CREATE USER IF NOT EXISTS '{APP_USER}'@'%' IDENTIFIED BY '{APP_PASSWORD}'")
cursor.execute(f"GRANT ALL PRIVILEGES ON {DB_NAME}.* TO '{APP_USER}'@'%'")
cursor.execute("FLUSH PRIVILEGES")
print(f"User '{APP_USER}' created with privileges on '{DB_NAME}'.")
conn.commit()
cursor.close()
conn.close()
return True
except Error as e:
print(f"Error creating database/user: {e}")
return False
def create_tables():
"""Create all required tables."""
tables = [
"""
CREATE TABLE IF NOT EXISTS organizers (
id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
staff_code VARCHAR(10) UNIQUE DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""",
"""
CREATE TABLE IF NOT EXISTS events (
id INT PRIMARY KEY AUTO_INCREMENT,
organizer_id INT NOT NULL,
code VARCHAR(10) UNIQUE NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
start_time DATETIME NOT NULL,
end_time DATETIME,
location VARCHAR(255),
max_attendees INT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (organizer_id) REFERENCES organizers(id) ON DELETE CASCADE
)
""",
"""
CREATE TABLE IF NOT EXISTS attendees (
id INT PRIMARY KEY AUTO_INCREMENT,
event_id INT NOT NULL,
email VARCHAR(255) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
organisation VARCHAR(255),
role VARCHAR(255),
introduction TEXT,
profile_picture VARCHAR(255) DEFAULT NULL,
checked_in BOOLEAN DEFAULT FALSE,
attendance_status ENUM('attending', 'not_attending') DEFAULT 'attending',
confirmation_token VARCHAR(64) DEFAULT NULL,
attendee_code VARCHAR(10) UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE,
UNIQUE KEY unique_attendee_event (event_id, email)
)
""",
"""
CREATE TABLE IF NOT EXISTS connections (
id INT PRIMARY KEY AUTO_INCREMENT,
attendee_id INT NOT NULL,
connected_attendee_id INT NOT NULL,
status ENUM('pending', 'accepted', 'rejected') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (attendee_id) REFERENCES attendees(id) ON DELETE CASCADE,
FOREIGN KEY (connected_attendee_id) REFERENCES attendees(id) ON DELETE CASCADE,
UNIQUE KEY unique_connection (attendee_id, connected_attendee_id)
)
""",
"""
CREATE TABLE IF NOT EXISTS appointments (
id INT PRIMARY KEY AUTO_INCREMENT,
event_id INT NOT NULL,
requester_id INT NOT NULL,
target_id INT NOT NULL,
appointment_time DATETIME NOT NULL,
location VARCHAR(255),
notes TEXT,
status ENUM('pending', 'accepted', 'rejected') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE,
FOREIGN KEY (requester_id) REFERENCES attendees(id) ON DELETE CASCADE,
FOREIGN KEY (target_id) REFERENCES attendees(id) ON DELETE CASCADE
)
""",
"""
CREATE TABLE IF NOT EXISTS breakout_sessions (
id INT PRIMARY KEY AUTO_INCREMENT,
code VARCHAR(10) NOT NULL UNIQUE,
event_id INT NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
start_time DATETIME NOT NULL,
end_time DATETIME NOT NULL,
location VARCHAR(255),
max_attendees INT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE
)
""",
"""
CREATE TABLE IF NOT EXISTS breakout_session_organizers (
id INT PRIMARY KEY AUTO_INCREMENT,
breakout_session_id INT NOT NULL,
organizer_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (breakout_session_id) REFERENCES breakout_sessions(id) ON DELETE CASCADE,
FOREIGN KEY (organizer_id) REFERENCES organizers(id) ON DELETE CASCADE,
UNIQUE KEY unique_session_organizer (breakout_session_id, organizer_id)
)
""",
"""
CREATE TABLE IF NOT EXISTS breakout_session_rsvps (
id INT PRIMARY KEY AUTO_INCREMENT,
breakout_session_id INT NOT NULL,
attendee_id INT NOT NULL,
status ENUM('registered', 'cancelled') DEFAULT 'registered',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (breakout_session_id) REFERENCES breakout_sessions(id) ON DELETE CASCADE,
FOREIGN KEY (attendee_id) REFERENCES attendees(id) ON DELETE CASCADE,
UNIQUE KEY unique_rsvp (breakout_session_id, attendee_id)
)
""",
"""
CREATE TABLE IF NOT EXISTS staff (
id INT PRIMARY KEY AUTO_INCREMENT,
event_id INT NOT NULL,
email VARCHAR(255) NOT NULL,
password_hash VARCHAR(255) DEFAULT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
staff_code VARCHAR(10) UNIQUE DEFAULT NULL,
invite_token VARCHAR(64) DEFAULT NULL,
invite_used BOOLEAN DEFAULT FALSE,
preferred_language VARCHAR(5) DEFAULT 'en',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE,
UNIQUE KEY unique_staff_event (event_id, email)
)
""",
# Languages table
"""
CREATE TABLE IF NOT EXISTS languages (
code VARCHAR(5) PRIMARY KEY,
name VARCHAR(50) NOT NULL,
native_name VARCHAR(50) NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
is_default BOOLEAN DEFAULT FALSE,
date_format VARCHAR(30) DEFAULT '%B %d, %Y at %H:%M',
sort_order INT DEFAULT 0
)
""",
"""
CREATE TABLE IF NOT EXISTS attendee_types (
id INT PRIMARY KEY AUTO_INCREMENT,
event_id INT NOT NULL,
code VARCHAR(10) NOT NULL,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) DEFAULT 0.00,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE,
UNIQUE KEY unique_type_code_per_event (event_id, code)
)
"""
]
# Alter existing tables to add preferred_language column
alter_statements = [
"ALTER TABLE organizers ADD COLUMN preferred_language VARCHAR(5) DEFAULT 'en'",
"ALTER TABLE attendees ADD COLUMN preferred_language VARCHAR(5) DEFAULT 'en'",
"ALTER TABLE attendees ADD COLUMN attendee_code VARCHAR(10) UNIQUE",
"ALTER TABLE attendees ADD COLUMN phone VARCHAR(50) DEFAULT ''",
"ALTER TABLE attendees ADD COLUMN linkedin VARCHAR(255) DEFAULT ''",
"ALTER TABLE attendees ADD COLUMN attendee_type_id INT DEFAULT NULL",
]
try:
conn = mysql.connector.connect(
host=DB_HOST,
port=DB_PORT,
user=APP_USER,
password=APP_PASSWORD,
database=DB_NAME
)
cursor = conn.cursor()
for table_sql in tables:
cursor.execute(table_sql)
# Alter existing tables
for alter_sql in alter_statements:
try:
cursor.execute(alter_sql)
except Error as e:
# Column might already exist
if e.errno != 1060: # Duplicate column name
print(f"Warning: {e}")
# Add foreign key constraint for attendee_type_id
try:
cursor.execute("""
ALTER TABLE attendees
ADD CONSTRAINT fk_attendee_type
FOREIGN KEY (attendee_type_id) REFERENCES attendee_types(id) ON DELETE SET NULL
""")
except Error as e:
if e.errno != 1060 and e.errno != 1826: # Not duplicate column or duplicate FK
print(f"Warning adding FK: {e}")
conn.commit()
cursor.close()
conn.close()
print("All tables created successfully.")
return True
except Error as e:
print(f"Error creating tables: {e}")
return False
def seed_languages():
"""Seed the languages table with EU languages."""
languages = [
('en', 'English', 'English', True, True, '%B %d, %Y at %H:%M', 1),
('nl', 'Dutch', 'Nederlands', True, False, '%d %B %Y om %H:%M', 2),
('de', 'German', 'Deutsch', True, False, '%d. %B %Y um %H:%M', 3),
('fr', 'French', 'Français', True, False, '%d %B %Y à %H:%M', 4),
('es', 'Spanish', 'Español', True, False, '%d de %B de %Y a las %H:%M', 5),
('it', 'Italian', 'Italiano', True, False, '%d %B %Y alle %H:%M', 6),
('pl', 'Polish', 'Polski', True, False, '%d %B %Y o %H:%M', 7),
]
try:
conn = mysql.connector.connect(
host=DB_HOST,
port=DB_PORT,
user=APP_USER,
password=APP_PASSWORD,
database=DB_NAME
)
cursor = conn.cursor()
for lang in languages:
cursor.execute("""
INSERT IGNORE INTO languages (code, name, native_name, is_active, is_default, date_format, sort_order)
VALUES (%s, %s, %s, %s, %s, %s, %s)
""", lang)
conn.commit()
cursor.close()
conn.close()
print("Languages seeded successfully.")
return True
except Error as e:
print(f"Error seeding languages: {e}")
return False
def init_database():
"""Initialize the complete database."""
print("Initializing NetEvent database...")
if create_database():
if create_tables():
seed_languages()
print("Database initialization complete!")
return True
print("Database initialization failed.")
return False
if __name__ == '__main__':
init_database()