196 lines
7.6 KiB
PL/PgSQL
196 lines
7.6 KiB
PL/PgSQL
-- CREATE FUNCTION public.check_database_integrity
|
|
CREATE OR REPLACE FUNCTION public.check_database_integrity()
|
|
RETURNS jsonb
|
|
SECURITY DEFINER
|
|
AS $$
|
|
DECLARE
|
|
profiles_exist boolean;
|
|
end_customers_exist boolean;
|
|
pos_modules_exist boolean;
|
|
licenses_exist boolean;
|
|
|
|
profiles_count bigint := 0;
|
|
end_customers_count bigint := 0;
|
|
pos_modules_count bigint := 0;
|
|
licenses_count bigint := 0;
|
|
|
|
fk_errors_count bigint := 0;
|
|
result jsonb;
|
|
BEGIN
|
|
-- Check table existence
|
|
SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'profiles') INTO profiles_exist;
|
|
SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'end_customers') INTO end_customers_exist;
|
|
SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'pos_modules') INTO pos_modules_exist;
|
|
SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'licenses') INTO licenses_exist;
|
|
|
|
-- Count rows if table exists
|
|
IF profiles_exist THEN
|
|
EXECUTE 'SELECT count(*) FROM public.profiles' INTO profiles_count;
|
|
END IF;
|
|
|
|
IF end_customers_exist THEN
|
|
EXECUTE 'SELECT count(*) FROM public.end_customers' INTO end_customers_count;
|
|
END IF;
|
|
|
|
IF pos_modules_exist THEN
|
|
EXECUTE 'SELECT count(*) FROM public.pos_modules' INTO pos_modules_count;
|
|
END IF;
|
|
|
|
IF licenses_exist THEN
|
|
EXECUTE 'SELECT count(*) FROM public.licenses' INTO licenses_count;
|
|
END IF;
|
|
|
|
-- Count foreign key errors (orphaned licenses)
|
|
IF licenses_exist AND end_customers_exist THEN
|
|
EXECUTE '
|
|
SELECT count(*)
|
|
FROM public.licenses l
|
|
LEFT JOIN public.end_customers c ON l.end_customer_id = c.id
|
|
WHERE c.id IS NULL AND l.end_customer_id IS NOT NULL
|
|
' INTO fk_errors_count;
|
|
END IF;
|
|
|
|
-- Build JSON result
|
|
result := jsonb_build_object(
|
|
'tables', jsonb_build_object(
|
|
'profiles', jsonb_build_object('exists', profiles_exist, 'count', profiles_count),
|
|
'end_customers', jsonb_build_object('exists', end_customers_exist, 'count', end_customers_count),
|
|
'pos_modules', jsonb_build_object('exists', pos_modules_exist, 'count', pos_modules_count),
|
|
'licenses', jsonb_build_object('exists', licenses_exist, 'count', licenses_count)
|
|
),
|
|
'errors', jsonb_build_object(
|
|
'foreign_keys', fk_errors_count
|
|
)
|
|
);
|
|
|
|
RETURN result;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- CREATE FUNCTION public.repair_database_schema
|
|
CREATE OR REPLACE FUNCTION public.repair_database_schema()
|
|
RETURNS jsonb
|
|
SECURITY DEFINER
|
|
AS $$
|
|
DECLARE
|
|
repaired_tables text[] := '{}';
|
|
result jsonb;
|
|
BEGIN
|
|
-- 1. profiles table (should exist, but check just in case)
|
|
IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'profiles') THEN
|
|
CREATE TABLE public.profiles (
|
|
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
first_name TEXT,
|
|
last_name TEXT,
|
|
company_name TEXT,
|
|
vat_id TEXT,
|
|
address TEXT,
|
|
city TEXT,
|
|
zip_code TEXT,
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
|
|
);
|
|
repaired_tables := array_append(repaired_tables, 'profiles');
|
|
END IF;
|
|
|
|
-- 2. end_customers table
|
|
IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'end_customers') THEN
|
|
CREATE TABLE public.end_customers (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
partner_id UUID NOT NULL REFERENCES public.companies(id) ON DELETE CASCADE,
|
|
company_name TEXT NOT NULL,
|
|
vat_id TEXT,
|
|
first_name TEXT,
|
|
last_name TEXT,
|
|
street TEXT,
|
|
zip TEXT,
|
|
city TEXT,
|
|
is_anonymized BOOLEAN NOT NULL DEFAULT false,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
repaired_tables := array_append(repaired_tables, 'end_customers');
|
|
END IF;
|
|
|
|
-- 3. pos_modules table
|
|
IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'pos_modules') THEN
|
|
CREATE TABLE public.pos_modules (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name TEXT NOT NULL,
|
|
price NUMERIC(10, 2) NOT NULL DEFAULT 0.00,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
repaired_tables := array_append(repaired_tables, 'pos_modules');
|
|
END IF;
|
|
|
|
-- 4. licenses table
|
|
IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'licenses') THEN
|
|
CREATE TABLE public.licenses (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
end_customer_id UUID REFERENCES public.end_customers(id) ON DELETE CASCADE,
|
|
pos_module_id UUID REFERENCES public.pos_modules(id) ON DELETE CASCADE,
|
|
license_key TEXT NOT NULL UNIQUE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
repaired_tables := array_append(repaired_tables, 'licenses');
|
|
END IF;
|
|
|
|
-- Enable RLS on all tables
|
|
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.end_customers ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.pos_modules ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.licenses ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- Recreate RLS Policies
|
|
|
|
-- profiles Policies
|
|
DROP POLICY IF EXISTS "Users can view their own profile" ON public.profiles;
|
|
CREATE POLICY "Users can view their own profile" ON public.profiles FOR SELECT USING (auth.uid() = id);
|
|
DROP POLICY IF EXISTS "Users can update their own profile" ON public.profiles;
|
|
CREATE POLICY "Users can update their own profile" ON public.profiles FOR UPDATE USING (auth.uid() = id);
|
|
DROP POLICY IF EXISTS "Users can insert their own profile" ON public.profiles;
|
|
CREATE POLICY "Users can insert their own profile" ON public.profiles FOR INSERT WITH CHECK (auth.uid() = id);
|
|
DROP POLICY IF EXISTS "Admins can view all profiles" ON public.profiles;
|
|
CREATE POLICY "Admins can view all profiles" ON public.profiles FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
-- end_customers Policies
|
|
DROP POLICY IF EXISTS "Partner sehen nur eigene Endkunden" ON public.end_customers;
|
|
CREATE POLICY "Partner sehen nur eigene Endkunden" ON public.end_customers FOR ALL USING (partner_id = (SELECT company_id FROM public.users WHERE id = auth.uid())) WITH CHECK (partner_id = (SELECT company_id FROM public.users WHERE id = auth.uid()));
|
|
|
|
-- pos_modules Policies
|
|
DROP POLICY IF EXISTS "Allow authenticated read on pos_modules" ON public.pos_modules;
|
|
CREATE POLICY "Allow authenticated read on pos_modules" ON public.pos_modules FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
-- licenses Policies
|
|
DROP POLICY IF EXISTS "Partner sehen Lizenzen eigener Kunden" ON public.licenses;
|
|
CREATE POLICY "Partner sehen Lizenzen eigener Kunden" ON public.licenses FOR SELECT USING (
|
|
EXISTS (
|
|
SELECT 1 FROM public.end_customers c
|
|
WHERE c.id = licenses.end_customer_id AND c.partner_id = (SELECT company_id FROM public.users WHERE id = auth.uid())
|
|
)
|
|
);
|
|
DROP POLICY IF EXISTS "Partner erstellen Lizenzen eigener Kunden" ON public.licenses;
|
|
CREATE POLICY "Partner erstellen Lizenzen eigener Kunden" ON public.licenses FOR INSERT WITH CHECK (
|
|
EXISTS (
|
|
SELECT 1 FROM public.end_customers c
|
|
WHERE c.id = licenses.end_customer_id AND c.partner_id = (SELECT company_id FROM public.users WHERE id = auth.uid())
|
|
)
|
|
);
|
|
|
|
result := jsonb_build_object(
|
|
'repaired', to_jsonb(repaired_tables),
|
|
'success', true
|
|
);
|
|
RETURN result;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- CREATE FUNCTION public.optimize_database_indices
|
|
CREATE OR REPLACE FUNCTION public.optimize_database_indices()
|
|
RETURNS jsonb
|
|
SECURITY DEFINER
|
|
AS $$
|
|
BEGIN
|
|
REINDEX SCHEMA public;
|
|
RETURN jsonb_build_object('success', true, 'message', 'Schema public successfully reindexed.');
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|