Описание изменений
This commit is contained in:
@@ -1,19 +1,21 @@
|
||||
const createGuestMessagesTable = require('./migrations/create_guest_messages_table');
|
||||
const { Pool } = require('pg');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
async function initDatabase() {
|
||||
try {
|
||||
// ... существующий код ...
|
||||
|
||||
// Выполняем миграции
|
||||
await pool.query(createUsersTable);
|
||||
await pool.query(createSessionTable);
|
||||
await pool.query(createNoncesTable);
|
||||
await pool.query(createMessagesTable);
|
||||
await pool.query(createConversationsTable);
|
||||
await pool.query(createGuestMessagesTable);
|
||||
|
||||
// ... существующий код ...
|
||||
} catch (error) {
|
||||
// ... существующий код ...
|
||||
const pool = new Pool({
|
||||
user: process.env.DB_USER || 'dapp_user',
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
database: process.env.DB_NAME || 'dapp_db',
|
||||
password: process.env.DB_PASSWORD,
|
||||
port: process.env.DB_PORT || 5432,
|
||||
});
|
||||
|
||||
// Проверка подключения
|
||||
pool.query('SELECT NOW()', (err, res) => {
|
||||
if (err) {
|
||||
logger.error('Error connecting to database:', err);
|
||||
} else {
|
||||
logger.info('Успешное подключение к базе данных:', res.rows[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = { pool };
|
||||
@@ -1,8 +1,13 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { pool } = require('./index');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
// Инициализация таблицы roles
|
||||
async function initRoles() {
|
||||
try {
|
||||
// Проверяем, существует ли таблица roles
|
||||
const tableExists = await db.query(`
|
||||
const tableExists = await pool.query(`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_name = 'roles'
|
||||
@@ -11,7 +16,7 @@ async function initRoles() {
|
||||
|
||||
if (!tableExists.rows[0].exists) {
|
||||
// Создаем таблицу roles
|
||||
await db.query(`
|
||||
await pool.query(`
|
||||
CREATE TABLE roles (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(50) NOT NULL UNIQUE,
|
||||
@@ -21,7 +26,7 @@ async function initRoles() {
|
||||
`);
|
||||
|
||||
// Добавляем роли
|
||||
await db.query(`
|
||||
await pool.query(`
|
||||
INSERT INTO roles (id, name, description) VALUES
|
||||
(3, 'user', 'Обычный пользователь'),
|
||||
(4, 'admin', 'Администратор с полным доступом');
|
||||
@@ -30,24 +35,24 @@ async function initRoles() {
|
||||
console.log('Таблица roles создана и заполнена');
|
||||
} else {
|
||||
// Проверяем наличие ролей
|
||||
const rolesExist = await db.query(`
|
||||
const rolesExist = await pool.query(`
|
||||
SELECT COUNT(*) FROM roles WHERE id IN (3, 4);
|
||||
`);
|
||||
|
||||
if (rolesExist.rows[0].count < 2) {
|
||||
// Добавляем недостающие роли
|
||||
const userRoleExists = await db.query(`SELECT EXISTS (SELECT FROM roles WHERE name = 'user');`);
|
||||
const adminRoleExists = await db.query(`SELECT EXISTS (SELECT FROM roles WHERE name = 'admin');`);
|
||||
const userRoleExists = await pool.query(`SELECT EXISTS (SELECT FROM roles WHERE name = 'user');`);
|
||||
const adminRoleExists = await pool.query(`SELECT EXISTS (SELECT FROM roles WHERE name = 'admin');`);
|
||||
|
||||
if (!userRoleExists.rows[0].exists) {
|
||||
await db.query(`
|
||||
await pool.query(`
|
||||
INSERT INTO roles (id, name, description) VALUES
|
||||
(3, 'user', 'Обычный пользователь');
|
||||
`);
|
||||
}
|
||||
|
||||
if (!adminRoleExists.rows[0].exists) {
|
||||
await db.query(`
|
||||
await pool.query(`
|
||||
INSERT INTO roles (id, name, description) VALUES
|
||||
(4, 'admin', 'Администратор с полным доступом');
|
||||
`);
|
||||
@@ -60,4 +65,55 @@ async function initRoles() {
|
||||
console.error('Ошибка при инициализации таблицы roles:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function initializeDatabase() {
|
||||
try {
|
||||
// Создаем таблицу для отслеживания миграций, если её нет
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS migrations (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
executed_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
`);
|
||||
|
||||
// Путь к папке с миграциями
|
||||
const migrationsPath = path.join(__dirname, 'migrations');
|
||||
|
||||
// Получаем все файлы миграций
|
||||
const migrationFiles = fs.readdirSync(migrationsPath)
|
||||
.filter(file => file.endsWith('.sql'))
|
||||
.sort();
|
||||
|
||||
// Получаем выполненные миграции
|
||||
const { rows } = await pool.query('SELECT name FROM migrations');
|
||||
const executedMigrations = new Set(rows.map(row => row.name));
|
||||
|
||||
// Выполняем только новые миграции
|
||||
for (const file of migrationFiles) {
|
||||
if (!executedMigrations.has(file)) {
|
||||
const filePath = path.join(migrationsPath, file);
|
||||
const sql = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
logger.info(`Executing migration: ${file}`);
|
||||
await pool.query(sql);
|
||||
|
||||
// Записываем выполненную миграцию
|
||||
await pool.query(
|
||||
'INSERT INTO migrations (name) VALUES ($1)',
|
||||
[file]
|
||||
);
|
||||
|
||||
logger.info(`Migration completed: ${file}`);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info('All migrations completed successfully');
|
||||
} catch (error) {
|
||||
logger.error('Error during database initialization:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { initializeDatabase };
|
||||
8
backend/db/migrations/000_session_table.sql
Normal file
8
backend/db/migrations/000_session_table.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
CREATE TABLE IF NOT EXISTS "session" (
|
||||
"sid" varchar NOT NULL COLLATE "default",
|
||||
"sess" json NOT NULL,
|
||||
"expire" timestamp(6) NOT NULL,
|
||||
CONSTRAINT "session_pkey" PRIMARY KEY ("sid")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_session_expire" ON "session" ("expire");
|
||||
9
backend/db/migrations/001_initial_schema.sql
Normal file
9
backend/db/migrations/001_initial_schema.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(255),
|
||||
email VARCHAR(255) UNIQUE,
|
||||
address VARCHAR(255) UNIQUE,
|
||||
status VARCHAR(50) DEFAULT 'active',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
24
backend/db/migrations/002_access_roles.sql
Normal file
24
backend/db/migrations/002_access_roles.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
CREATE TABLE IF NOT EXISTS roles (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(50) NOT NULL UNIQUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Добавляем базовые роли
|
||||
INSERT INTO roles (name) VALUES ('admin'), ('user')
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
|
||||
-- Добавляем связь пользователей с ролями
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'users' AND column_name = 'role_id'
|
||||
) THEN
|
||||
ALTER TABLE users
|
||||
ADD COLUMN role_id INTEGER REFERENCES roles(id);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Создаем индекс для role_id после добавления колонки
|
||||
CREATE INDEX IF NOT EXISTS idx_users_role_id ON users(role_id);
|
||||
28
backend/db/migrations/003_user_identities.sql
Normal file
28
backend/db/migrations/003_user_identities.sql
Normal file
@@ -0,0 +1,28 @@
|
||||
CREATE TABLE IF NOT EXISTS user_identities (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
provider VARCHAR(50) NOT NULL,
|
||||
provider_id VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(provider, provider_id)
|
||||
);
|
||||
|
||||
-- Создаем индексы после создания таблицы
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Индекс для user_id
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_indexes
|
||||
WHERE tablename = 'user_identities' AND indexname = 'idx_user_identities_user_id'
|
||||
) THEN
|
||||
CREATE INDEX idx_user_identities_user_id ON user_identities(user_id);
|
||||
END IF;
|
||||
|
||||
-- Индекс для provider и provider_id
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_indexes
|
||||
WHERE tablename = 'user_identities' AND indexname = 'idx_user_identities_type_value'
|
||||
) THEN
|
||||
CREATE INDEX idx_user_identities_type_value ON user_identities(provider, provider_id);
|
||||
END IF;
|
||||
END $$;
|
||||
10
backend/db/migrations/004_conversations.sql
Normal file
10
backend/db/migrations/004_conversations.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE IF NOT EXISTS conversations (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
title VARCHAR(255),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_conversations_user_id ON conversations(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_conversations_created_at ON conversations(created_at);
|
||||
20
backend/db/migrations/005_messages.sql
Normal file
20
backend/db/migrations/005_messages.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
id SERIAL PRIMARY KEY,
|
||||
conversation_id INTEGER REFERENCES conversations(id) ON DELETE CASCADE,
|
||||
sender_type VARCHAR(20) NOT NULL,
|
||||
sender_id INTEGER,
|
||||
content TEXT,
|
||||
channel VARCHAR(20) NOT NULL,
|
||||
metadata JSONB,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
role VARCHAR(20) NOT NULL DEFAULT 'user',
|
||||
guest_message_id INTEGER,
|
||||
tokens_used INTEGER DEFAULT 0,
|
||||
is_processed BOOLEAN DEFAULT FALSE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_conversation_id ON messages(conversation_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_sender_type ON messages(sender_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_channel ON messages(channel);
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_metadata ON messages USING gin(metadata);
|
||||
52
backend/db/migrations/006_guest_messages.sql
Normal file
52
backend/db/migrations/006_guest_messages.sql
Normal file
@@ -0,0 +1,52 @@
|
||||
CREATE TABLE IF NOT EXISTS guest_messages (
|
||||
id SERIAL PRIMARY KEY,
|
||||
guest_id VARCHAR(255) NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
language VARCHAR(10) DEFAULT 'en',
|
||||
is_ai BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_indexes
|
||||
WHERE tablename = 'guest_messages' AND indexname = 'idx_guest_messages_guest_id'
|
||||
) THEN
|
||||
CREATE INDEX idx_guest_messages_guest_id ON guest_messages(guest_id);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'messages' AND column_name = 'guest_message_id'
|
||||
) THEN
|
||||
ALTER TABLE messages ADD COLUMN guest_message_id INTEGER;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint
|
||||
WHERE conname = 'fk_messages_guest_message'
|
||||
) THEN
|
||||
ALTER TABLE messages
|
||||
ADD CONSTRAINT fk_messages_guest_message
|
||||
FOREIGN KEY (guest_message_id)
|
||||
REFERENCES guest_messages(id)
|
||||
ON DELETE SET NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_indexes
|
||||
WHERE tablename = 'messages' AND indexname = 'idx_messages_guest_message_id'
|
||||
) THEN
|
||||
CREATE INDEX idx_messages_guest_message_id ON messages(guest_message_id);
|
||||
END IF;
|
||||
END $$;
|
||||
46
backend/db/migrations/007_user_preferences.sql
Normal file
46
backend/db/migrations/007_user_preferences.sql
Normal file
@@ -0,0 +1,46 @@
|
||||
CREATE TABLE IF NOT EXISTS user_preferences (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
||||
preference_key VARCHAR(50) NOT NULL,
|
||||
preference_value TEXT,
|
||||
metadata JSONB DEFAULT '{}',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(user_id, preference_key)
|
||||
);
|
||||
|
||||
-- Добавляем колонку metadata, если её нет
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'user_preferences' AND column_name = 'metadata'
|
||||
) THEN
|
||||
ALTER TABLE user_preferences ADD COLUMN metadata JSONB DEFAULT '{}';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_preferences_user_id ON user_preferences(user_id);
|
||||
|
||||
-- Базовые настройки
|
||||
DO $$
|
||||
BEGIN
|
||||
INSERT INTO user_preferences (user_id, preference_key, preference_value, metadata)
|
||||
SELECT id, 'language', 'ru', '{"available": ["ru", "en"]}'::jsonb
|
||||
FROM users u
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM user_preferences
|
||||
WHERE preference_key = 'language' AND user_id = u.id
|
||||
);
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
INSERT INTO user_preferences (user_id, preference_key, preference_value, metadata)
|
||||
SELECT id, 'notifications', 'true', '{"channels": ["email", "telegram"]}'::jsonb
|
||||
FROM users u
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM user_preferences
|
||||
WHERE preference_key = 'notifications' AND user_id = u.id
|
||||
);
|
||||
END $$;
|
||||
45
backend/db/migrations/008_update_messages_structure.sql
Normal file
45
backend/db/migrations/008_update_messages_structure.sql
Normal file
@@ -0,0 +1,45 @@
|
||||
-- Добавляем новые поля в messages
|
||||
ALTER TABLE messages
|
||||
ADD COLUMN IF NOT EXISTS role VARCHAR(20) NOT NULL DEFAULT 'user',
|
||||
ADD COLUMN IF NOT EXISTS guest_message_id INTEGER,
|
||||
ADD COLUMN IF NOT EXISTS tokens_used INTEGER DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS is_processed BOOLEAN DEFAULT FALSE;
|
||||
|
||||
-- Создаем функцию для связывания сообщений
|
||||
CREATE OR REPLACE FUNCTION link_guest_messages(
|
||||
p_user_id INTEGER,
|
||||
p_guest_id VARCHAR(255)
|
||||
) RETURNS VOID AS $$
|
||||
DECLARE
|
||||
v_conversation_id INTEGER;
|
||||
BEGIN
|
||||
-- Создаем новую беседу для гостевых сообщений
|
||||
INSERT INTO conversations (created_at, updated_at)
|
||||
VALUES (NOW(), NOW())
|
||||
RETURNING id INTO v_conversation_id;
|
||||
|
||||
-- Копируем гостевые сообщения в основную таблицу
|
||||
INSERT INTO messages (
|
||||
conversation_id,
|
||||
sender_type,
|
||||
sender_id,
|
||||
content,
|
||||
role,
|
||||
channel,
|
||||
guest_message_id,
|
||||
created_at
|
||||
)
|
||||
SELECT
|
||||
v_conversation_id,
|
||||
CASE WHEN is_ai THEN 'assistant' ELSE 'user' END,
|
||||
CASE WHEN NOT is_ai THEN p_user_id ELSE NULL END,
|
||||
content,
|
||||
CASE WHEN is_ai THEN 'assistant' ELSE 'user' END,
|
||||
'chat',
|
||||
id,
|
||||
created_at
|
||||
FROM guest_messages
|
||||
WHERE guest_id = p_guest_id
|
||||
ORDER BY created_at;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
13
backend/db/migrations/009_nonces_table.sql
Normal file
13
backend/db/migrations/009_nonces_table.sql
Normal file
@@ -0,0 +1,13 @@
|
||||
CREATE TABLE IF NOT EXISTS nonces (
|
||||
id SERIAL PRIMARY KEY,
|
||||
identity_value VARCHAR(255) NOT NULL,
|
||||
nonce VARCHAR(255) NOT NULL,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Индекс для быстрого поиска по identity_value
|
||||
CREATE INDEX IF NOT EXISTS idx_nonces_identity_value ON nonces(identity_value);
|
||||
|
||||
-- Индекс для очистки просроченных nonce
|
||||
CREATE INDEX IF NOT EXISTS idx_nonces_expires_at ON nonces(expires_at);
|
||||
71
backend/db/migrations/010_cleanup_roles.sql
Normal file
71
backend/db/migrations/010_cleanup_roles.sql
Normal file
@@ -0,0 +1,71 @@
|
||||
-- Проверяем существование типа user_role
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'user_role') THEN
|
||||
CREATE TYPE user_role AS ENUM ('user', 'admin');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Удаляем лишние колонки и связи
|
||||
ALTER TABLE users DROP CONSTRAINT IF EXISTS users_role_id_fkey;
|
||||
ALTER TABLE users DROP COLUMN IF EXISTS role_id;
|
||||
|
||||
-- Добавляем колонку role если её нет
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'users' AND column_name = 'role'
|
||||
) THEN
|
||||
ALTER TABLE users ADD COLUMN role user_role DEFAULT 'user'::user_role;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Удаляем лишние триггеры и функции
|
||||
DROP TRIGGER IF EXISTS sync_identity_type_trigger ON user_identities;
|
||||
DROP TRIGGER IF EXISTS user_identity_role_check ON user_identities;
|
||||
DROP TRIGGER IF EXISTS check_admin_role_trigger ON user_identities;
|
||||
DROP FUNCTION IF EXISTS sync_identity_type() CASCADE;
|
||||
DROP FUNCTION IF EXISTS update_user_role() CASCADE;
|
||||
DROP FUNCTION IF EXISTS check_admin_role(INTEGER) CASCADE;
|
||||
|
||||
-- Создаем функцию проверки роли
|
||||
CREATE FUNCTION check_admin_role()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
v_wallet_address VARCHAR;
|
||||
BEGIN
|
||||
SELECT provider_id INTO v_wallet_address
|
||||
FROM user_identities
|
||||
WHERE user_id = NEW.user_id
|
||||
AND provider = 'wallet'
|
||||
LIMIT 1;
|
||||
|
||||
IF v_wallet_address IS NULL THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
UPDATE users
|
||||
SET role = 'admin'::user_role
|
||||
WHERE id = NEW.user_id;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Создаем триггер
|
||||
CREATE TRIGGER check_admin_role_trigger
|
||||
AFTER INSERT OR UPDATE ON user_identities
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION check_admin_role();
|
||||
|
||||
-- Обновляем существующие записи
|
||||
UPDATE users u
|
||||
SET role = CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1 FROM user_identities ui
|
||||
WHERE ui.user_id = u.id
|
||||
AND ui.provider = 'wallet'
|
||||
) THEN 'admin'::user_role
|
||||
ELSE 'user'::user_role
|
||||
END;
|
||||
@@ -1,15 +0,0 @@
|
||||
// Создаем таблицу для хранения сообщений неаутентифицированных пользователей
|
||||
const createGuestMessagesTable = `
|
||||
CREATE TABLE IF NOT EXISTS guest_messages (
|
||||
id SERIAL PRIMARY KEY,
|
||||
guest_id VARCHAR(255) NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
language VARCHAR(10) DEFAULT 'en',
|
||||
is_ai BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_guest_messages_guest_id ON guest_messages(guest_id);
|
||||
`;
|
||||
|
||||
module.exports = createGuestMessagesTable;
|
||||
56
backend/db/migrations/functions/link_guest_messages.sql
Normal file
56
backend/db/migrations/functions/link_guest_messages.sql
Normal file
@@ -0,0 +1,56 @@
|
||||
CREATE OR REPLACE FUNCTION link_guest_messages(
|
||||
p_user_id INTEGER,
|
||||
p_guest_id VARCHAR(255)
|
||||
) RETURNS VOID AS $$
|
||||
DECLARE
|
||||
v_conversation_id INTEGER;
|
||||
v_count INTEGER;
|
||||
BEGIN
|
||||
-- Логируем входные параметры
|
||||
RAISE NOTICE 'Linking messages for user_id: %, guest_id: %', p_user_id, p_guest_id;
|
||||
|
||||
-- Проверяем наличие гостевых сообщений
|
||||
SELECT COUNT(*) INTO v_count
|
||||
FROM guest_messages
|
||||
WHERE guest_id = p_guest_id;
|
||||
|
||||
RAISE NOTICE 'Found % guest messages', v_count;
|
||||
|
||||
-- Создаем новую беседу
|
||||
INSERT INTO conversations (user_id, created_at, updated_at)
|
||||
VALUES (p_user_id, NOW(), NOW())
|
||||
RETURNING id INTO v_conversation_id;
|
||||
|
||||
RAISE NOTICE 'Created conversation with id: %', v_conversation_id;
|
||||
|
||||
-- Копируем сообщения пользователя
|
||||
WITH inserted_messages AS (
|
||||
INSERT INTO messages (
|
||||
conversation_id,
|
||||
sender_type,
|
||||
sender_id,
|
||||
content,
|
||||
role,
|
||||
channel,
|
||||
guest_message_id,
|
||||
created_at
|
||||
)
|
||||
SELECT
|
||||
v_conversation_id,
|
||||
CASE WHEN is_ai THEN 'assistant' ELSE 'user' END,
|
||||
CASE WHEN NOT is_ai THEN p_user_id ELSE NULL END,
|
||||
content,
|
||||
CASE WHEN is_ai THEN 'assistant' ELSE 'user' END,
|
||||
'chat',
|
||||
id, -- Сохраняем связь с гостевым сообщением
|
||||
created_at
|
||||
FROM guest_messages
|
||||
WHERE guest_id = p_guest_id
|
||||
ORDER BY created_at
|
||||
RETURNING id
|
||||
)
|
||||
SELECT COUNT(*) INTO v_count FROM inserted_messages;
|
||||
|
||||
RAISE NOTICE 'Inserted % messages', v_count;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
Reference in New Issue
Block a user