feat: add registration and authentication
This commit is contained in:
114
backend/migrations/004_auth_and_race_ownership.sql
Normal file
114
backend/migrations/004_auth_and_race_ownership.sql
Normal file
@@ -0,0 +1,114 @@
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
email TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
email_verified_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS users_email_normalized_key
|
||||
ON users (LOWER(BTRIM(email)));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sessions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
token_hash TEXT NOT NULL UNIQUE,
|
||||
csrf_token_hash TEXT NOT NULL,
|
||||
expires_at TIMESTAMPTZ NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
revoked_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS sessions_user_id_idx ON sessions(user_id);
|
||||
CREATE INDEX IF NOT EXISTS sessions_expires_at_idx ON sessions(expires_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS email_verification_tokens (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
token_hash TEXT NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMPTZ NOT NULL,
|
||||
used_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS email_verification_tokens_user_id_idx
|
||||
ON email_verification_tokens(user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS password_reset_tokens (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
token_hash TEXT NOT NULL UNIQUE,
|
||||
expires_at TIMESTAMPTZ NOT NULL,
|
||||
used_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS password_reset_tokens_user_id_idx
|
||||
ON password_reset_tokens(user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS app_settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
id_type TEXT;
|
||||
pk_name TEXT;
|
||||
BEGIN
|
||||
SELECT data_type INTO id_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'races' AND column_name = 'id';
|
||||
|
||||
IF id_type IS NOT NULL AND id_type <> 'uuid' THEN
|
||||
SELECT conname INTO pk_name
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'races'::regclass AND contype = 'p'
|
||||
LIMIT 1;
|
||||
|
||||
IF pk_name IS NOT NULL THEN
|
||||
EXECUTE format('ALTER TABLE races DROP CONSTRAINT %I', pk_name);
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'races' AND column_name = 'slug'
|
||||
) THEN
|
||||
ALTER TABLE races RENAME COLUMN id TO slug;
|
||||
ELSE
|
||||
ALTER TABLE races DROP COLUMN id;
|
||||
END IF;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
ALTER TABLE races ADD COLUMN IF NOT EXISTS id UUID DEFAULT gen_random_uuid();
|
||||
UPDATE races SET id = gen_random_uuid() WHERE id IS NULL;
|
||||
ALTER TABLE races ALTER COLUMN id SET NOT NULL;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint
|
||||
WHERE conrelid = 'races'::regclass AND contype = 'p'
|
||||
) THEN
|
||||
ALTER TABLE races ADD CONSTRAINT races_pkey PRIMARY KEY (id);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
ALTER TABLE races ADD COLUMN IF NOT EXISTS slug TEXT;
|
||||
UPDATE races SET slug = id::text WHERE slug IS NULL OR BTRIM(slug) = '';
|
||||
ALTER TABLE races ALTER COLUMN slug SET NOT NULL;
|
||||
|
||||
ALTER TABLE races ADD COLUMN IF NOT EXISTS owner_user_id UUID REFERENCES users(id) ON DELETE CASCADE;
|
||||
ALTER TABLE races ADD COLUMN IF NOT EXISTS source TEXT NOT NULL DEFAULT 'user';
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS races_owner_slug_key
|
||||
ON races(owner_user_id, slug)
|
||||
WHERE owner_user_id IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS races_owner_user_id_idx ON races(owner_user_id);
|
||||
Reference in New Issue
Block a user