106 lines
2.9 KiB
PL/PgSQL
106 lines
2.9 KiB
PL/PgSQL
BEGIN;
|
|
|
|
ALTER TABLE app_user
|
|
ADD COLUMN IF NOT EXISTS role TEXT NOT NULL DEFAULT 'USER';
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_app_user_role ON app_user(role);
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'chk_app_user_role') THEN
|
|
ALTER TABLE app_user
|
|
ADD CONSTRAINT chk_app_user_role
|
|
CHECK (role IN ('USER','ADMIN','SUPER_ADMIN'));
|
|
END IF;
|
|
END $$;
|
|
|
|
UPDATE app_user
|
|
SET role = 'SUPER_ADMIN'
|
|
WHERE role <> 'SUPER_ADMIN' AND COALESCE(is_super_admin, false) = true;
|
|
|
|
UPDATE app_user
|
|
SET role = 'ADMIN'
|
|
WHERE role = 'USER' AND COALESCE(is_admin, false) = true;
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_name = 'app_user' AND column_name = 'is_admin'
|
|
) THEN
|
|
UPDATE app_user
|
|
SET is_admin = (role IN ('ADMIN','SUPER_ADMIN'))
|
|
WHERE is_admin IS DISTINCT FROM (role IN ('ADMIN','SUPER_ADMIN'));
|
|
END IF;
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_name = 'app_user' AND column_name = 'is_super_admin'
|
|
) THEN
|
|
UPDATE app_user
|
|
SET is_super_admin = (role = 'SUPER_ADMIN')
|
|
WHERE is_super_admin IS DISTINCT FROM (role = 'SUPER_ADMIN');
|
|
END IF;
|
|
END $$;
|
|
|
|
CREATE TABLE IF NOT EXISTS admin_role_audit (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
actor_user_id TEXT NOT NULL,
|
|
target_user_id TEXT NOT NULL,
|
|
old_role TEXT NOT NULL,
|
|
new_role TEXT NOT NULL,
|
|
changed_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE OR REPLACE FUNCTION prevent_super_admin_delete()
|
|
RETURNS trigger AS $$
|
|
BEGIN
|
|
IF OLD.role = 'SUPER_ADMIN' OR OLD.is_super_admin THEN
|
|
RAISE EXCEPTION 'cannot delete super admin user';
|
|
END IF;
|
|
RETURN OLD;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP VIEW IF EXISTS admin_user_metrics;
|
|
CREATE OR REPLACE VIEW admin_user_metrics AS
|
|
WITH session_stats AS (
|
|
SELECT
|
|
user_id,
|
|
MIN(created_at) AS first_session_at,
|
|
MAX(COALESCE(last_seen_at, created_at)) AS last_login_at
|
|
FROM app_session
|
|
GROUP BY user_id
|
|
),
|
|
run_stats AS (
|
|
SELECT
|
|
user_id,
|
|
COUNT(*) AS runs_count,
|
|
MAX(CASE WHEN status = 'RUNNING' THEN run_id END) AS active_run_id,
|
|
MAX(CASE WHEN status = 'RUNNING' THEN status END) AS active_run_status,
|
|
MIN(created_at) AS first_run_at
|
|
FROM strategy_run
|
|
GROUP BY user_id
|
|
),
|
|
broker_stats AS (
|
|
SELECT user_id, BOOL_OR(connected) AS broker_connected
|
|
FROM user_broker
|
|
GROUP BY user_id
|
|
)
|
|
SELECT
|
|
u.id AS user_id,
|
|
u.username,
|
|
u.role,
|
|
(u.role IN ('ADMIN','SUPER_ADMIN')) AS is_admin,
|
|
COALESCE(session_stats.first_session_at, run_stats.first_run_at) AS created_at,
|
|
session_stats.last_login_at,
|
|
COALESCE(run_stats.runs_count, 0) AS runs_count,
|
|
run_stats.active_run_id,
|
|
run_stats.active_run_status,
|
|
COALESCE(broker_stats.broker_connected, FALSE) AS broker_connected
|
|
FROM app_user u
|
|
LEFT JOIN session_stats ON session_stats.user_id = u.id
|
|
LEFT JOIN run_stats ON run_stats.user_id = u.id
|
|
LEFT JOIN broker_stats ON broker_stats.user_id = u.id;
|
|
|
|
COMMIT;
|