mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-18 01:49:40 +02:00
refactor: restructure
monorepo with apps/ and services/ directories
This commit is contained in:
parent
25824ed0ac
commit
ff80aeec1f
4062 changed files with 2592 additions and 1278 deletions
33
apps/chat/apps/mobile/scripts/add_archive_functionality.sql
Normal file
33
apps/chat/apps/mobile/scripts/add_archive_functionality.sql
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
-- SQL-Skript zum Hinzufügen der Archivfunktionalität
|
||||
-- Fügt ein 'is_archived' Feld zur 'conversations' Tabelle hinzu
|
||||
|
||||
-- Prüfen, ob die Spalte existiert und füge sie hinzu, falls nicht
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'conversations'
|
||||
AND column_name = 'is_archived'
|
||||
) THEN
|
||||
ALTER TABLE public.conversations
|
||||
ADD COLUMN is_archived BOOLEAN DEFAULT false;
|
||||
|
||||
RAISE NOTICE 'Spalte is_archived zur conversations-Tabelle hinzugefügt.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Spalte is_archived existiert bereits in der conversations-Tabelle.';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- Kommentar für die neue Spalte hinzufügen
|
||||
COMMENT ON COLUMN conversations.is_archived IS 'Gibt an, ob die Konversation archiviert wurde.';
|
||||
|
||||
-- Index für schnellere Abfragen, da wir oft nach archivierten/nicht-archivierten Konversationen filtern werden
|
||||
CREATE INDEX IF NOT EXISTS idx_conversations_is_archived ON conversations(is_archived);
|
||||
|
||||
-- Indices für die Kombination aus Benutzer-ID und Archivierungsstatus für optimierte Abfragen
|
||||
CREATE INDEX IF NOT EXISTS idx_conversations_user_archived ON conversations(user_id, is_archived);
|
||||
|
||||
-- Stelle sicher, dass die RLS-Policies aktualisiert werden, um die neue Spalte zu berücksichtigen
|
||||
ALTER TABLE conversations ENABLE ROW LEVEL SECURITY;
|
||||
19
apps/chat/apps/mobile/scripts/add_conversation_title.sql
Normal file
19
apps/chat/apps/mobile/scripts/add_conversation_title.sql
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
-- SQL zum Hinzufügen der Titel-Spalte zur Conversations-Tabelle
|
||||
-- SCHRITT 1: Spalte zur Tabelle hinzufügen
|
||||
ALTER TABLE conversations
|
||||
ADD COLUMN IF NOT EXISTS title TEXT;
|
||||
|
||||
-- SCHRITT 2: Kommentar für Dokumentation hinzufügen
|
||||
COMMENT ON COLUMN conversations.title IS 'KI-generierter Titel für die Konversation';
|
||||
|
||||
-- SCHRITT 3: Aktualisiere RLS-Policy (Row Level Security) für die neue Spalte
|
||||
-- (Stelle sicher, dass Benutzer nur ihre eigenen Konversationen lesen/bearbeiten können)
|
||||
DROP POLICY IF EXISTS "Users can update their own conversations" ON conversations;
|
||||
CREATE POLICY "Users can update their own conversations"
|
||||
ON conversations
|
||||
FOR UPDATE USING (user_id = auth.uid());
|
||||
|
||||
-- SCHRITT 4: (Optional) Standardwerte für bestehende Konversationen setzen
|
||||
UPDATE conversations
|
||||
SET title = 'Frühere Konversation'
|
||||
WHERE title IS NULL;
|
||||
84
apps/chat/apps/mobile/scripts/check_and_create_models.sql
Normal file
84
apps/chat/apps/mobile/scripts/check_and_create_models.sql
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
-- Überprüfe und erstelle Modelle in der Datenbank
|
||||
|
||||
-- 1. Überprüfe, ob die models-Tabelle existiert
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'models'
|
||||
) THEN
|
||||
-- Erstelle die models-Tabelle
|
||||
CREATE TABLE public.models (
|
||||
id UUID PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
parameters JSONB,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Erstelle einen Trigger für updated_at
|
||||
CREATE OR REPLACE FUNCTION set_updated_at()
|
||||
RETURNS TRIGGER AS $func$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$func$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER set_models_updated_at
|
||||
BEFORE UPDATE ON public.models
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
RAISE NOTICE 'Tabelle models wurde erstellt.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Tabelle models existiert bereits.';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- 2. Überprüfe die Struktur der models-Tabelle und füge updated_at hinzu, falls es fehlt
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'models'
|
||||
AND column_name = 'updated_at'
|
||||
) THEN
|
||||
ALTER TABLE public.models ADD COLUMN updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW();
|
||||
RAISE NOTICE 'Spalte updated_at zur models-Tabelle hinzugefügt.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Spalte updated_at existiert bereits in der models-Tabelle.';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- 3. Füge Standard-Modelle ein
|
||||
INSERT INTO public.models (id, name, description, parameters)
|
||||
VALUES
|
||||
('550e8400-e29b-41d4-a716-446655440000', 'GPT-O3-Mini', 'Azure OpenAI GPT-O3-Mini', '{"temperature": 0.7, "max_tokens": 800}'),
|
||||
('550e8400-e29b-41d4-a716-446655440001', 'GPT-4', 'OpenAI GPT-4', '{"temperature": 0.7, "max_tokens": 1000}'),
|
||||
('550e8400-e29b-41d4-a716-446655440002', 'GPT-3.5-Turbo', 'OpenAI GPT-3.5 Turbo', '{"temperature": 0.7, "max_tokens": 800}'),
|
||||
('550e8400-e29b-41d4-a716-446655440003', 'Claude 3', 'Anthropic Claude 3', '{"temperature": 0.7, "max_tokens": 1000}')
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
parameters = EXCLUDED.parameters;
|
||||
|
||||
-- 4. Aktiviere RLS für die models-Tabelle
|
||||
ALTER TABLE public.models ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 5. Erstelle eine Richtlinie für das Lesen von Modellen
|
||||
-- Alle authentifizierten Benutzer dürfen Modelle sehen
|
||||
DROP POLICY IF EXISTS models_select_policy ON models;
|
||||
CREATE POLICY models_select_policy
|
||||
ON models
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (true);
|
||||
|
||||
-- 6. Überprüfe, ob die Modelle existieren
|
||||
SELECT id, name, description FROM public.models;
|
||||
66
apps/chat/apps/mobile/scripts/check_azure_openai.sql
Normal file
66
apps/chat/apps/mobile/scripts/check_azure_openai.sql
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
-- Skript zur Überprüfung und Konfiguration der Azure OpenAI-Einstellungen in der Datenbank
|
||||
|
||||
-- 1. Erstelle eine Tabelle für die Anwendungseinstellungen, falls sie noch nicht existiert
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'app_settings'
|
||||
) THEN
|
||||
CREATE TABLE public.app_settings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
key TEXT NOT NULL UNIQUE,
|
||||
value TEXT,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Erstelle einen Trigger für updated_at
|
||||
CREATE OR REPLACE FUNCTION set_updated_at()
|
||||
RETURNS TRIGGER AS $func$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$func$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER set_app_settings_updated_at
|
||||
BEFORE UPDATE ON public.app_settings
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
RAISE NOTICE 'Tabelle app_settings wurde erstellt.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Tabelle app_settings existiert bereits.';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- 2. Füge Azure OpenAI-Einstellungen hinzu oder aktualisiere sie
|
||||
INSERT INTO public.app_settings (key, value, description)
|
||||
VALUES
|
||||
('AZURE_OPENAI_ENDPOINT', 'https://memoroseopenai.openai.azure.com', 'Azure OpenAI API Endpoint'),
|
||||
('AZURE_OPENAI_DEPLOYMENT', 'gpt-o3-mini-se', 'Azure OpenAI Deployment Name'),
|
||||
('AZURE_OPENAI_API_VERSION', '2024-12-01-preview', 'Azure OpenAI API Version'),
|
||||
('AZURE_OPENAI_API_KEY', '3082103c9b0d4270a795686ccaa89921', 'Azure OpenAI API Key')
|
||||
ON CONFLICT (key) DO UPDATE SET
|
||||
value = EXCLUDED.value,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = NOW();
|
||||
|
||||
-- 3. Aktiviere RLS für die app_settings-Tabelle
|
||||
ALTER TABLE public.app_settings ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 4. Erstelle eine Richtlinie für das Lesen von Einstellungen
|
||||
-- Alle authentifizierten Benutzer dürfen Einstellungen sehen
|
||||
DROP POLICY IF EXISTS app_settings_select_policy ON app_settings;
|
||||
CREATE POLICY app_settings_select_policy
|
||||
ON app_settings
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (true);
|
||||
|
||||
-- 5. Überprüfe, ob die Einstellungen existieren
|
||||
SELECT key, value, description FROM public.app_settings;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
-- Diese SQL-Funktion zum Löschen eines Dokuments erstellt eine sichere Methode
|
||||
-- zum Löschen über RPC, was besser gegen Datenbank-Caching und Race-Conditions ist
|
||||
|
||||
-- Führen Sie dieses SQL im Supabase SQL-Editor aus
|
||||
|
||||
CREATE OR REPLACE FUNCTION delete_document_by_id(document_id uuid)
|
||||
RETURNS boolean AS $$
|
||||
DECLARE
|
||||
success boolean;
|
||||
affected_rows int;
|
||||
BEGIN
|
||||
-- Führe die eigentliche Löschung durch
|
||||
DELETE FROM documents
|
||||
WHERE id = document_id
|
||||
AND conversation_id IN (
|
||||
SELECT id FROM conversations WHERE user_id = auth.uid()
|
||||
);
|
||||
|
||||
-- Speichere die Anzahl der betroffenen Zeilen
|
||||
GET DIAGNOSTICS affected_rows = ROW_COUNT;
|
||||
|
||||
-- Setze den Erfolgsstatus basierend auf der Anzahl der gelöschten Zeilen
|
||||
success := affected_rows > 0;
|
||||
|
||||
-- Gib das Ergebnis zurück (true wenn erfolgreich, false wenn nicht)
|
||||
RETURN success;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Diese Funktion kann dann mit dem folgenden JavaScript aufgerufen werden:
|
||||
-- const { data, error } = await supabase.rpc('delete_document_by_id', { document_id: 'uuid-here' });
|
||||
66
apps/chat/apps/mobile/scripts/create_templates_table.sql
Normal file
66
apps/chat/apps/mobile/scripts/create_templates_table.sql
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
-- Erstelle die Tabelle für Vorlagen
|
||||
CREATE TABLE IF NOT EXISTS templates (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
system_prompt TEXT NOT NULL,
|
||||
model_id UUID REFERENCES models(id),
|
||||
color TEXT DEFAULT '#0A84FF',
|
||||
is_default BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||
);
|
||||
|
||||
-- Kommentare für Dokumentation
|
||||
COMMENT ON TABLE templates IS 'Vorlagen für vordefinierte Chat-Prompts';
|
||||
COMMENT ON COLUMN templates.name IS 'Name der Vorlage';
|
||||
COMMENT ON COLUMN templates.description IS 'Beschreibung der Vorlage';
|
||||
COMMENT ON COLUMN templates.system_prompt IS 'System-Prompt für die KI';
|
||||
COMMENT ON COLUMN templates.model_id IS 'Das bevorzugte Modell für diese Vorlage (optional)';
|
||||
COMMENT ON COLUMN templates.color IS 'Farbcode für die Darstellung in der UI';
|
||||
COMMENT ON COLUMN templates.is_default IS 'Gibt an, ob diese Vorlage als Standard verwendet werden soll';
|
||||
|
||||
-- Row Level Security
|
||||
ALTER TABLE templates ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY "Users can view their own templates" ON templates
|
||||
FOR SELECT USING (user_id = auth.uid());
|
||||
|
||||
CREATE POLICY "Users can create their own templates" ON templates
|
||||
FOR INSERT WITH CHECK (user_id = auth.uid());
|
||||
|
||||
CREATE POLICY "Users can update their own templates" ON templates
|
||||
FOR UPDATE USING (user_id = auth.uid());
|
||||
|
||||
CREATE POLICY "Users can delete their own templates" ON templates
|
||||
FOR DELETE USING (user_id = auth.uid());
|
||||
|
||||
-- Beispiel-Vorlagen
|
||||
INSERT INTO templates (user_id, name, description, system_prompt, color, is_default)
|
||||
VALUES (
|
||||
(SELECT id FROM auth.users LIMIT 1), -- Erste Benutzer-ID
|
||||
'Persönlicher Assistent',
|
||||
'Allgemeiner Assistent, der bei vielfältigen Aufgaben hilft',
|
||||
'Du bist ein hilfreicher Assistent. Antworte präzise und freundlich auf alle Fragen des Nutzers. Wenn du etwas nicht weißt, gib an, dass du dir unsicher bist, statt zu spekulieren.',
|
||||
'#0A84FF',
|
||||
true
|
||||
);
|
||||
|
||||
INSERT INTO templates (user_id, name, description, system_prompt, color)
|
||||
VALUES (
|
||||
(SELECT id FROM auth.users LIMIT 1), -- Erste Benutzer-ID
|
||||
'Kreativer Schreibpartner',
|
||||
'Hilft beim Brainstorming und der Entwicklung kreativer Ideen',
|
||||
'Du bist ein kreativer Schreibpartner. Hilf dem Nutzer bei der Entwicklung von Ideen für Geschichten, Charaktere, Szenarien und Dialoge. Sei fantasievoll und inspirierend. Schlage neue Richtungen vor, wenn der Nutzer feststeckt.',
|
||||
'#FF375F'
|
||||
);
|
||||
|
||||
INSERT INTO templates (user_id, name, description, system_prompt, color)
|
||||
VALUES (
|
||||
(SELECT id FROM auth.users LIMIT 1), -- Erste Benutzer-ID
|
||||
'Technischer Berater',
|
||||
'Unterstützt bei technischen Fragen und Programmierung',
|
||||
'Du bist ein technischer Berater mit Expertenwissen in Programmierung, Softwareentwicklung und IT. Erkläre technische Konzepte verständlich, gib Code-Beispiele wenn nötig und biete praktische Lösungen für technische Probleme. Wenn Code bereitgestellt wird, analysiere ihn gründlich vor der Antwort.',
|
||||
'#32D74B'
|
||||
);
|
||||
144
apps/chat/apps/mobile/scripts/create_usage_functions.sql
Normal file
144
apps/chat/apps/mobile/scripts/create_usage_functions.sql
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
-- Funktionen zum Abfragen der Token-Nutzung
|
||||
|
||||
-- 1. Funktion zum Abrufen der Token-Nutzung eines Benutzers, gruppiert nach Modell
|
||||
CREATE OR REPLACE FUNCTION get_user_model_usage(user_id UUID)
|
||||
RETURNS TABLE (
|
||||
model_id UUID,
|
||||
model_name TEXT,
|
||||
total_prompt_tokens BIGINT,
|
||||
total_completion_tokens BIGINT,
|
||||
total_tokens BIGINT,
|
||||
total_cost DECIMAL(10, 6)
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
ul.model_id,
|
||||
m.name AS model_name,
|
||||
SUM(ul.prompt_tokens)::BIGINT AS total_prompt_tokens,
|
||||
SUM(ul.completion_tokens)::BIGINT AS total_completion_tokens,
|
||||
SUM(ul.total_tokens)::BIGINT AS total_tokens,
|
||||
SUM(ul.estimated_cost)::DECIMAL(10, 6) AS total_cost
|
||||
FROM
|
||||
usage_logs ul
|
||||
JOIN
|
||||
models m ON ul.model_id = m.id
|
||||
WHERE
|
||||
ul.user_id = get_user_model_usage.user_id
|
||||
GROUP BY
|
||||
ul.model_id, m.name
|
||||
ORDER BY
|
||||
total_cost DESC;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- 2. Funktion zum Abrufen der Token-Nutzung eines Benutzers nach Zeitraum
|
||||
CREATE OR REPLACE FUNCTION get_user_usage_by_period(user_id UUID, period TEXT)
|
||||
RETURNS TABLE (
|
||||
time_period TEXT,
|
||||
total_tokens BIGINT,
|
||||
total_cost DECIMAL(10, 6)
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
BEGIN
|
||||
IF period = 'day' THEN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
TO_CHAR(ul.created_at, 'YYYY-MM-DD') AS time_period,
|
||||
SUM(ul.total_tokens)::BIGINT AS total_tokens,
|
||||
SUM(ul.estimated_cost)::DECIMAL(10, 6) AS total_cost
|
||||
FROM
|
||||
usage_logs ul
|
||||
WHERE
|
||||
ul.user_id = get_user_usage_by_period.user_id
|
||||
GROUP BY
|
||||
time_period
|
||||
ORDER BY
|
||||
time_period DESC;
|
||||
ELSIF period = 'month' THEN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
TO_CHAR(ul.created_at, 'YYYY-MM') AS time_period,
|
||||
SUM(ul.total_tokens)::BIGINT AS total_tokens,
|
||||
SUM(ul.estimated_cost)::DECIMAL(10, 6) AS total_cost
|
||||
FROM
|
||||
usage_logs ul
|
||||
WHERE
|
||||
ul.user_id = get_user_usage_by_period.user_id
|
||||
GROUP BY
|
||||
time_period
|
||||
ORDER BY
|
||||
time_period DESC;
|
||||
ELSIF period = 'year' THEN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
TO_CHAR(ul.created_at, 'YYYY') AS time_period,
|
||||
SUM(ul.total_tokens)::BIGINT AS total_tokens,
|
||||
SUM(ul.estimated_cost)::DECIMAL(10, 6) AS total_cost
|
||||
FROM
|
||||
usage_logs ul
|
||||
WHERE
|
||||
ul.user_id = get_user_usage_by_period.user_id
|
||||
GROUP BY
|
||||
time_period
|
||||
ORDER BY
|
||||
time_period DESC;
|
||||
ELSE
|
||||
-- Fallback auf tägliche Ansicht
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
TO_CHAR(ul.created_at, 'YYYY-MM-DD') AS time_period,
|
||||
SUM(ul.total_tokens)::BIGINT AS total_tokens,
|
||||
SUM(ul.estimated_cost)::DECIMAL(10, 6) AS total_cost
|
||||
FROM
|
||||
usage_logs ul
|
||||
WHERE
|
||||
ul.user_id = get_user_usage_by_period.user_id
|
||||
GROUP BY
|
||||
time_period
|
||||
ORDER BY
|
||||
time_period DESC;
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- 3. Funktion zum Abrufen der Token-Nutzung einer bestimmten Konversation
|
||||
CREATE OR REPLACE FUNCTION get_conversation_usage(conversation_id UUID)
|
||||
RETURNS TABLE (
|
||||
message_id UUID,
|
||||
created_at TIMESTAMP WITH TIME ZONE,
|
||||
prompt_tokens BIGINT,
|
||||
completion_tokens BIGINT,
|
||||
total_tokens BIGINT,
|
||||
estimated_cost DECIMAL(10, 6)
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
ul.message_id,
|
||||
ul.created_at,
|
||||
ul.prompt_tokens::BIGINT,
|
||||
ul.completion_tokens::BIGINT,
|
||||
ul.total_tokens::BIGINT,
|
||||
ul.estimated_cost::DECIMAL(10, 6)
|
||||
FROM
|
||||
usage_logs ul
|
||||
WHERE
|
||||
ul.conversation_id = get_conversation_usage.conversation_id
|
||||
ORDER BY
|
||||
ul.created_at;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- Erteile Berechtigungen für die Funktionen
|
||||
GRANT EXECUTE ON FUNCTION get_user_model_usage TO authenticated;
|
||||
GRANT EXECUTE ON FUNCTION get_user_usage_by_period TO authenticated;
|
||||
GRANT EXECUTE ON FUNCTION get_conversation_usage TO authenticated;
|
||||
122
apps/chat/apps/mobile/scripts/create_usage_logs_table.sql
Normal file
122
apps/chat/apps/mobile/scripts/create_usage_logs_table.sql
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
-- Erstelle eine neue Tabelle für die Token-Nutzung und Kostenerfassung
|
||||
|
||||
-- 1. Überprüfe, ob die usage_logs-Tabelle existiert
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'usage_logs'
|
||||
) THEN
|
||||
-- Erstelle die usage_logs-Tabelle
|
||||
CREATE TABLE public.usage_logs (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
conversation_id UUID REFERENCES conversations(id) ON DELETE CASCADE,
|
||||
message_id UUID REFERENCES messages(id) ON DELETE CASCADE,
|
||||
user_id UUID REFERENCES auth.users(id),
|
||||
model_id UUID REFERENCES models(id),
|
||||
prompt_tokens INTEGER NOT NULL,
|
||||
completion_tokens INTEGER NOT NULL,
|
||||
total_tokens INTEGER NOT NULL,
|
||||
estimated_cost DECIMAL(10, 6) NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
RAISE NOTICE 'Tabelle usage_logs wurde erstellt.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Tabelle usage_logs existiert bereits.';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- 2. Aktiviere RLS für die usage_logs-Tabelle
|
||||
ALTER TABLE public.usage_logs ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 3. Erstelle RLS-Richtlinien für usage_logs
|
||||
-- Benutzer können nur ihre eigenen Nutzungsdaten sehen
|
||||
DROP POLICY IF EXISTS usage_logs_select_policy ON usage_logs;
|
||||
CREATE POLICY usage_logs_select_policy
|
||||
ON usage_logs
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid());
|
||||
|
||||
-- Nur über die Anwendung dürfen Einträge erstellt werden
|
||||
DROP POLICY IF EXISTS usage_logs_insert_policy ON usage_logs;
|
||||
CREATE POLICY usage_logs_insert_policy
|
||||
ON usage_logs
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (user_id = auth.uid());
|
||||
|
||||
-- 4. Erweitere das Modell-Schema um Kosteninformationen
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'models'
|
||||
AND column_name = 'cost_settings'
|
||||
) THEN
|
||||
ALTER TABLE public.models ADD COLUMN cost_settings JSONB DEFAULT '{"prompt_per_1k_tokens": 0.0001, "completion_per_1k_tokens": 0.0002}'::jsonb;
|
||||
RAISE NOTICE 'Spalte cost_settings zur models-Tabelle hinzugefügt.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Spalte cost_settings existiert bereits in der models-Tabelle.';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- 5. Aktualisiere die vorhandenen Modelle mit Kosteninformationen
|
||||
UPDATE public.models
|
||||
SET cost_settings = jsonb_build_object(
|
||||
'prompt_per_1k_tokens', CASE
|
||||
WHEN name LIKE '%GPT-O3-Mini%' THEN 0.0001
|
||||
WHEN name LIKE '%GPT-4o-mini%' THEN 0.0001
|
||||
WHEN name LIKE '%GPT-4o%' THEN 0.003
|
||||
WHEN name LIKE '%GPT-4%' THEN 0.003
|
||||
WHEN name LIKE '%GPT-3.5%' THEN 0.0001
|
||||
WHEN name LIKE '%Claude%' THEN 0.0008
|
||||
ELSE 0.0001
|
||||
END,
|
||||
'completion_per_1k_tokens', CASE
|
||||
WHEN name LIKE '%GPT-O3-Mini%' THEN 0.0002
|
||||
WHEN name LIKE '%GPT-4o-mini%' THEN 0.0002
|
||||
WHEN name LIKE '%GPT-4o%' THEN 0.006
|
||||
WHEN name LIKE '%GPT-4%' THEN 0.006
|
||||
WHEN name LIKE '%GPT-3.5%' THEN 0.0002
|
||||
WHEN name LIKE '%Claude%' THEN 0.0024
|
||||
ELSE 0.0002
|
||||
END
|
||||
)
|
||||
WHERE cost_settings IS NULL OR cost_settings = '{}'::jsonb;
|
||||
|
||||
-- 6. Funktion zur Berechnung der Kosten
|
||||
CREATE OR REPLACE FUNCTION calculate_token_cost(
|
||||
p_prompt_tokens INTEGER,
|
||||
p_completion_tokens INTEGER,
|
||||
p_model_id UUID
|
||||
) RETURNS DECIMAL(10, 6) AS $$
|
||||
DECLARE
|
||||
v_prompt_cost DECIMAL(10, 6);
|
||||
v_completion_cost DECIMAL(10, 6);
|
||||
v_cost_settings JSONB;
|
||||
v_cost DECIMAL(10, 6);
|
||||
BEGIN
|
||||
-- Hole die Kosteneinstellungen für das angegebene Modell
|
||||
SELECT cost_settings INTO v_cost_settings
|
||||
FROM models
|
||||
WHERE id = p_model_id;
|
||||
|
||||
-- Extrahiere die Kosten pro 1000 Token
|
||||
v_prompt_cost := (v_cost_settings->>'prompt_per_1k_tokens')::DECIMAL;
|
||||
v_completion_cost := (v_cost_settings->>'completion_per_1k_tokens')::DECIMAL;
|
||||
|
||||
-- Berechne die Gesamtkosten
|
||||
v_cost := (p_prompt_tokens * v_prompt_cost + p_completion_tokens * v_completion_cost) / 1000;
|
||||
|
||||
RETURN ROUND(v_cost, 6);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 7. Berechtigung zum Ausführen der Funktion
|
||||
GRANT EXECUTE ON FUNCTION calculate_token_cost TO authenticated;
|
||||
103
apps/chat/apps/mobile/scripts/create_users_table.sql
Normal file
103
apps/chat/apps/mobile/scripts/create_users_table.sql
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
-- Erstelle oder aktualisiere die users-Tabelle im public-Schema
|
||||
|
||||
-- Prüfe, ob die users-Tabelle bereits existiert
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'users'
|
||||
) THEN
|
||||
-- Erstelle die users-Tabelle
|
||||
CREATE TABLE public.users (
|
||||
id UUID PRIMARY KEY,
|
||||
email TEXT UNIQUE NOT NULL,
|
||||
name TEXT,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Erstelle einen Trigger für updated_at
|
||||
CREATE OR REPLACE FUNCTION set_updated_at()
|
||||
RETURNS TRIGGER AS $func$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$func$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER set_users_updated_at
|
||||
BEFORE UPDATE ON public.users
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
RAISE NOTICE 'Tabelle users wurde erstellt.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Tabelle users existiert bereits.';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- Erstelle eine Funktion, um Benutzer aus auth.users in public.users zu synchronisieren
|
||||
CREATE OR REPLACE FUNCTION sync_user_after_auth_event()
|
||||
RETURNS TRIGGER AS $sync_func$
|
||||
BEGIN
|
||||
IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') AND NEW.confirmed_at IS NOT NULL THEN
|
||||
-- Füge den Benutzer in die public.users-Tabelle ein oder aktualisiere ihn
|
||||
INSERT INTO public.users (id, email, name, created_at, updated_at)
|
||||
VALUES (
|
||||
NEW.id,
|
||||
NEW.email,
|
||||
COALESCE(NEW.raw_user_meta_data->>'name', NEW.email),
|
||||
NEW.created_at,
|
||||
NEW.updated_at
|
||||
)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
email = EXCLUDED.email,
|
||||
name = COALESCE(NEW.raw_user_meta_data->>'name', NEW.email),
|
||||
updated_at = NOW();
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$sync_func$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Erstelle einen Trigger für die auth.users-Tabelle
|
||||
DROP TRIGGER IF EXISTS sync_user_after_auth_event_trigger ON auth.users;
|
||||
CREATE TRIGGER sync_user_after_auth_event_trigger
|
||||
AFTER INSERT OR UPDATE ON auth.users
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION sync_user_after_auth_event();
|
||||
|
||||
-- Synchronisiere bestehende Benutzer
|
||||
INSERT INTO public.users (id, email, name, created_at, updated_at)
|
||||
SELECT
|
||||
id,
|
||||
email,
|
||||
COALESCE(raw_user_meta_data->>'name', email) as name,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM auth.users
|
||||
WHERE confirmed_at IS NOT NULL
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
email = EXCLUDED.email,
|
||||
name = COALESCE(EXCLUDED.name, users.name),
|
||||
updated_at = NOW();
|
||||
|
||||
-- Aktiviere RLS für die users-Tabelle
|
||||
ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Erstelle eine Richtlinie für das Lesen von Benutzern
|
||||
-- Benutzer dürfen nur ihre eigenen Daten sehen
|
||||
CREATE POLICY users_select_policy
|
||||
ON public.users
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (id = auth.uid());
|
||||
|
||||
-- Erstelle eine Richtlinie für das Aktualisieren von Benutzern
|
||||
-- Benutzer dürfen nur ihre eigenen Daten aktualisieren
|
||||
CREATE POLICY users_update_policy
|
||||
ON public.users
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (id = auth.uid());
|
||||
120
apps/chat/apps/mobile/scripts/fix_conversation_creation.sql
Normal file
120
apps/chat/apps/mobile/scripts/fix_conversation_creation.sql
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
-- Überprüfe und behebe Probleme mit der Conversations-Tabelle
|
||||
|
||||
-- 1. Überprüfe die Struktur der Conversations-Tabelle
|
||||
DO $$
|
||||
DECLARE
|
||||
column_exists BOOLEAN;
|
||||
BEGIN
|
||||
-- Prüfe, ob die user_id-Spalte vom Typ UUID ist
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'conversations'
|
||||
AND column_name = 'user_id'
|
||||
AND data_type = 'uuid'
|
||||
) INTO column_exists;
|
||||
|
||||
IF NOT column_exists THEN
|
||||
RAISE NOTICE 'Die user_id-Spalte in der conversations-Tabelle ist nicht vom Typ UUID. Bitte überprüfe die Tabellendefinition.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Die user_id-Spalte in der conversations-Tabelle ist korrekt vom Typ UUID.';
|
||||
END IF;
|
||||
|
||||
-- Prüfe, ob es eine Unique-Constraint gibt, die Konflikte verursachen könnte
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.table_constraints
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'conversations'
|
||||
AND constraint_type = 'UNIQUE'
|
||||
) INTO column_exists;
|
||||
|
||||
IF column_exists THEN
|
||||
RAISE NOTICE 'Es gibt eine Unique-Constraint in der conversations-Tabelle, die Konflikte verursachen könnte.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Es gibt keine Unique-Constraint in der conversations-Tabelle.';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 2. Überprüfe den Foreign-Key-Constraint
|
||||
DO $$
|
||||
DECLARE
|
||||
fk_exists BOOLEAN;
|
||||
BEGIN
|
||||
-- Prüfe, ob es einen Foreign-Key-Constraint auf die users-Tabelle gibt
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.table_constraints tc
|
||||
JOIN information_schema.key_column_usage kcu
|
||||
ON tc.constraint_name = kcu.constraint_name
|
||||
WHERE tc.constraint_type = 'FOREIGN KEY'
|
||||
AND tc.table_schema = 'public'
|
||||
AND tc.table_name = 'conversations'
|
||||
AND kcu.column_name = 'user_id'
|
||||
) INTO fk_exists;
|
||||
|
||||
IF fk_exists THEN
|
||||
RAISE NOTICE 'Es gibt einen Foreign-Key-Constraint auf die user_id-Spalte in der conversations-Tabelle.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Es gibt keinen Foreign-Key-Constraint auf die user_id-Spalte in der conversations-Tabelle.';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 3. Überprüfe, ob der angemeldete Benutzer in der users-Tabelle existiert
|
||||
-- Ersetze 'DEINE_BENUTZER_ID' durch die tatsächliche Benutzer-ID
|
||||
DO $$
|
||||
DECLARE
|
||||
user_exists BOOLEAN;
|
||||
user_id_value UUID := auth.uid(); -- Aktuelle Benutzer-ID
|
||||
BEGIN
|
||||
-- Prüfe, ob der Benutzer in der users-Tabelle existiert
|
||||
EXECUTE format('
|
||||
SELECT EXISTS (
|
||||
SELECT FROM public.users
|
||||
WHERE id = %L
|
||||
)', user_id_value) INTO user_exists;
|
||||
|
||||
IF user_exists THEN
|
||||
RAISE NOTICE 'Der Benutzer mit der ID % existiert in der users-Tabelle.', user_id_value;
|
||||
ELSE
|
||||
RAISE NOTICE 'Der Benutzer mit der ID % existiert NICHT in der users-Tabelle.', user_id_value;
|
||||
|
||||
-- Füge den Benutzer manuell in die users-Tabelle ein
|
||||
EXECUTE format('
|
||||
INSERT INTO public.users (id, email, created_at, updated_at)
|
||||
SELECT id, email, created_at, updated_at
|
||||
FROM auth.users
|
||||
WHERE id = %L
|
||||
ON CONFLICT (id) DO NOTHING
|
||||
', user_id_value);
|
||||
|
||||
RAISE NOTICE 'Der Benutzer wurde in die users-Tabelle eingefügt.';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 4. Überprüfe, ob die Synchronisierung zwischen auth.users und public.users funktioniert
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Prüfe, ob der Trigger für die Synchronisierung existiert
|
||||
IF EXISTS (
|
||||
SELECT FROM pg_trigger
|
||||
WHERE tgname = 'sync_user_after_auth_event_trigger'
|
||||
) THEN
|
||||
RAISE NOTICE 'Der Trigger für die Synchronisierung zwischen auth.users und public.users existiert.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Der Trigger für die Synchronisierung zwischen auth.users und public.users existiert NICHT.';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 5. Synchronisiere alle Benutzer aus auth.users in public.users
|
||||
INSERT INTO public.users (id, email, name, created_at, updated_at)
|
||||
SELECT
|
||||
id,
|
||||
email,
|
||||
COALESCE(raw_user_meta_data->>'name', email) as name,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM auth.users
|
||||
WHERE confirmed_at IS NOT NULL
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
email = EXCLUDED.email,
|
||||
name = COALESCE(EXCLUDED.name, users.name),
|
||||
updated_at = NOW();
|
||||
46
apps/chat/apps/mobile/scripts/fix_messages_constraint.sql
Normal file
46
apps/chat/apps/mobile/scripts/fix_messages_constraint.sql
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
-- SQL-Skript, um die Nachrichtentabelle zu überprüfen und zu korrigieren
|
||||
|
||||
-- Überprüfe die aktuelle Struktur der messages-Tabelle
|
||||
SELECT
|
||||
column_name,
|
||||
data_type,
|
||||
is_nullable,
|
||||
column_default
|
||||
FROM
|
||||
information_schema.columns
|
||||
WHERE
|
||||
table_name = 'messages'
|
||||
ORDER BY
|
||||
ordinal_position;
|
||||
|
||||
-- Überprüfe Constraints für die messages-Tabelle
|
||||
SELECT
|
||||
tc.constraint_name,
|
||||
tc.constraint_type,
|
||||
kcu.column_name,
|
||||
cc.check_clause
|
||||
FROM
|
||||
information_schema.table_constraints tc
|
||||
JOIN
|
||||
information_schema.constraint_column_usage kcu
|
||||
ON tc.constraint_name = kcu.constraint_name
|
||||
LEFT JOIN
|
||||
information_schema.check_constraints cc
|
||||
ON tc.constraint_name = cc.constraint_name
|
||||
WHERE
|
||||
tc.table_name = 'messages';
|
||||
|
||||
-- Behebt das Problem mit der Check-Constraint in der messages-Tabelle
|
||||
-- Entfernt die bestehende Check-Constraint und erstellt eine neue, die 'assistant' akzeptiert
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Entferne die bestehende Check-Constraint
|
||||
ALTER TABLE messages DROP CONSTRAINT IF EXISTS messages_sender_check;
|
||||
|
||||
-- Erstelle eine neue Check-Constraint, die 'assistant' akzeptiert
|
||||
ALTER TABLE messages
|
||||
ADD CONSTRAINT messages_sender_check
|
||||
CHECK (sender IN ('user', 'assistant', 'system'));
|
||||
|
||||
RAISE NOTICE 'Check-Constraint für die sender-Spalte in der messages-Tabelle wurde aktualisiert.';
|
||||
END $$;
|
||||
27
apps/chat/apps/mobile/scripts/fix_models_table.sql
Normal file
27
apps/chat/apps/mobile/scripts/fix_models_table.sql
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
-- Überprüfe die aktuelle Struktur der models-Tabelle
|
||||
SELECT column_name, data_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'models';
|
||||
|
||||
-- Füge die fehlenden Spalten hinzu, wenn sie nicht existieren
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Überprüfe, ob created_at existiert
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'models' AND column_name = 'created_at'
|
||||
) THEN
|
||||
ALTER TABLE models ADD COLUMN created_at TIMESTAMPTZ DEFAULT now();
|
||||
END IF;
|
||||
|
||||
-- Überprüfe, ob updated_at existiert
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'models' AND column_name = 'updated_at'
|
||||
) THEN
|
||||
ALTER TABLE models ADD COLUMN updated_at TIMESTAMPTZ DEFAULT now();
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
157
apps/chat/apps/mobile/scripts/fix_rls_policies.sql
Normal file
157
apps/chat/apps/mobile/scripts/fix_rls_policies.sql
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
-- RLS-Richtlinien für die Conversations-Tabelle
|
||||
|
||||
-- Aktiviere RLS für die Conversations-Tabelle
|
||||
ALTER TABLE conversations ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Löschen vorhandener Richtlinien (falls vorhanden)
|
||||
DROP POLICY IF EXISTS conversations_insert_policy ON conversations;
|
||||
DROP POLICY IF EXISTS conversations_select_policy ON conversations;
|
||||
DROP POLICY IF EXISTS conversations_update_policy ON conversations;
|
||||
DROP POLICY IF EXISTS conversations_delete_policy ON conversations;
|
||||
|
||||
-- Erstelle eine Richtlinie für das Einfügen von Konversationen
|
||||
-- Benutzer dürfen nur Konversationen für sich selbst erstellen
|
||||
CREATE POLICY conversations_insert_policy
|
||||
ON conversations
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (auth.uid() = user_id);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Lesen von Konversationen
|
||||
-- Benutzer dürfen nur ihre eigenen Konversationen sehen
|
||||
CREATE POLICY conversations_select_policy
|
||||
ON conversations
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Aktualisieren von Konversationen
|
||||
-- Benutzer dürfen nur ihre eigenen Konversationen aktualisieren
|
||||
CREATE POLICY conversations_update_policy
|
||||
ON conversations
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Löschen von Konversationen
|
||||
-- Benutzer dürfen nur ihre eigenen Konversationen löschen
|
||||
CREATE POLICY conversations_delete_policy
|
||||
ON conversations
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- RLS-Richtlinien für die Messages-Tabelle
|
||||
|
||||
-- Aktiviere RLS für die Messages-Tabelle
|
||||
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Löschen vorhandener Richtlinien (falls vorhanden)
|
||||
DROP POLICY IF EXISTS messages_insert_policy ON messages;
|
||||
DROP POLICY IF EXISTS messages_select_policy ON messages;
|
||||
DROP POLICY IF EXISTS messages_update_policy ON messages;
|
||||
DROP POLICY IF EXISTS messages_delete_policy ON messages;
|
||||
|
||||
-- Erstelle eine Richtlinie für das Einfügen von Nachrichten
|
||||
-- Benutzer dürfen nur Nachrichten zu ihren eigenen Konversationen hinzufügen
|
||||
CREATE POLICY messages_insert_policy
|
||||
ON messages
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (
|
||||
conversation_id IN (
|
||||
SELECT id FROM conversations WHERE user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Lesen von Nachrichten
|
||||
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen sehen
|
||||
CREATE POLICY messages_select_policy
|
||||
ON messages
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (
|
||||
conversation_id IN (
|
||||
SELECT id FROM conversations WHERE user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Aktualisieren von Nachrichten
|
||||
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen aktualisieren
|
||||
CREATE POLICY messages_update_policy
|
||||
ON messages
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (
|
||||
conversation_id IN (
|
||||
SELECT id FROM conversations WHERE user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Löschen von Nachrichten
|
||||
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen löschen
|
||||
CREATE POLICY messages_delete_policy
|
||||
ON messages
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (
|
||||
conversation_id IN (
|
||||
SELECT id FROM conversations WHERE user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- RLS-Richtlinien für die Models-Tabelle
|
||||
|
||||
-- Aktiviere RLS für die Models-Tabelle
|
||||
ALTER TABLE models ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Löschen vorhandener Richtlinien (falls vorhanden)
|
||||
DROP POLICY IF EXISTS models_select_policy ON models;
|
||||
|
||||
-- Erstelle eine Richtlinie für das Lesen von Modellen
|
||||
-- Alle authentifizierten Benutzer dürfen Modelle sehen
|
||||
CREATE POLICY models_select_policy
|
||||
ON models
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (true);
|
||||
|
||||
-- Erstelle eine Bypass-Richtlinie für Anon-Benutzer, um Modelle zu sehen
|
||||
-- Dies ist wichtig für die API-Route, die Modelle abruft
|
||||
CREATE POLICY models_anon_select_policy
|
||||
ON models
|
||||
FOR SELECT
|
||||
TO anon
|
||||
USING (true);
|
||||
|
||||
-- RLS-Richtlinien für die Templates-Tabelle (falls vorhanden)
|
||||
|
||||
-- Aktiviere RLS für die Templates-Tabelle (nur wenn sie existiert)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'templates'
|
||||
) THEN
|
||||
EXECUTE 'ALTER TABLE templates ENABLE ROW LEVEL SECURITY;';
|
||||
|
||||
-- Löschen vorhandener Richtlinien (falls vorhanden)
|
||||
EXECUTE 'DROP POLICY IF EXISTS templates_select_policy ON templates;';
|
||||
|
||||
-- Erstelle eine Richtlinie für das Lesen von Templates
|
||||
EXECUTE 'CREATE POLICY templates_select_policy
|
||||
ON templates
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (true);';
|
||||
|
||||
-- Erstelle eine Bypass-Richtlinie für Anon-Benutzer, um Templates zu sehen
|
||||
EXECUTE 'CREATE POLICY templates_anon_select_policy
|
||||
ON templates
|
||||
FOR SELECT
|
||||
TO anon
|
||||
USING (true);';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
73
apps/chat/apps/mobile/scripts/fix_templates_table.sql
Normal file
73
apps/chat/apps/mobile/scripts/fix_templates_table.sql
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
-- Überprüfe und korrigiere die templates-Tabelle
|
||||
|
||||
-- 1. Prüfe, ob die templates-Tabelle existiert, erstelle sie falls nicht
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'templates'
|
||||
) THEN
|
||||
-- Erstelle die Tabelle für Vorlagen
|
||||
CREATE TABLE public.templates (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
system_prompt TEXT NOT NULL,
|
||||
initial_question TEXT,
|
||||
model_id UUID REFERENCES models(id),
|
||||
color TEXT DEFAULT '#0A84FF',
|
||||
is_default BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
|
||||
);
|
||||
|
||||
RAISE NOTICE 'Tabelle templates wurde erstellt.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Tabelle templates existiert bereits.';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- 2. Prüfe, ob die color-Spalte existiert, füge sie hinzu falls nicht
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'templates'
|
||||
AND column_name = 'color'
|
||||
) THEN
|
||||
ALTER TABLE public.templates ADD COLUMN color TEXT DEFAULT '#0A84FF';
|
||||
RAISE NOTICE 'Spalte color zur templates-Tabelle hinzugefügt.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Spalte color existiert bereits in der templates-Tabelle.';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- 3. Row Level Security
|
||||
ALTER TABLE templates ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Lösche bestehende Policies, falls vorhanden
|
||||
DROP POLICY IF EXISTS "Users can view their own templates" ON templates;
|
||||
DROP POLICY IF EXISTS "Users can create their own templates" ON templates;
|
||||
DROP POLICY IF EXISTS "Users can update their own templates" ON templates;
|
||||
DROP POLICY IF EXISTS "Users can delete their own templates" ON templates;
|
||||
|
||||
-- Erstelle die Policies neu
|
||||
CREATE POLICY "Users can view their own templates" ON templates
|
||||
FOR SELECT USING (user_id = auth.uid());
|
||||
|
||||
CREATE POLICY "Users can create their own templates" ON templates
|
||||
FOR INSERT WITH CHECK (user_id = auth.uid());
|
||||
|
||||
CREATE POLICY "Users can update their own templates" ON templates
|
||||
FOR UPDATE USING (user_id = auth.uid());
|
||||
|
||||
CREATE POLICY "Users can delete their own templates" ON templates
|
||||
FOR DELETE USING (user_id = auth.uid());
|
||||
|
||||
-- 4. Zeige einige Beispieldaten an
|
||||
SELECT id, name, description, color FROM templates LIMIT 5;
|
||||
115
apps/chat/apps/mobile/scripts/setup_rls_policies.sql
Normal file
115
apps/chat/apps/mobile/scripts/setup_rls_policies.sql
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
-- RLS-Richtlinien für die Conversations-Tabelle
|
||||
|
||||
-- Aktiviere RLS für die Conversations-Tabelle
|
||||
ALTER TABLE conversations ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Erstelle eine Richtlinie für das Einfügen von Konversationen
|
||||
-- Benutzer dürfen nur Konversationen für sich selbst erstellen
|
||||
CREATE POLICY conversations_insert_policy
|
||||
ON conversations
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (auth.uid() = user_id);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Lesen von Konversationen
|
||||
-- Benutzer dürfen nur ihre eigenen Konversationen sehen
|
||||
CREATE POLICY conversations_select_policy
|
||||
ON conversations
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Aktualisieren von Konversationen
|
||||
-- Benutzer dürfen nur ihre eigenen Konversationen aktualisieren
|
||||
CREATE POLICY conversations_update_policy
|
||||
ON conversations
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Löschen von Konversationen
|
||||
-- Benutzer dürfen nur ihre eigenen Konversationen löschen
|
||||
CREATE POLICY conversations_delete_policy
|
||||
ON conversations
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- RLS-Richtlinien für die Messages-Tabelle
|
||||
|
||||
-- Aktiviere RLS für die Messages-Tabelle
|
||||
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Erstelle eine Richtlinie für das Einfügen von Nachrichten
|
||||
-- Benutzer dürfen nur Nachrichten zu ihren eigenen Konversationen hinzufügen
|
||||
CREATE POLICY messages_insert_policy
|
||||
ON messages
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (
|
||||
conversation_id IN (
|
||||
SELECT id FROM conversations WHERE user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Lesen von Nachrichten
|
||||
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen sehen
|
||||
CREATE POLICY messages_select_policy
|
||||
ON messages
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (
|
||||
conversation_id IN (
|
||||
SELECT id FROM conversations WHERE user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Aktualisieren von Nachrichten
|
||||
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen aktualisieren
|
||||
CREATE POLICY messages_update_policy
|
||||
ON messages
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (
|
||||
conversation_id IN (
|
||||
SELECT id FROM conversations WHERE user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Erstelle eine Richtlinie für das Löschen von Nachrichten
|
||||
-- Benutzer dürfen nur Nachrichten aus ihren eigenen Konversationen löschen
|
||||
CREATE POLICY messages_delete_policy
|
||||
ON messages
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (
|
||||
conversation_id IN (
|
||||
SELECT id FROM conversations WHERE user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- RLS-Richtlinien für die Models-Tabelle
|
||||
|
||||
-- Aktiviere RLS für die Models-Tabelle
|
||||
ALTER TABLE models ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Erstelle eine Richtlinie für das Lesen von Modellen
|
||||
-- Alle authentifizierten Benutzer dürfen Modelle sehen
|
||||
CREATE POLICY models_select_policy
|
||||
ON models
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (true);
|
||||
|
||||
-- RLS-Richtlinien für die Templates-Tabelle
|
||||
|
||||
-- Aktiviere RLS für die Templates-Tabelle
|
||||
ALTER TABLE templates ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Erstelle eine Richtlinie für das Lesen von Templates
|
||||
-- Alle authentifizierten Benutzer dürfen Templates sehen
|
||||
CREATE POLICY templates_select_policy
|
||||
ON templates
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (true);
|
||||
136
apps/chat/apps/mobile/scripts/setup_supabase.js
Normal file
136
apps/chat/apps/mobile/scripts/setup_supabase.js
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// Skript zum Einrichten von Supabase-Funktionen und Tabellen
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import dotenv from 'dotenv';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
// Lade Umgebungsvariablen aus .env
|
||||
dotenv.config();
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Supabase-Client erstellen
|
||||
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL;
|
||||
const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
|
||||
|
||||
if (!supabaseUrl || !supabaseKey) {
|
||||
console.error('Fehler: EXPO_PUBLIC_SUPABASE_URL und EXPO_PUBLIC_SUPABASE_ANON_KEY müssen in der .env-Datei definiert sein.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||||
|
||||
// Funktion zum Ausführen einer SQL-Datei
|
||||
async function executeSqlFile(filePath) {
|
||||
try {
|
||||
const fullPath = join(__dirname, filePath);
|
||||
console.log(`Führe SQL-Datei aus: ${fullPath}`);
|
||||
|
||||
if (!fs.existsSync(fullPath)) {
|
||||
console.error(`Fehler: Datei ${fullPath} existiert nicht.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const query = fs.readFileSync(fullPath, 'utf8');
|
||||
|
||||
// Teile die Abfrage in einzelne Anweisungen auf
|
||||
const statements = query.split(';').filter(stmt => stmt.trim() !== '');
|
||||
|
||||
for (const statement of statements) {
|
||||
console.log(`Führe aus: ${statement.trim()}`);
|
||||
const { error } = await supabase.rpc('execute_sql', { query: statement.trim() });
|
||||
|
||||
if (error) {
|
||||
console.error('Fehler bei der Ausführung:', error.message);
|
||||
// Fahre trotz Fehler fort
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Lesen oder Ausführen der Datei:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zum Erstellen der execute_sql-Funktion
|
||||
async function createExecuteSqlFunction() {
|
||||
try {
|
||||
console.log('Erstelle execute_sql-Funktion...');
|
||||
|
||||
const query = `
|
||||
CREATE OR REPLACE FUNCTION execute_sql(query text)
|
||||
RETURNS JSONB
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
result JSONB;
|
||||
BEGIN
|
||||
EXECUTE 'SELECT jsonb_agg(row_to_json(t)) FROM (' || query || ') t' INTO result;
|
||||
RETURN COALESCE(result, '[]'::jsonb);
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
RAISE EXCEPTION 'SQL-Fehler: %', SQLERRM;
|
||||
END;
|
||||
$$;
|
||||
`;
|
||||
|
||||
const { error } = await supabase.rpc('execute_sql', { query });
|
||||
|
||||
if (error) {
|
||||
// Die Funktion existiert möglicherweise noch nicht, versuche direkte SQL-Ausführung
|
||||
console.log('Versuche direkte SQL-Ausführung...');
|
||||
|
||||
const { error: directError } = await supabase
|
||||
.from('_exec_sql')
|
||||
.insert({ sql: query });
|
||||
|
||||
if (directError) {
|
||||
console.error('Fehler beim Erstellen der execute_sql-Funktion:', directError.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('execute_sql-Funktion erfolgreich erstellt.');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Unerwarteter Fehler:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Hauptfunktion
|
||||
async function setupSupabase() {
|
||||
console.log('Starte Supabase-Setup...');
|
||||
|
||||
// Erstelle die execute_sql-Funktion
|
||||
const execSqlCreated = await createExecuteSqlFunction();
|
||||
|
||||
if (!execSqlCreated) {
|
||||
console.log('Konnte execute_sql-Funktion nicht erstellen. Versuche trotzdem fortzufahren...');
|
||||
}
|
||||
|
||||
// Führe die SQL-Dateien aus
|
||||
console.log('Führe Supabase-Funktionen-Setup aus...');
|
||||
await executeSqlFile('setup_supabase_functions.sql');
|
||||
|
||||
console.log('Führe Modell-Updates aus...');
|
||||
await executeSqlFile('update_models.sql');
|
||||
|
||||
console.log('Richte RLS-Richtlinien ein...');
|
||||
await executeSqlFile('setup_rls_policies.sql');
|
||||
|
||||
console.log('Supabase-Setup abgeschlossen.');
|
||||
}
|
||||
|
||||
// Führe die Funktion aus
|
||||
setupSupabase()
|
||||
.catch(error => {
|
||||
console.error('Unerwarteter Fehler:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
52
apps/chat/apps/mobile/scripts/setup_supabase_functions.sql
Normal file
52
apps/chat/apps/mobile/scripts/setup_supabase_functions.sql
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
-- Erstelle eine Funktion zum Ausführen von SQL-Abfragen
|
||||
CREATE OR REPLACE FUNCTION execute_sql(query text)
|
||||
RETURNS JSONB
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
result JSONB;
|
||||
BEGIN
|
||||
EXECUTE 'SELECT jsonb_agg(row_to_json(t)) FROM (' || query || ') t' INTO result;
|
||||
RETURN COALESCE(result, '[]'::jsonb);
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
RAISE EXCEPTION 'SQL-Fehler: %', SQLERRM;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- Erstelle eine Funktion zum Erstellen der models-Tabelle, falls sie nicht existiert
|
||||
CREATE OR REPLACE FUNCTION create_models_table()
|
||||
RETURNS VOID
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
BEGIN
|
||||
-- Prüfe, ob die Tabelle bereits existiert
|
||||
IF NOT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'models'
|
||||
) THEN
|
||||
-- Erstelle die Tabelle
|
||||
CREATE TABLE models (
|
||||
id UUID PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
parameters JSONB,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Erstelle einen Trigger für updated_at
|
||||
CREATE TRIGGER set_updated_at
|
||||
BEFORE UPDATE ON models
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at();
|
||||
|
||||
RAISE NOTICE 'Tabelle models wurde erstellt.';
|
||||
ELSE
|
||||
RAISE NOTICE 'Tabelle models existiert bereits.';
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
176
apps/chat/apps/mobile/scripts/spaces/create_spaces_rls.sql
Normal file
176
apps/chat/apps/mobile/scripts/spaces/create_spaces_rls.sql
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
-- Enable Row Level Security for spaces tables
|
||||
ALTER TABLE public.spaces ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.space_members ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- RLS policies for spaces
|
||||
|
||||
-- Space owners can do everything with their spaces
|
||||
CREATE POLICY spaces_owner_policy
|
||||
ON public.spaces
|
||||
TO authenticated
|
||||
USING (owner_id = auth.uid());
|
||||
|
||||
-- Members can view spaces they belong to
|
||||
CREATE POLICY spaces_member_select_policy
|
||||
ON public.spaces
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (
|
||||
id IN (
|
||||
SELECT space_id
|
||||
FROM public.space_members
|
||||
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
|
||||
)
|
||||
);
|
||||
|
||||
-- RLS policies for space_members
|
||||
|
||||
-- Space owners can manage all members
|
||||
CREATE POLICY space_members_owner_policy
|
||||
ON public.space_members
|
||||
TO authenticated
|
||||
USING (
|
||||
space_id IN (
|
||||
SELECT id FROM public.spaces WHERE owner_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Space admins can manage members (except owners)
|
||||
CREATE POLICY space_members_admin_policy
|
||||
ON public.space_members
|
||||
TO authenticated
|
||||
USING (
|
||||
space_id IN (
|
||||
SELECT space_id FROM public.space_members
|
||||
WHERE user_id = auth.uid() AND role = 'admin' AND invitation_status = 'accepted'
|
||||
)
|
||||
AND role != 'owner'
|
||||
);
|
||||
|
||||
-- Users can see which spaces they are members of
|
||||
CREATE POLICY space_members_self_select_policy
|
||||
ON public.space_members
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid());
|
||||
|
||||
-- Users can accept/decline their own invitations
|
||||
CREATE POLICY space_members_invitation_update_policy
|
||||
ON public.space_members
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid())
|
||||
WITH CHECK (
|
||||
user_id = auth.uid()
|
||||
AND (OLD.invitation_status = 'pending')
|
||||
AND (NEW.invitation_status IN ('accepted', 'declined'))
|
||||
AND (OLD.role = NEW.role)
|
||||
AND (OLD.space_id = NEW.space_id)
|
||||
AND (OLD.user_id = NEW.user_id)
|
||||
);
|
||||
|
||||
-- Update RLS policies for conversations
|
||||
|
||||
-- Modify existing policies to include space-based access
|
||||
DROP POLICY IF EXISTS conversations_select_policy ON conversations;
|
||||
CREATE POLICY conversations_select_policy
|
||||
ON conversations
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (
|
||||
user_id = auth.uid()
|
||||
OR
|
||||
(
|
||||
space_id IN (
|
||||
SELECT space_id FROM public.space_members
|
||||
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Allow space members to create conversations in spaces they belong to
|
||||
CREATE POLICY conversations_space_insert_policy
|
||||
ON conversations
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (
|
||||
user_id = auth.uid()
|
||||
AND
|
||||
(
|
||||
space_id IS NULL
|
||||
OR
|
||||
space_id IN (
|
||||
SELECT space_id FROM public.space_members
|
||||
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Allow updates to conversations in spaces based on role
|
||||
DROP POLICY IF EXISTS conversations_update_policy ON conversations;
|
||||
CREATE POLICY conversations_update_policy
|
||||
ON conversations
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (
|
||||
user_id = auth.uid()
|
||||
OR
|
||||
(
|
||||
space_id IN (
|
||||
SELECT sm.space_id FROM public.space_members sm
|
||||
WHERE sm.user_id = auth.uid()
|
||||
AND sm.invitation_status = 'accepted'
|
||||
AND sm.role IN ('owner', 'admin')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Allow deletion of conversations in spaces based on role
|
||||
DROP POLICY IF EXISTS conversations_delete_policy ON conversations;
|
||||
CREATE POLICY conversations_delete_policy
|
||||
ON conversations
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (
|
||||
user_id = auth.uid()
|
||||
OR
|
||||
(
|
||||
space_id IN (
|
||||
SELECT sm.space_id FROM public.space_members sm
|
||||
WHERE sm.user_id = auth.uid()
|
||||
AND sm.invitation_status = 'accepted'
|
||||
AND sm.role IN ('owner', 'admin')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Helper function to check if a user has access to a space
|
||||
CREATE OR REPLACE FUNCTION public.user_has_space_access(space_uuid UUID, role_level TEXT DEFAULT 'viewer')
|
||||
RETURNS BOOLEAN AS $$
|
||||
DECLARE
|
||||
has_access BOOLEAN;
|
||||
role_hierarchy TEXT[];
|
||||
BEGIN
|
||||
-- Define role hierarchy from highest to lowest
|
||||
role_hierarchy := ARRAY['owner', 'admin', 'member', 'viewer'];
|
||||
|
||||
-- Find position of requested role in hierarchy
|
||||
WITH role_positions AS (
|
||||
SELECT
|
||||
unnest(role_hierarchy) AS role,
|
||||
row_number() OVER () AS position
|
||||
)
|
||||
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM public.space_members sm
|
||||
JOIN role_positions rp1 ON sm.role = rp1.role
|
||||
JOIN role_positions rp2 ON rp2.role = role_level
|
||||
WHERE sm.space_id = space_uuid
|
||||
AND sm.user_id = auth.uid()
|
||||
AND sm.invitation_status = 'accepted'
|
||||
AND rp1.position <= rp2.position -- Check if user's role is at least the required level
|
||||
) INTO has_access;
|
||||
|
||||
RETURN has_access;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
-- Create spaces table
|
||||
CREATE TABLE IF NOT EXISTS public.spaces (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
owner_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
is_archived BOOLEAN DEFAULT false
|
||||
);
|
||||
|
||||
-- Add comments for documentation
|
||||
COMMENT ON TABLE public.spaces IS 'Collaborative spaces for organizing conversations';
|
||||
COMMENT ON COLUMN spaces.name IS 'Name of the space';
|
||||
COMMENT ON COLUMN spaces.description IS 'Optional description of the space';
|
||||
COMMENT ON COLUMN spaces.owner_id IS 'User ID of the space owner';
|
||||
COMMENT ON COLUMN spaces.is_archived IS 'Indicates whether the space is archived';
|
||||
|
||||
-- Create space_members table with roles/permissions
|
||||
CREATE TABLE IF NOT EXISTS public.space_members (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
space_id UUID NOT NULL REFERENCES public.spaces(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
|
||||
role TEXT NOT NULL CHECK (role IN ('owner', 'admin', 'member', 'viewer')),
|
||||
invitation_status TEXT NOT NULL DEFAULT 'pending' CHECK (invitation_status IN ('pending', 'accepted', 'declined')),
|
||||
invited_by UUID REFERENCES public.users(id),
|
||||
invited_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
joined_at TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
UNIQUE(space_id, user_id)
|
||||
);
|
||||
|
||||
-- Add comments for space_members
|
||||
COMMENT ON TABLE public.space_members IS 'Members of collaborative spaces with defined roles';
|
||||
COMMENT ON COLUMN space_members.role IS 'Role of the user in the space (owner, admin, member, viewer)';
|
||||
COMMENT ON COLUMN space_members.invitation_status IS 'Status of the invitation (pending, accepted, declined)';
|
||||
|
||||
-- Modify conversations table to add space_id
|
||||
ALTER TABLE public.conversations
|
||||
ADD COLUMN IF NOT EXISTS space_id UUID REFERENCES public.spaces(id) ON DELETE SET NULL;
|
||||
|
||||
-- Create indexes for faster queries
|
||||
CREATE INDEX IF NOT EXISTS idx_conversations_space_id ON conversations(space_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_conversations_space_user ON conversations(space_id, user_id);
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
-- Create updated_at trigger for spaces
|
||||
CREATE OR REPLACE FUNCTION set_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Apply updated_at trigger to spaces table if it doesn't exist
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'set_spaces_updated_at'
|
||||
) THEN
|
||||
CREATE TRIGGER set_spaces_updated_at
|
||||
BEFORE UPDATE ON public.spaces
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at();
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- Apply updated_at trigger to space_members table if it doesn't exist
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'set_space_members_updated_at'
|
||||
) THEN
|
||||
CREATE TRIGGER set_space_members_updated_at
|
||||
BEFORE UPDATE ON public.space_members
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_updated_at();
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- Automatically add space owner as member with owner role
|
||||
CREATE OR REPLACE FUNCTION add_owner_to_space_members()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
INSERT INTO public.space_members (
|
||||
space_id,
|
||||
user_id,
|
||||
role,
|
||||
invitation_status,
|
||||
joined_at
|
||||
)
|
||||
VALUES (
|
||||
NEW.id,
|
||||
NEW.owner_id,
|
||||
'owner',
|
||||
'accepted',
|
||||
NOW()
|
||||
);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Apply owner trigger to spaces table if it doesn't exist
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'add_owner_to_space_members_trigger'
|
||||
) THEN
|
||||
CREATE TRIGGER add_owner_to_space_members_trigger
|
||||
AFTER INSERT ON public.spaces
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION add_owner_to_space_members();
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- Update space modification timestamp when members are added/changed
|
||||
CREATE OR REPLACE FUNCTION update_space_timestamp_on_member_change()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
UPDATE public.spaces
|
||||
SET updated_at = NOW()
|
||||
WHERE id = NEW.space_id;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Apply space timestamp update trigger if it doesn't exist
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'update_space_timestamp_trigger'
|
||||
) THEN
|
||||
CREATE TRIGGER update_space_timestamp_trigger
|
||||
AFTER INSERT OR UPDATE ON public.space_members
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_space_timestamp_on_member_change();
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
86
apps/chat/apps/mobile/scripts/spaces/fix_rls_policies.sql
Normal file
86
apps/chat/apps/mobile/scripts/spaces/fix_rls_policies.sql
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
-- Drop problematic policies that cause infinite recursion
|
||||
DROP POLICY IF EXISTS space_members_owner_policy ON space_members;
|
||||
DROP POLICY IF EXISTS space_members_admin_policy ON space_members;
|
||||
DROP POLICY IF EXISTS space_members_self_select_policy ON space_members;
|
||||
DROP POLICY IF EXISTS space_members_invitation_update_policy ON space_members;
|
||||
DROP POLICY IF EXISTS conversations_select_policy ON conversations;
|
||||
DROP POLICY IF EXISTS conversations_space_insert_policy ON conversations;
|
||||
DROP POLICY IF EXISTS conversations_update_policy ON conversations;
|
||||
DROP POLICY IF EXISTS conversations_delete_policy ON conversations;
|
||||
|
||||
-- Recreate RLS policies for space_members (simplified to avoid recursion)
|
||||
CREATE POLICY space_members_owner_policy
|
||||
ON public.space_members
|
||||
TO authenticated
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.spaces
|
||||
WHERE id = space_id AND owner_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Users can see which spaces they are members of
|
||||
CREATE POLICY space_members_self_select_policy
|
||||
ON public.space_members
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid());
|
||||
|
||||
-- Users can accept/decline their own invitations
|
||||
CREATE POLICY space_members_invitation_update_policy
|
||||
ON public.space_members
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid())
|
||||
WITH CHECK (
|
||||
user_id = auth.uid()
|
||||
AND invitation_status = 'pending'
|
||||
);
|
||||
|
||||
-- Create simplified policies for conversations
|
||||
|
||||
-- Allow users to see their own conversations or shared with them
|
||||
CREATE POLICY conversations_select_policy
|
||||
ON conversations
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (
|
||||
user_id = auth.uid()
|
||||
OR
|
||||
space_id IN (
|
||||
SELECT space_id FROM public.space_members
|
||||
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
|
||||
)
|
||||
);
|
||||
|
||||
-- Allow users to create conversations in spaces they belong to
|
||||
CREATE POLICY conversations_space_insert_policy
|
||||
ON conversations
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (
|
||||
user_id = auth.uid()
|
||||
AND
|
||||
(
|
||||
space_id IS NULL
|
||||
OR
|
||||
space_id IN (
|
||||
SELECT space_id FROM public.space_members
|
||||
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Allow users to update their own conversations
|
||||
CREATE POLICY conversations_update_policy
|
||||
ON conversations
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid());
|
||||
|
||||
-- Allow users to delete their own conversations
|
||||
CREATE POLICY conversations_delete_policy
|
||||
ON conversations
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid());
|
||||
69
apps/chat/apps/mobile/scripts/spaces/fix_rls_policies_v2.sql
Normal file
69
apps/chat/apps/mobile/scripts/spaces/fix_rls_policies_v2.sql
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
-- Completely drop ALL RLS policies for the affected tables
|
||||
DROP POLICY IF EXISTS spaces_owner_policy ON spaces;
|
||||
DROP POLICY IF EXISTS spaces_member_select_policy ON spaces;
|
||||
DROP POLICY IF EXISTS space_members_owner_policy ON space_members;
|
||||
DROP POLICY IF EXISTS space_members_admin_policy ON space_members;
|
||||
DROP POLICY IF EXISTS space_members_self_select_policy ON space_members;
|
||||
DROP POLICY IF EXISTS space_members_invitation_update_policy ON space_members;
|
||||
DROP POLICY IF EXISTS conversations_select_policy ON conversations;
|
||||
DROP POLICY IF EXISTS conversations_space_insert_policy ON conversations;
|
||||
DROP POLICY IF EXISTS conversations_update_policy ON conversations;
|
||||
DROP POLICY IF EXISTS conversations_delete_policy ON conversations;
|
||||
|
||||
-- Create minimal basic policies for spaces
|
||||
CREATE POLICY spaces_select_policy
|
||||
ON public.spaces
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (true); -- Allow all users to see all spaces for now
|
||||
|
||||
CREATE POLICY spaces_insert_policy
|
||||
ON public.spaces
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (owner_id = auth.uid()); -- Only allow users to create spaces where they are the owner
|
||||
|
||||
-- Create minimal basic policies for space_members
|
||||
CREATE POLICY space_members_select_policy
|
||||
ON public.space_members
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (true); -- Allow all users to see all space members for now
|
||||
|
||||
CREATE POLICY space_members_insert_policy
|
||||
ON public.space_members
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (true); -- Allow all insertions for now
|
||||
|
||||
CREATE POLICY space_members_update_policy
|
||||
ON public.space_members
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (true) -- Allow all updates for now
|
||||
WITH CHECK (true);
|
||||
|
||||
-- Revert conversations back to simple user-based policies
|
||||
CREATE POLICY conversations_select_policy
|
||||
ON conversations
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid()); -- Only see your own conversations
|
||||
|
||||
CREATE POLICY conversations_insert_policy
|
||||
ON conversations
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (user_id = auth.uid()); -- Only create your own conversations
|
||||
|
||||
CREATE POLICY conversations_update_policy
|
||||
ON conversations
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid()); -- Only update your own conversations
|
||||
|
||||
CREATE POLICY conversations_delete_policy
|
||||
ON conversations
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid()); -- Only delete your own conversations
|
||||
83
apps/chat/apps/mobile/scripts/spaces/setup_spaces.js
Executable file
83
apps/chat/apps/mobile/scripts/spaces/setup_spaces.js
Executable file
|
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* This script sets up the spaces feature by running the necessary SQL scripts
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { spawnSync } = require('child_process');
|
||||
const { createClient } = require('@supabase/supabase-js');
|
||||
|
||||
// Get environment variables
|
||||
const SUPABASE_URL = process.env.SUPABASE_URL;
|
||||
const SUPABASE_SERVICE_KEY = process.env.SUPABASE_SERVICE_KEY;
|
||||
|
||||
if (!SUPABASE_URL || !SUPABASE_SERVICE_KEY) {
|
||||
console.error('Error: SUPABASE_URL and SUPABASE_SERVICE_KEY environment variables must be set');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Create Supabase client
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_KEY, {
|
||||
auth: {
|
||||
autoRefreshToken: false,
|
||||
persistSession: false
|
||||
}
|
||||
});
|
||||
|
||||
async function executeSQL(filename) {
|
||||
try {
|
||||
const filePath = path.join(__dirname, filename);
|
||||
const sql = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
// Split the SQL file by semicolons to get individual statements
|
||||
const statements = sql
|
||||
.split(';')
|
||||
.map(statement => statement.trim())
|
||||
.filter(statement => statement.length > 0);
|
||||
|
||||
console.log(`Executing ${statements.length} statements from ${filename}...`);
|
||||
|
||||
for (const statement of statements) {
|
||||
const { error } = await supabase.rpc('exec_sql', { sql: statement });
|
||||
|
||||
if (error) {
|
||||
console.error(`Error executing statement:`, error);
|
||||
console.error(`Statement was: ${statement.substring(0, 100)}...`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ Successfully executed ${filename}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`❌ Error executing ${filename}:`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('Setting up spaces feature...');
|
||||
|
||||
// Run the SQL scripts in the correct order
|
||||
const scripts = [
|
||||
'create_spaces_tables.sql',
|
||||
'create_spaces_triggers.sql',
|
||||
'create_spaces_rls.sql'
|
||||
];
|
||||
|
||||
for (const script of scripts) {
|
||||
const success = await executeSQL(script);
|
||||
if (!success) {
|
||||
console.error(`Failed to execute ${script}. Aborting.`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Spaces feature setup complete!');
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('Unhandled error:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
167
apps/chat/apps/mobile/scripts/supabase-cli.js
Normal file
167
apps/chat/apps/mobile/scripts/supabase-cli.js
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
#!/usr/bin/env node
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import dotenv from 'dotenv';
|
||||
import readline from 'readline';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
// Lade Umgebungsvariablen aus .env
|
||||
dotenv.config();
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Supabase-Client erstellen
|
||||
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL;
|
||||
const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
|
||||
|
||||
if (!supabaseUrl || !supabaseKey) {
|
||||
console.error('Fehler: EXPO_PUBLIC_SUPABASE_URL und EXPO_PUBLIC_SUPABASE_ANON_KEY müssen in der .env-Datei definiert sein.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||||
|
||||
// Readline-Interface für interaktive Eingabe
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
// Funktion zum Ausführen einer SQL-Abfrage
|
||||
async function executeQuery(query) {
|
||||
try {
|
||||
console.log(`Führe Abfrage aus: ${query}`);
|
||||
const { data, error } = await supabase.rpc('execute_sql', { query });
|
||||
|
||||
if (error) {
|
||||
console.error('Fehler bei der Ausführung der Abfrage:', error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Ergebnis:');
|
||||
console.table(data);
|
||||
} catch (error) {
|
||||
console.error('Unerwarteter Fehler:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zum Ausführen einer SQL-Datei
|
||||
async function executeFile(filePath) {
|
||||
try {
|
||||
const fullPath = join(process.cwd(), filePath);
|
||||
console.log(`Führe SQL-Datei aus: ${fullPath}`);
|
||||
|
||||
if (!fs.existsSync(fullPath)) {
|
||||
console.error(`Fehler: Datei ${fullPath} existiert nicht.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const query = fs.readFileSync(fullPath, 'utf8');
|
||||
await executeQuery(query);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Lesen oder Ausführen der Datei:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zum Anzeigen der Tabellenliste
|
||||
async function listTables() {
|
||||
try {
|
||||
const query = `
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
ORDER BY table_name;
|
||||
`;
|
||||
|
||||
const { data, error } = await supabase.rpc('execute_sql', { query });
|
||||
|
||||
if (error) {
|
||||
console.error('Fehler beim Abrufen der Tabellenliste:', error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Verfügbare Tabellen:');
|
||||
data.forEach((row, index) => {
|
||||
console.log(`${index + 1}. ${row.table_name}`);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Unerwarteter Fehler:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zum Anzeigen der Tabellenstruktur
|
||||
async function describeTable(tableName) {
|
||||
try {
|
||||
const query = `
|
||||
SELECT column_name, data_type, is_nullable
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public' AND table_name = '${tableName}'
|
||||
ORDER BY ordinal_position;
|
||||
`;
|
||||
|
||||
const { data, error } = await supabase.rpc('execute_sql', { query });
|
||||
|
||||
if (error) {
|
||||
console.error(`Fehler beim Beschreiben der Tabelle ${tableName}:`, error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Struktur der Tabelle ${tableName}:`);
|
||||
console.table(data);
|
||||
} catch (error) {
|
||||
console.error('Unerwarteter Fehler:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Hauptmenü
|
||||
function showMenu() {
|
||||
console.log('\n--- Supabase CLI ---');
|
||||
console.log('1. SQL-Abfrage ausführen');
|
||||
console.log('2. SQL-Datei ausführen');
|
||||
console.log('3. Tabellenliste anzeigen');
|
||||
console.log('4. Tabellenstruktur anzeigen');
|
||||
console.log('5. Beenden');
|
||||
|
||||
rl.question('\nWähle eine Option (1-5): ', async (answer) => {
|
||||
switch (answer.trim()) {
|
||||
case '1':
|
||||
rl.question('Gib deine SQL-Abfrage ein: ', async (query) => {
|
||||
await executeQuery(query);
|
||||
showMenu();
|
||||
});
|
||||
break;
|
||||
case '2':
|
||||
rl.question('Gib den Pfad zur SQL-Datei ein: ', async (filePath) => {
|
||||
await executeFile(filePath);
|
||||
showMenu();
|
||||
});
|
||||
break;
|
||||
case '3':
|
||||
await listTables();
|
||||
showMenu();
|
||||
break;
|
||||
case '4':
|
||||
rl.question('Gib den Tabellennamen ein: ', async (tableName) => {
|
||||
await describeTable(tableName);
|
||||
showMenu();
|
||||
});
|
||||
break;
|
||||
case '5':
|
||||
console.log('Auf Wiedersehen!');
|
||||
rl.close();
|
||||
process.exit(0);
|
||||
break;
|
||||
default:
|
||||
console.log('Ungültige Option. Bitte wähle 1-5.');
|
||||
showMenu();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Starte das Programm
|
||||
console.log('Verbindung zu Supabase hergestellt.');
|
||||
console.log(`URL: ${supabaseUrl}`);
|
||||
showMenu();
|
||||
112
apps/chat/apps/mobile/scripts/update_models.js
Normal file
112
apps/chat/apps/mobile/scripts/update_models.js
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
// Skript zum Aktualisieren der Modelle in der Supabase-Datenbank
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import dotenv from 'dotenv';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
|
||||
// Lade Umgebungsvariablen aus .env
|
||||
dotenv.config();
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Supabase-Client erstellen
|
||||
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL;
|
||||
const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY;
|
||||
|
||||
if (!supabaseUrl || !supabaseKey) {
|
||||
console.error('Fehler: EXPO_PUBLIC_SUPABASE_URL und EXPO_PUBLIC_SUPABASE_ANON_KEY müssen in der .env-Datei definiert sein.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||||
|
||||
// Modelle, die wir in die Datenbank einfügen wollen
|
||||
const models = [
|
||||
{
|
||||
id: '550e8400-e29b-41d4-a716-446655440000',
|
||||
name: 'GPT-O3-Mini',
|
||||
description: 'Azure OpenAI O3-Mini: Effizientes Modell für schnelle Antworten.',
|
||||
parameters: {
|
||||
temperature: 0.7,
|
||||
max_tokens: 800,
|
||||
provider: 'azure',
|
||||
deployment: 'gpt-o3-mini-se',
|
||||
endpoint: 'https://memoroseopenai.openai.azure.com',
|
||||
api_version: '2024-12-01-preview'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '550e8400-e29b-41d4-a716-446655440004',
|
||||
name: 'GPT-4o-Mini',
|
||||
description: 'Azure OpenAI GPT-4o-Mini: Kompaktes, leistungsstarkes KI-Modell.',
|
||||
parameters: {
|
||||
temperature: 0.7,
|
||||
max_tokens: 1000,
|
||||
provider: 'azure',
|
||||
deployment: 'gpt-4o-mini-se',
|
||||
endpoint: 'https://memoroseopenai.openai.azure.com',
|
||||
api_version: '2024-12-01-preview'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '550e8400-e29b-41d4-a716-446655440005',
|
||||
name: 'GPT-4o',
|
||||
description: 'Azure OpenAI GPT-4o: Das fortschrittlichste multimodale KI-Modell.',
|
||||
parameters: {
|
||||
temperature: 0.7,
|
||||
max_tokens: 1200,
|
||||
provider: 'azure',
|
||||
deployment: 'gpt-4o-se',
|
||||
endpoint: 'https://memoroseopenai.openai.azure.com',
|
||||
api_version: '2024-12-01-preview'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
async function updateModels() {
|
||||
console.log('Aktualisiere Modelle in der Supabase-Datenbank...');
|
||||
|
||||
// Prüfe, ob die Tabelle existiert
|
||||
const { error: tableError } = await supabase
|
||||
.from('models')
|
||||
.select('id')
|
||||
.limit(1);
|
||||
|
||||
if (tableError) {
|
||||
console.error('Fehler beim Zugriff auf die models-Tabelle:', tableError.message);
|
||||
console.log('Erstelle models-Tabelle...');
|
||||
|
||||
// Erstelle die Tabelle, falls sie nicht existiert
|
||||
const { error: createError } = await supabase.rpc('create_models_table');
|
||||
|
||||
if (createError) {
|
||||
console.error('Fehler beim Erstellen der models-Tabelle:', createError.message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Füge die Modelle ein oder aktualisiere sie
|
||||
for (const model of models) {
|
||||
const { error } = await supabase
|
||||
.from('models')
|
||||
.upsert(model, { onConflict: 'id' });
|
||||
|
||||
if (error) {
|
||||
console.error(`Fehler beim Aktualisieren des Modells ${model.name}:`, error.message);
|
||||
} else {
|
||||
console.log(`Modell ${model.name} erfolgreich aktualisiert.`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Modellaktualisierung abgeschlossen.');
|
||||
}
|
||||
|
||||
// Führe die Funktion aus
|
||||
updateModels()
|
||||
.catch(error => {
|
||||
console.error('Unerwarteter Fehler:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
29
apps/chat/apps/mobile/scripts/update_models.sql
Normal file
29
apps/chat/apps/mobile/scripts/update_models.sql
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
-- Löschen der vorhandenen Modelle (optional)
|
||||
-- DELETE FROM models;
|
||||
|
||||
-- Einfügen der neuen Modelle mit UUIDs
|
||||
INSERT INTO models (id, name, description, parameters)
|
||||
VALUES
|
||||
(
|
||||
'550e8400-e29b-41d4-a716-446655440000',
|
||||
'GPT-O3-Mini',
|
||||
'Azure OpenAI O3-Mini: Effizientes Modell für schnelle Antworten.',
|
||||
'{"temperature": 0.7, "max_tokens": 800, "provider": "azure", "deployment": "gpt-o3-mini-se", "endpoint": "https://memoroseopenai.openai.azure.com", "api_version": "2024-12-01-preview"}'
|
||||
),
|
||||
(
|
||||
'550e8400-e29b-41d4-a716-446655440004',
|
||||
'GPT-4o-Mini',
|
||||
'Azure OpenAI GPT-4o-Mini: Kompaktes, leistungsstarkes KI-Modell.',
|
||||
'{"temperature": 0.7, "max_tokens": 1000, "provider": "azure", "deployment": "gpt-4o-mini-se", "endpoint": "https://memoroseopenai.openai.azure.com", "api_version": "2024-12-01-preview"}'
|
||||
),
|
||||
(
|
||||
'550e8400-e29b-41d4-a716-446655440005',
|
||||
'GPT-4o',
|
||||
'Azure OpenAI GPT-4o: Das fortschrittlichste multimodale KI-Modell.',
|
||||
'{"temperature": 0.7, "max_tokens": 1200, "provider": "azure", "deployment": "gpt-4o-se", "endpoint": "https://memoroseopenai.openai.azure.com", "api_version": "2024-12-01-preview"}'
|
||||
)
|
||||
ON CONFLICT (id)
|
||||
DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
parameters = EXCLUDED.parameters;
|
||||
Loading…
Add table
Add a link
Reference in a new issue