172 lines
5.3 KiB
JavaScript
172 lines
5.3 KiB
JavaScript
|
|
const { Pool } = require('pg');
|
||
|
|
|
||
|
|
const pool = new Pool({
|
||
|
|
connectionString: process.env.DATABASE_URL,
|
||
|
|
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
|
||
|
|
});
|
||
|
|
|
||
|
|
export default async function handler(req, res) {
|
||
|
|
if (req.method !== 'POST') {
|
||
|
|
return res.status(405).json({ error: 'Method not allowed' });
|
||
|
|
}
|
||
|
|
|
||
|
|
const client = await pool.connect();
|
||
|
|
|
||
|
|
try {
|
||
|
|
console.log('Setting up user authentication schema...');
|
||
|
|
|
||
|
|
// Check if users table already exists
|
||
|
|
const tableCheck = await client.query(`
|
||
|
|
SELECT EXISTS (
|
||
|
|
SELECT FROM information_schema.tables
|
||
|
|
WHERE table_schema = 'public'
|
||
|
|
AND table_name = 'users'
|
||
|
|
);
|
||
|
|
`);
|
||
|
|
|
||
|
|
if (tableCheck.rows[0].exists) {
|
||
|
|
return res.status(200).json({
|
||
|
|
success: true,
|
||
|
|
message: 'User authentication schema already exists',
|
||
|
|
already_setup: true
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create tables one by one
|
||
|
|
await client.query(`
|
||
|
|
CREATE TABLE IF NOT EXISTS users (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
username VARCHAR(50) UNIQUE NOT NULL,
|
||
|
|
email VARCHAR(100) UNIQUE NOT NULL,
|
||
|
|
password_hash VARCHAR(255) NOT NULL,
|
||
|
|
first_name VARCHAR(50),
|
||
|
|
last_name VARCHAR(50),
|
||
|
|
avatar_url TEXT,
|
||
|
|
is_active BOOLEAN DEFAULT true,
|
||
|
|
email_verified BOOLEAN DEFAULT false,
|
||
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
last_login TIMESTAMP WITH TIME ZONE
|
||
|
|
);
|
||
|
|
`);
|
||
|
|
|
||
|
|
await client.query(`
|
||
|
|
CREATE TABLE IF NOT EXISTS roles (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
name VARCHAR(50) UNIQUE NOT NULL,
|
||
|
|
description TEXT,
|
||
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
`);
|
||
|
|
|
||
|
|
await client.query(`
|
||
|
|
CREATE TABLE IF NOT EXISTS user_roles (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||
|
|
role_id INTEGER REFERENCES roles(id) ON DELETE CASCADE,
|
||
|
|
assigned_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
assigned_by INTEGER REFERENCES users(id),
|
||
|
|
UNIQUE(user_id, role_id)
|
||
|
|
);
|
||
|
|
`);
|
||
|
|
|
||
|
|
await client.query(`
|
||
|
|
CREATE TABLE IF NOT EXISTS permissions (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
name VARCHAR(100) UNIQUE NOT NULL,
|
||
|
|
description TEXT,
|
||
|
|
resource VARCHAR(50),
|
||
|
|
action VARCHAR(50),
|
||
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||
|
|
);
|
||
|
|
`);
|
||
|
|
|
||
|
|
await client.query(`
|
||
|
|
CREATE TABLE IF NOT EXISTS role_permissions (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
role_id INTEGER REFERENCES roles(id) ON DELETE CASCADE,
|
||
|
|
permission_id INTEGER REFERENCES permissions(id) ON DELETE CASCADE,
|
||
|
|
UNIQUE(role_id, permission_id)
|
||
|
|
);
|
||
|
|
`);
|
||
|
|
|
||
|
|
await client.query(`
|
||
|
|
CREATE TABLE IF NOT EXISTS user_sessions (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||
|
|
token_hash VARCHAR(255) NOT NULL,
|
||
|
|
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
last_used TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
|
|
user_agent TEXT,
|
||
|
|
ip_address INET
|
||
|
|
);
|
||
|
|
`);
|
||
|
|
|
||
|
|
// Insert default roles
|
||
|
|
await client.query(`
|
||
|
|
INSERT INTO roles (name, description) VALUES
|
||
|
|
('user', 'Standard user with basic permissions'),
|
||
|
|
('admin', 'Administrator with full system access')
|
||
|
|
ON CONFLICT (name) DO NOTHING;
|
||
|
|
`);
|
||
|
|
|
||
|
|
// Insert basic permissions
|
||
|
|
const permissions = [
|
||
|
|
['cards.read', 'View cards'],
|
||
|
|
['collections.manage', 'Manage collections'],
|
||
|
|
['decks.manage', 'Manage decks'],
|
||
|
|
['admin.access', 'Access admin panel']
|
||
|
|
];
|
||
|
|
|
||
|
|
for (const [name, description] of permissions) {
|
||
|
|
await client.query(`
|
||
|
|
INSERT INTO permissions (name, description)
|
||
|
|
VALUES ($1, $2)
|
||
|
|
ON CONFLICT (name) DO NOTHING;
|
||
|
|
`, [name, description]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Assign permissions to roles
|
||
|
|
await client.query(`
|
||
|
|
INSERT INTO role_permissions (role_id, permission_id)
|
||
|
|
SELECT r.id, p.id
|
||
|
|
FROM roles r, permissions p
|
||
|
|
WHERE r.name = 'user'
|
||
|
|
AND p.name IN ('cards.read', 'collections.manage', 'decks.manage')
|
||
|
|
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||
|
|
`);
|
||
|
|
|
||
|
|
await client.query(`
|
||
|
|
INSERT INTO role_permissions (role_id, permission_id)
|
||
|
|
SELECT r.id, p.id
|
||
|
|
FROM roles r, permissions p
|
||
|
|
WHERE r.name = 'admin'
|
||
|
|
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||
|
|
`);
|
||
|
|
|
||
|
|
// Create indexes
|
||
|
|
await client.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON user_roles(user_id);
|
||
|
|
`);
|
||
|
|
|
||
|
|
console.log('✅ User authentication schema setup completed!');
|
||
|
|
|
||
|
|
res.status(200).json({
|
||
|
|
success: true,
|
||
|
|
message: 'User authentication schema setup completed successfully'
|
||
|
|
});
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Schema setup failed:', error);
|
||
|
|
res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
error: 'Schema setup failed',
|
||
|
|
details: error.message
|
||
|
|
});
|
||
|
|
} finally {
|
||
|
|
client.release();
|
||
|
|
}
|
||
|
|
}
|