ваше сообщение коммита
This commit is contained in:
@@ -4,9 +4,8 @@ CREATE TABLE IF NOT EXISTS roles (
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Добавляем базовые роли
|
||||
INSERT INTO roles (name) VALUES ('admin'), ('user')
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
-- Добавляем базовые роли (пропускаем, так как таблица уже зашифрована)
|
||||
-- Роли будут добавлены через encryptedDatabaseService
|
||||
|
||||
-- Добавляем связь пользователей с ролями
|
||||
DO $$
|
||||
|
||||
@@ -18,11 +18,6 @@ BEGIN
|
||||
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;
|
||||
-- Индекс для provider и provider_id (пропускаем, так как колонки зашифрованы)
|
||||
-- Индекс будет создан автоматически при необходимости
|
||||
END $$;
|
||||
@@ -14,8 +14,8 @@ CREATE TABLE IF NOT EXISTS messages (
|
||||
);
|
||||
|
||||
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_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);
|
||||
-- CREATE INDEX IF NOT EXISTS idx_messages_channel ON messages(channel); -- пропускаем, колонка зашифрована
|
||||
-- CREATE INDEX IF NOT EXISTS idx_messages_metadata ON messages USING gin(metadata); -- пропускаем, колонки нет
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_user_id ON messages(user_id);
|
||||
@@ -7,15 +7,16 @@ CREATE TABLE IF NOT EXISTS guest_messages (
|
||||
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 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 $$;
|
||||
-- -- Пропускаем создание индекса, так как колонка guest_id зашифрована
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
|
||||
@@ -22,25 +22,26 @@ 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 $$;
|
||||
-- Базовые настройки (пропускаем, так как колонки зашифрованы)
|
||||
-- Данные будут добавлены через encryptedDatabaseService
|
||||
-- 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 $$;
|
||||
-- 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 $$;
|
||||
@@ -6,8 +6,8 @@ CREATE TABLE IF NOT EXISTS nonces (
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Индекс для быстрого поиска по identity_value
|
||||
CREATE INDEX IF NOT EXISTS idx_nonces_identity_value ON nonces(identity_value);
|
||||
-- Индекс для быстрого поиска по 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);
|
||||
@@ -59,10 +59,13 @@ END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Создаем триггер
|
||||
CREATE TRIGGER check_admin_role_trigger
|
||||
AFTER INSERT OR UPDATE ON user_identities
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION check_admin_role();
|
||||
-- CREATE TRIGGER check_admin_role_trigger
|
||||
-- AFTER INSERT OR UPDATE ON user_identities
|
||||
-- FOR EACH ROW
|
||||
-- EXECUTE FUNCTION check_admin_role();
|
||||
|
||||
-- Триггер отключен, так как проверка роли админа происходит в JavaScript коде
|
||||
-- и триггер вызывает ошибку с зашифрованными полями provider_encrypted
|
||||
|
||||
-- Сбрасываем все роли на user
|
||||
UPDATE users SET role = 'user'::user_role;
|
||||
|
||||
@@ -9,8 +9,8 @@ BEGIN
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Удаляем гостевые идентификаторы из user_identities
|
||||
DELETE FROM user_identities WHERE provider = 'guest';
|
||||
-- Удаляем гостевые идентификаторы из user_identities (пропускаем, колонка зашифрована)
|
||||
-- DELETE FROM user_identities WHERE provider = 'guest';
|
||||
|
||||
-- Удаляем индекс для guest_message_id если он существует
|
||||
DO $$
|
||||
|
||||
@@ -10,9 +10,9 @@ CREATE TABLE IF NOT EXISTS verification_codes (
|
||||
used BOOLEAN DEFAULT FALSE
|
||||
);
|
||||
|
||||
-- Индексы для оптимизации
|
||||
CREATE INDEX IF NOT EXISTS idx_verification_codes_code ON verification_codes(code);
|
||||
CREATE INDEX IF NOT EXISTS idx_verification_codes_provider ON verification_codes(provider);
|
||||
-- Индексы для оптимизации (пропускаем зашифрованные колонки)
|
||||
-- CREATE INDEX IF NOT EXISTS idx_verification_codes_code ON verification_codes(code); -- колонка зашифрована
|
||||
-- CREATE INDEX IF NOT EXISTS idx_verification_codes_provider ON verification_codes(provider); -- колонка зашифрована
|
||||
CREATE INDEX IF NOT EXISTS idx_verification_codes_expires ON verification_codes(expires_at);
|
||||
|
||||
-- Удаляем старую таблицу email_auth_tokens
|
||||
|
||||
@@ -12,24 +12,24 @@ CREATE TABLE IF NOT EXISTS guest_user_mapping (
|
||||
);
|
||||
|
||||
-- 2. Создание индексов для guest_user_mapping
|
||||
CREATE INDEX IF NOT EXISTS idx_guest_user_mapping_guest_id ON guest_user_mapping(guest_id);
|
||||
-- CREATE INDEX IF NOT EXISTS idx_guest_user_mapping_guest_id ON guest_user_mapping(guest_id); -- колонка зашифрована
|
||||
CREATE INDEX IF NOT EXISTS idx_guest_user_mapping_user_id ON guest_user_mapping(user_id);
|
||||
|
||||
-- 3. Перенос гостевых идентификаторов из user_identities в guest_user_mapping
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Выполняем только если есть гостевые идентификаторы в user_identities
|
||||
IF EXISTS (SELECT 1 FROM user_identities WHERE provider = 'guest') THEN
|
||||
INSERT INTO guest_user_mapping (user_id, guest_id, processed)
|
||||
SELECT user_id, provider_id, true
|
||||
FROM user_identities
|
||||
WHERE provider = 'guest'
|
||||
ON CONFLICT (guest_id) DO NOTHING;
|
||||
|
||||
-- Удаляем перенесенные идентификаторы
|
||||
DELETE FROM user_identities WHERE provider = 'guest';
|
||||
END IF;
|
||||
END $$;
|
||||
-- 3. Перенос гостевых идентификаторов из user_identities в guest_user_mapping (пропускаем, колонки зашифрованы)
|
||||
-- DO $$
|
||||
-- BEGIN
|
||||
-- -- Выполняем только если есть гостевые идентификаторы в user_identities
|
||||
-- IF EXISTS (SELECT 1 FROM user_identities WHERE provider = 'guest') THEN
|
||||
-- INSERT INTO guest_user_mapping (user_id, guest_id, processed)
|
||||
-- SELECT user_id, provider_id, true
|
||||
-- FROM user_identities
|
||||
-- WHERE provider = 'guest'
|
||||
-- ON CONFLICT (guest_id) DO NOTHING;
|
||||
--
|
||||
-- -- Удаляем перенесенные идентификаторы
|
||||
-- DELETE FROM user_identities WHERE provider = 'guest';
|
||||
-- END IF;
|
||||
-- END $$;
|
||||
|
||||
-- 4. Добавление/обновление поля user_id в таблице messages
|
||||
DO $$
|
||||
@@ -71,74 +71,74 @@ BEFORE INSERT ON messages
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_message_user_id();
|
||||
|
||||
-- 7. Перенос идентификаторов из полей users в user_identities
|
||||
DO $$
|
||||
DECLARE
|
||||
user_rec RECORD;
|
||||
BEGIN
|
||||
-- Обрабатываем email
|
||||
FOR user_rec IN
|
||||
SELECT id, email FROM users
|
||||
WHERE email IS NOT NULL AND email != ''
|
||||
LOOP
|
||||
-- Проверяем, существует ли такой email в user_identities
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM user_identities
|
||||
WHERE user_id = user_rec.id AND provider = 'email' AND provider_id = user_rec.email
|
||||
) THEN
|
||||
-- Если нет, добавляем его
|
||||
INSERT INTO user_identities (user_id, provider, provider_id)
|
||||
VALUES (user_rec.id, 'email', LOWER(user_rec.email));
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
-- Обрабатываем address (wallet)
|
||||
FOR user_rec IN
|
||||
SELECT id, address FROM users
|
||||
WHERE address IS NOT NULL AND address != ''
|
||||
LOOP
|
||||
-- Проверяем, существует ли такой адрес в user_identities
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM user_identities
|
||||
WHERE user_id = user_rec.id AND provider = 'wallet' AND provider_id = LOWER(user_rec.address)
|
||||
) THEN
|
||||
-- Если нет, добавляем его
|
||||
INSERT INTO user_identities (user_id, provider, provider_id)
|
||||
VALUES (user_rec.id, 'wallet', LOWER(user_rec.address));
|
||||
END IF;
|
||||
END LOOP;
|
||||
END $$;
|
||||
-- 7. Перенос идентификаторов из полей users в user_identities (пропускаем, колонки зашифрованы)
|
||||
-- DO $$
|
||||
-- DECLARE
|
||||
-- user_rec RECORD;
|
||||
-- BEGIN
|
||||
-- -- Обрабатываем email
|
||||
-- FOR user_rec IN
|
||||
-- SELECT id, email FROM users
|
||||
-- WHERE email IS NOT NULL AND email != ''
|
||||
-- LOOP
|
||||
-- -- Проверяем, существует ли такой email в user_identities
|
||||
-- IF NOT EXISTS (
|
||||
-- SELECT 1 FROM user_identities
|
||||
-- WHERE user_id = user_rec.id AND provider = 'email' AND provider_id = user_rec.email
|
||||
-- ) THEN
|
||||
-- -- Если нет, добавляем его
|
||||
-- INSERT INTO user_identities (user_id, provider, provider_id)
|
||||
-- VALUES (user_rec.id, 'email', LOWER(user_rec.email));
|
||||
-- END IF;
|
||||
-- END LOOP;
|
||||
--
|
||||
-- -- Обрабатываем address (wallet)
|
||||
-- FOR user_rec IN
|
||||
-- SELECT id, address FROM users
|
||||
-- WHERE address IS NOT NULL AND address != ''
|
||||
-- LOOP
|
||||
-- -- Проверяем, существует ли такой адрес в user_identities
|
||||
-- IF NOT EXISTS (
|
||||
-- SELECT 1 FROM user_identities
|
||||
-- WHERE user_id = user_rec.id AND provider = 'wallet' AND provider_id = LOWER(user_rec.address)
|
||||
-- ) THEN
|
||||
-- -- Если нет, добавляем его
|
||||
-- INSERT INTO user_identities (user_id, provider, provider_id)
|
||||
-- VALUES (user_rec.id, 'wallet', LOWER(user_rec.address));
|
||||
-- END IF;
|
||||
-- END LOOP;
|
||||
-- END $$;
|
||||
|
||||
-- 8. Очистка устаревших полей в таблице users
|
||||
UPDATE users
|
||||
SET
|
||||
email = NULL,
|
||||
address = NULL,
|
||||
username = NULL
|
||||
WHERE
|
||||
email IS NOT NULL OR address IS NOT NULL OR username IS NOT NULL;
|
||||
-- 8. Очистка устаревших полей в таблице users (пропускаем, колонки зашифрованы)
|
||||
-- UPDATE users
|
||||
-- SET
|
||||
-- email = NULL,
|
||||
-- address = NULL,
|
||||
-- username = NULL
|
||||
-- WHERE
|
||||
-- email IS NOT NULL OR address IS NOT NULL OR username IS NOT NULL;
|
||||
|
||||
-- 9. Нормализация регистра для email и wallet идентификаторов
|
||||
UPDATE user_identities
|
||||
SET provider_id = LOWER(provider_id)
|
||||
WHERE (provider = 'wallet' OR provider = 'email') AND provider_id != LOWER(provider_id);
|
||||
-- 9. Нормализация регистра для email и wallet идентификаторов (пропускаем, колонки зашифрованы)
|
||||
-- UPDATE user_identities
|
||||
-- SET provider_id = LOWER(provider_id)
|
||||
-- WHERE (provider = 'wallet' OR provider = 'email') AND provider_id != LOWER(provider_id);
|
||||
|
||||
-- 10. Ограничения для предотвращения использования guest в user_identities
|
||||
ALTER TABLE user_identities DROP CONSTRAINT IF EXISTS check_provider_not_guest;
|
||||
ALTER TABLE user_identities ADD CONSTRAINT check_provider_not_guest
|
||||
CHECK (provider != 'guest');
|
||||
-- 10. Ограничения для предотвращения использования guest в user_identities (пропускаем, колонки зашифрованы)
|
||||
-- ALTER TABLE user_identities DROP CONSTRAINT IF EXISTS check_provider_not_guest;
|
||||
-- ALTER TABLE user_identities ADD CONSTRAINT check_provider_not_guest
|
||||
-- CHECK (provider != 'guest');
|
||||
|
||||
-- 11. Ограничение на допустимые типы идентификаторов
|
||||
ALTER TABLE user_identities DROP CONSTRAINT IF EXISTS check_provider_allowed;
|
||||
ALTER TABLE user_identities ADD CONSTRAINT check_provider_allowed
|
||||
CHECK (provider IN ('email', 'wallet', 'telegram'));
|
||||
-- 11. Ограничение на допустимые типы идентификаторов (пропускаем, колонки зашифрованы)
|
||||
-- ALTER TABLE user_identities DROP CONSTRAINT IF EXISTS check_provider_allowed;
|
||||
-- ALTER TABLE user_identities ADD CONSTRAINT check_provider_allowed
|
||||
-- CHECK (provider IN ('email', 'wallet', 'telegram'));
|
||||
|
||||
-- 12. Помечаем обработанные гостевые идентификаторы
|
||||
UPDATE guest_user_mapping
|
||||
SET processed = true
|
||||
WHERE processed = false AND NOT EXISTS (
|
||||
SELECT 1 FROM guest_messages WHERE guest_id = guest_user_mapping.guest_id
|
||||
);
|
||||
-- 12. Помечаем обработанные гостевые идентификаторы (пропускаем, колонки зашифрованы)
|
||||
-- UPDATE guest_user_mapping
|
||||
-- SET processed = true
|
||||
-- WHERE processed = false AND NOT EXISTS (
|
||||
-- SELECT 1 FROM guest_messages WHERE guest_id = guest_user_mapping.guest_id
|
||||
-- );
|
||||
|
||||
-- 13. Добавляем комментарии к таблицам и полям
|
||||
COMMENT ON TABLE users IS 'Основная таблица пользователей системы';
|
||||
@@ -149,16 +149,16 @@ COMMENT ON TABLE messages IS 'Сообщения пользователей и
|
||||
COMMENT ON TABLE guest_messages IS 'Временное хранилище сообщений от неавторизованных пользователей';
|
||||
|
||||
COMMENT ON COLUMN users.id IS 'Уникальный идентификатор пользователя';
|
||||
COMMENT ON COLUMN users.username IS 'Имя пользователя (устарело, используется user_identities)';
|
||||
COMMENT ON COLUMN users.email IS 'Email пользователя (устарело, используется user_identities)';
|
||||
COMMENT ON COLUMN users.address IS 'Адрес кошелька (устарело, используется user_identities)';
|
||||
COMMENT ON COLUMN users.status IS 'Статус пользователя (active, blocked)';
|
||||
-- COMMENT ON COLUMN users.username IS 'Имя пользователя (устарело, используется user_identities)'; -- колонка зашифрована
|
||||
-- COMMENT ON COLUMN users.email IS 'Email пользователя (устарело, используется user_identities)'; -- колонка зашифрована
|
||||
-- COMMENT ON COLUMN users.address IS 'Адрес кошелька (устарело, используется user_identities)'; -- колонка зашифрована
|
||||
-- COMMENT ON COLUMN users.status IS 'Статус пользователя (active, blocked)'; -- колонка зашифрована
|
||||
COMMENT ON COLUMN users.role IS 'Роль пользователя (user, admin)';
|
||||
|
||||
COMMENT ON COLUMN user_identities.provider IS 'Тип идентификатора (email, wallet, telegram, username)';
|
||||
COMMENT ON COLUMN user_identities.provider_id IS 'Значение идентификатора';
|
||||
-- COMMENT ON COLUMN user_identities.provider IS 'Тип идентификатора (email, wallet, telegram, username)'; -- колонка зашифрована
|
||||
-- COMMENT ON COLUMN user_identities.provider_id IS 'Значение идентификатора'; -- колонка зашифрована
|
||||
|
||||
COMMENT ON COLUMN guest_user_mapping.guest_id IS 'Идентификатор гостя из localStorage';
|
||||
-- COMMENT ON COLUMN guest_user_mapping.guest_id IS 'Идентификатор гостя из localStorage'; -- колонка зашифрована
|
||||
COMMENT ON COLUMN guest_user_mapping.processed IS 'Флаг, показывающий, были ли обработаны гостевые сообщения';
|
||||
|
||||
-- 14. Создаем диагностическую функцию
|
||||
|
||||
11
backend/db/migrations/015_disable_admin_role_trigger.sql
Normal file
11
backend/db/migrations/015_disable_admin_role_trigger.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- Отключаем триггер check_admin_role_trigger, который вызывает ошибку с зашифрованными полями
|
||||
-- Проверка роли админа теперь происходит в JavaScript коде
|
||||
|
||||
-- Удаляем триггер
|
||||
DROP TRIGGER IF EXISTS check_admin_role_trigger ON user_identities;
|
||||
|
||||
-- Удаляем функцию, так как она больше не нужна
|
||||
DROP FUNCTION IF EXISTS check_admin_role() CASCADE;
|
||||
|
||||
-- Комментарий: Проверка роли админа теперь происходит в JavaScript коде
|
||||
-- в файлах auth-service.js, admin-role.js и других сервисах
|
||||
@@ -1,52 +1,10 @@
|
||||
-- Миграция для изменения структуры таблицы users
|
||||
-- Переносим данные из email и address в user_identities, затем преобразуем эти поля в first_name и last_name
|
||||
|
||||
-- Сначала проверяем, что все email и address уже существуют в user_identities
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Переносим email в user_identities, если еще не перенесены
|
||||
INSERT INTO user_identities (user_id, provider, provider_id)
|
||||
SELECT id, 'email', email
|
||||
FROM users
|
||||
WHERE email IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM user_identities
|
||||
WHERE user_id = users.id AND provider = 'email' AND provider_id = users.email
|
||||
);
|
||||
|
||||
-- Переносим address в user_identities, если еще не перенесены
|
||||
INSERT INTO user_identities (user_id, provider, provider_id)
|
||||
SELECT id, 'wallet', address
|
||||
FROM users
|
||||
WHERE address IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM user_identities
|
||||
WHERE user_id = users.id AND provider = 'wallet' AND provider_id = users.address
|
||||
);
|
||||
|
||||
-- Логируем результаты миграции
|
||||
RAISE NOTICE 'Данные из колонок email и address перенесены в таблицу user_identities';
|
||||
END $$;
|
||||
|
||||
-- Теперь изменяем структуру таблицы users
|
||||
ALTER TABLE users
|
||||
DROP CONSTRAINT IF EXISTS users_email_key,
|
||||
DROP CONSTRAINT IF EXISTS users_address_key;
|
||||
-- Добавляем поля first_name и last_name (колонки email и address уже зашифрованы)
|
||||
|
||||
-- Добавляем временные колонки
|
||||
ALTER TABLE users
|
||||
ADD COLUMN first_name VARCHAR(255),
|
||||
ADD COLUMN last_name VARCHAR(255);
|
||||
|
||||
-- Убираем уникальность и переименовываем колонки email и address
|
||||
ALTER TABLE users
|
||||
ALTER COLUMN email DROP NOT NULL,
|
||||
ALTER COLUMN address DROP NOT NULL;
|
||||
|
||||
-- Удаляем колонки email и address
|
||||
ALTER TABLE users
|
||||
DROP COLUMN email,
|
||||
DROP COLUMN address;
|
||||
ADD COLUMN IF NOT EXISTS first_name VARCHAR(255),
|
||||
ADD COLUMN IF NOT EXISTS last_name VARCHAR(255);
|
||||
|
||||
-- Добавляем комментарии к столбцам
|
||||
COMMENT ON COLUMN users.first_name IS 'Имя пользователя';
|
||||
|
||||
@@ -1,93 +1,8 @@
|
||||
-- Миграция для исправления дублирующихся записей в user_identities из-за разного регистра букв
|
||||
-- Исправляем записи для провайдеров wallet и email
|
||||
|
||||
-- Сначала удаляем существующее ограничение уникальности
|
||||
ALTER TABLE user_identities DROP CONSTRAINT IF EXISTS user_identities_provider_provider_id_key;
|
||||
|
||||
-- Создаем временную таблицу для хранения идентификаторов, которые нужно обработать
|
||||
CREATE TEMP TABLE duplicate_identities AS
|
||||
SELECT
|
||||
provider,
|
||||
LOWER(provider_id) as normalized_provider_id,
|
||||
array_agg(id) as id_list,
|
||||
array_agg(user_id) as user_id_list
|
||||
FROM user_identities
|
||||
WHERE provider IN ('wallet', 'email')
|
||||
GROUP BY provider, LOWER(provider_id)
|
||||
HAVING COUNT(*) > 1;
|
||||
|
||||
-- Логируем количество найденных дубликатов
|
||||
DO $$
|
||||
DECLARE
|
||||
duplicate_count INTEGER;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO duplicate_count FROM duplicate_identities;
|
||||
RAISE NOTICE 'Найдено % групп дублирующихся идентификаторов', duplicate_count;
|
||||
END $$;
|
||||
|
||||
-- Обновляем все записи, приводя provider_id к нижнему регистру
|
||||
UPDATE user_identities
|
||||
SET provider_id = LOWER(provider_id)
|
||||
WHERE provider IN ('wallet', 'email');
|
||||
|
||||
-- Удаляем дублирующиеся записи, оставляя только одну для каждой комбинации (provider, provider_id)
|
||||
WITH
|
||||
duplicates AS (
|
||||
SELECT
|
||||
id,
|
||||
provider,
|
||||
provider_id,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY provider, provider_id
|
||||
ORDER BY id
|
||||
) as row_num
|
||||
FROM user_identities
|
||||
WHERE provider IN ('wallet', 'email')
|
||||
)
|
||||
DELETE FROM user_identities
|
||||
WHERE id IN (
|
||||
SELECT id FROM duplicates WHERE row_num > 1
|
||||
);
|
||||
|
||||
-- Удаляем дублирующиеся записи для одного пользователя
|
||||
WITH
|
||||
user_duplicates AS (
|
||||
SELECT
|
||||
id,
|
||||
user_id,
|
||||
provider,
|
||||
provider_id,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY user_id, provider, provider_id
|
||||
ORDER BY id
|
||||
) as row_num
|
||||
FROM user_identities
|
||||
WHERE provider IN ('wallet', 'email')
|
||||
)
|
||||
DELETE FROM user_identities
|
||||
WHERE id IN (
|
||||
SELECT id FROM user_duplicates WHERE row_num > 1
|
||||
);
|
||||
|
||||
-- Добавляем обратно ограничение уникальности
|
||||
ALTER TABLE user_identities
|
||||
ADD CONSTRAINT user_identities_provider_provider_id_key
|
||||
UNIQUE (provider, provider_id);
|
||||
|
||||
-- Добавляем уникальный индекс для пользователей
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_indexes
|
||||
WHERE tablename = 'user_identities' AND indexname = 'unique_idx_user_identities_user_provider_provider_id'
|
||||
) THEN
|
||||
CREATE UNIQUE INDEX unique_idx_user_identities_user_provider_provider_id
|
||||
ON user_identities(user_id, provider, provider_id);
|
||||
END IF;
|
||||
END $$;
|
||||
-- Миграция для исправления дублирующихся записей в user_identities
|
||||
-- Пропускаем операции с зашифрованными колонками
|
||||
|
||||
-- Логируем завершение миграции
|
||||
DO $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'Миграция для исправления дублирующихся идентификаторов завершена';
|
||||
RAISE NOTICE 'Миграция для исправления дублирующихся идентификаторов пропущена (колонки зашифрованы)';
|
||||
END $$;
|
||||
@@ -4,18 +4,44 @@
|
||||
BEGIN;
|
||||
|
||||
-- Добавляем колонки для хранения файла и его метаданных в таблицу messages
|
||||
ALTER TABLE messages
|
||||
ADD COLUMN attachment_filename TEXT NULL,
|
||||
ADD COLUMN attachment_mimetype TEXT NULL,
|
||||
ADD COLUMN attachment_size BIGINT NULL,
|
||||
ADD COLUMN attachment_data BYTEA NULL;
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'messages' AND column_name = 'attachment_filename') THEN
|
||||
ALTER TABLE messages ADD COLUMN attachment_filename TEXT NULL;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'messages' AND column_name = 'attachment_mimetype') THEN
|
||||
ALTER TABLE messages ADD COLUMN attachment_mimetype TEXT NULL;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'messages' AND column_name = 'attachment_size') THEN
|
||||
ALTER TABLE messages ADD COLUMN attachment_size BIGINT NULL;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'messages' AND column_name = 'attachment_data') THEN
|
||||
ALTER TABLE messages ADD COLUMN attachment_data BYTEA NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Добавляем колонки для хранения файла и его метаданных в таблицу guest_messages
|
||||
ALTER TABLE guest_messages
|
||||
ADD COLUMN attachment_filename TEXT NULL,
|
||||
ADD COLUMN attachment_mimetype TEXT NULL,
|
||||
ADD COLUMN attachment_size BIGINT NULL,
|
||||
ADD COLUMN attachment_data BYTEA NULL;
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'guest_messages' AND column_name = 'attachment_filename') THEN
|
||||
ALTER TABLE guest_messages ADD COLUMN attachment_filename TEXT NULL;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'guest_messages' AND column_name = 'attachment_mimetype') THEN
|
||||
ALTER TABLE guest_messages ADD COLUMN attachment_mimetype TEXT NULL;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'guest_messages' AND column_name = 'attachment_size') THEN
|
||||
ALTER TABLE guest_messages ADD COLUMN attachment_size BIGINT NULL;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'guest_messages' AND column_name = 'attachment_data') THEN
|
||||
ALTER TABLE guest_messages ADD COLUMN attachment_data BYTEA NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Удаляем старую колонку attachments из таблицы messages, если она существует
|
||||
ALTER TABLE messages DROP COLUMN IF EXISTS attachments;
|
||||
@@ -36,7 +62,7 @@ DROP COLUMN IF EXISTS attachment_size,
|
||||
DROP COLUMN IF EXISTS attachment_data;
|
||||
-- Пытаемся вернуть старую колонку (данные будут потеряны при откате)
|
||||
-- Возможно, потребуется указать правильный тип (TEXT или JSONB), который был раньше
|
||||
ALTER TABLE messages ADD COLUMN attachments TEXT NULL;
|
||||
ALTER TABLE messages ADD COLUMN IF NOT EXISTS attachments TEXT NULL;
|
||||
|
||||
ALTER TABLE guest_messages
|
||||
DROP COLUMN IF EXISTS attachment_filename,
|
||||
@@ -45,6 +71,6 @@ DROP COLUMN IF EXISTS attachment_size,
|
||||
DROP COLUMN IF EXISTS attachment_data;
|
||||
-- Пытаемся вернуть старую колонку (данные будут потеряны при откате)
|
||||
-- Возможно, потребуется указать правильный тип (TEXT или JSONB), который был раньше
|
||||
ALTER TABLE guest_messages ADD COLUMN attachments TEXT NULL;
|
||||
ALTER TABLE guest_messages ADD COLUMN IF NOT EXISTS attachments TEXT NULL;
|
||||
|
||||
COMMIT;
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1. Создаем таблицу для названий уровней ISIC
|
||||
-- 1. Создаем таблицу для названий уровней ISIC (если не существует)
|
||||
CREATE TABLE IF NOT EXISTS isic_rev4_level_names (
|
||||
code_level INTEGER PRIMARY KEY,
|
||||
level_name_en TEXT
|
||||
level_name_en_encrypted TEXT
|
||||
);
|
||||
|
||||
-- 2. Создаем основную таблицу для кодов ISIC
|
||||
-- 2. Создаем основную таблицу для кодов ISIC (если не существует)
|
||||
CREATE TABLE IF NOT EXISTS isic_rev4_codes (
|
||||
sort_order INTEGER,
|
||||
code VARCHAR(10) PRIMARY KEY,
|
||||
@@ -23,83 +23,98 @@ CREATE TABLE IF NOT EXISTS isic_rev4_codes (
|
||||
level4 VARCHAR(10),
|
||||
level5 VARCHAR(10),
|
||||
level6 VARCHAR(10),
|
||||
CONSTRAINT fk_code_level FOREIGN KEY (code_level) REFERENCES isic_rev4_level_names (code_level) -- Добавляем внешний ключ
|
||||
CONSTRAINT fk_code_level FOREIGN KEY (code_level) REFERENCES isic_rev4_level_names (code_level)
|
||||
);
|
||||
|
||||
-- 3. Загружаем данные в isic_rev4_level_names
|
||||
-- ВАЖНО: Укажите АБСОЛЮТНЫЙ ПУТЬ к CSV файлу ВНУТРИ Docker-контейнера backend,
|
||||
-- где запущен PostgreSQL или откуда скрипт миграции имеет доступ к файлам.
|
||||
-- Если CSV лежат в backend/db/data/isic/ и ваш Dockerfile копирует всю директорию backend
|
||||
-- то путь может быть что-то вроде '/app/db/data/isic/isic_level_names.csv'
|
||||
-- (где /app - это WORKDIR в вашем Dockerfile для backend сервиса)
|
||||
-- Уточните этот путь!
|
||||
COPY isic_rev4_level_names (code_level, level_name_en)
|
||||
FROM '/mnt/isic_csv_data/isic_level_names.csv' -- <--- ПУТЬ СООТВЕТСТВУЕТ ТОМУ, ЧТО В volumes
|
||||
WITH (FORMAT CSV, HEADER TRUE, DELIMITER ',', QUOTE '"');
|
||||
-- 3. Загружаем данные в isic_rev4_level_names только если таблица пустая
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM isic_rev4_level_names LIMIT 1) THEN
|
||||
-- Создаем временную таблицу для импорта
|
||||
CREATE TEMP TABLE tmp_isic_level_names (
|
||||
code_level_tmp INTEGER,
|
||||
level_name_en_tmp TEXT
|
||||
) ON COMMIT DROP;
|
||||
|
||||
-- Загружаем данные во временную таблицу
|
||||
COPY tmp_isic_level_names (code_level_tmp, level_name_en_tmp)
|
||||
FROM '/app/db/data/isic_level_names.csv'
|
||||
WITH (FORMAT CSV, HEADER TRUE, DELIMITER ',', QUOTE '"');
|
||||
|
||||
-- Вставляем данные в основную таблицу
|
||||
INSERT INTO isic_rev4_level_names (code_level, level_name_en_encrypted)
|
||||
SELECT code_level_tmp, level_name_en_tmp FROM tmp_isic_level_names;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 4. Создаем временные таблицы для импорта основных данных ISIC
|
||||
CREATE TEMP TABLE tmp_isic_titles (
|
||||
sort_order_tmp INTEGER,
|
||||
code_tmp VARCHAR(10),
|
||||
description_tmp TEXT,
|
||||
inclusion_tmp TEXT,
|
||||
exclusion_tmp TEXT
|
||||
) ON COMMIT DROP; -- Временная таблица удалится после коммита
|
||||
-- 4. Загружаем данные в isic_rev4_codes только если таблица пустая
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM isic_rev4_codes LIMIT 1) THEN
|
||||
-- Создаем временные таблицы для импорта основных данных ISIC
|
||||
CREATE TEMP TABLE tmp_isic_titles (
|
||||
sort_order_tmp INTEGER,
|
||||
code_tmp VARCHAR(10),
|
||||
description_tmp TEXT,
|
||||
inclusion_tmp TEXT,
|
||||
exclusion_tmp TEXT
|
||||
) ON COMMIT DROP;
|
||||
|
||||
CREATE TEMP TABLE tmp_isic_structure (
|
||||
sort_order_tmp INTEGER,
|
||||
code_tmp VARCHAR(10),
|
||||
code_level_tmp INTEGER,
|
||||
level1_tmp VARCHAR(10),
|
||||
level2_tmp VARCHAR(10),
|
||||
level3_tmp VARCHAR(10),
|
||||
level4_tmp VARCHAR(10),
|
||||
level5_tmp VARCHAR(10),
|
||||
level6_tmp VARCHAR(10)
|
||||
) ON COMMIT DROP; -- Временная таблица удалится после коммита
|
||||
CREATE TEMP TABLE tmp_isic_structure (
|
||||
sort_order_tmp INTEGER,
|
||||
code_tmp VARCHAR(10),
|
||||
code_level_tmp INTEGER,
|
||||
level1_tmp VARCHAR(10),
|
||||
level2_tmp VARCHAR(10),
|
||||
level3_tmp VARCHAR(10),
|
||||
level4_tmp VARCHAR(10),
|
||||
level5_tmp VARCHAR(10),
|
||||
level6_tmp VARCHAR(10)
|
||||
) ON COMMIT DROP;
|
||||
|
||||
-- 5. Загружаем данные во временные таблицы
|
||||
-- Опять же, укажите правильные АБСОЛЮТНЫЕ ПУТИ внутри контейнера
|
||||
COPY tmp_isic_titles (sort_order_tmp, code_tmp, description_tmp, inclusion_tmp, exclusion_tmp)
|
||||
FROM '/mnt/isic_csv_data/isic_titles.csv' -- <--- ПУТЬ СООТВЕТСТВУЕТ ТОМУ, ЧТО В volumes
|
||||
WITH (FORMAT CSV, HEADER TRUE, DELIMITER ',', QUOTE '"');
|
||||
-- Загружаем данные во временные таблицы
|
||||
COPY tmp_isic_titles (sort_order_tmp, code_tmp, description_tmp, inclusion_tmp, exclusion_tmp)
|
||||
FROM '/app/db/data/isic_titles.csv'
|
||||
WITH (FORMAT CSV, HEADER TRUE, DELIMITER ',', QUOTE '"');
|
||||
|
||||
COPY tmp_isic_structure (sort_order_tmp, code_tmp, code_level_tmp, level1_tmp, level2_tmp, level3_tmp, level4_tmp, level5_tmp, level6_tmp)
|
||||
FROM '/mnt/isic_csv_data/isic_structure.csv' -- <--- ПУТЬ СООТВЕТСТВУЕТ ТОМУ, ЧТО В volumes
|
||||
WITH (FORMAT CSV, HEADER TRUE, DELIMITER ',', QUOTE '"');
|
||||
COPY tmp_isic_structure (sort_order_tmp, code_tmp, code_level_tmp, level1_tmp, level2_tmp, level3_tmp, level4_tmp, level5_tmp, level6_tmp)
|
||||
FROM '/app/db/data/isic_structure.csv'
|
||||
WITH (FORMAT CSV, HEADER TRUE, DELIMITER ',', QUOTE '"');
|
||||
|
||||
-- 6. Переносим и объединяем данные из временных таблиц в основную таблицу isic_rev4_codes
|
||||
INSERT INTO isic_rev4_codes (
|
||||
sort_order,
|
||||
code,
|
||||
description,
|
||||
explanatory_note_inclusion,
|
||||
explanatory_note_exclusion,
|
||||
code_level,
|
||||
level1,
|
||||
level2,
|
||||
level3,
|
||||
level4,
|
||||
level5,
|
||||
level6
|
||||
)
|
||||
SELECT
|
||||
COALESCE(t.sort_order_tmp, s.sort_order_tmp),
|
||||
s.code_tmp,
|
||||
t.description_tmp,
|
||||
t.inclusion_tmp,
|
||||
t.exclusion_tmp,
|
||||
s.code_level_tmp,
|
||||
s.level1_tmp,
|
||||
s.level2_tmp,
|
||||
s.level3_tmp,
|
||||
s.level4_tmp,
|
||||
s.level5_tmp,
|
||||
s.level6_tmp
|
||||
FROM
|
||||
tmp_isic_structure s
|
||||
LEFT JOIN
|
||||
tmp_isic_titles t ON s.code_tmp = t.code_tmp;
|
||||
-- Переносим и объединяем данные из временных таблиц в основную таблицу isic_rev4_codes
|
||||
INSERT INTO isic_rev4_codes (
|
||||
sort_order,
|
||||
code,
|
||||
description,
|
||||
explanatory_note_inclusion,
|
||||
explanatory_note_exclusion,
|
||||
code_level,
|
||||
level1,
|
||||
level2,
|
||||
level3,
|
||||
level4,
|
||||
level5,
|
||||
level6
|
||||
)
|
||||
SELECT
|
||||
COALESCE(t.sort_order_tmp, s.sort_order_tmp),
|
||||
s.code_tmp,
|
||||
t.description_tmp,
|
||||
t.inclusion_tmp,
|
||||
t.exclusion_tmp,
|
||||
s.code_level_tmp,
|
||||
s.level1_tmp,
|
||||
s.level2_tmp,
|
||||
s.level3_tmp,
|
||||
s.level4_tmp,
|
||||
s.level5_tmp,
|
||||
s.level6_tmp
|
||||
FROM
|
||||
tmp_isic_structure s
|
||||
LEFT JOIN
|
||||
tmp_isic_titles t ON s.code_tmp = t.code_tmp;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
COMMIT;
|
||||
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
-- Создаем таблицу email_settings если она не существует
|
||||
CREATE TABLE IF NOT EXISTS email_settings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
smtp_host VARCHAR(255) NOT NULL,
|
||||
smtp_host_encrypted TEXT,
|
||||
smtp_port INTEGER NOT NULL,
|
||||
smtp_user VARCHAR(255) NOT NULL,
|
||||
smtp_password VARCHAR(255) NOT NULL,
|
||||
imap_host VARCHAR(255),
|
||||
smtp_user_encrypted TEXT,
|
||||
smtp_password_encrypted TEXT,
|
||||
imap_host_encrypted TEXT,
|
||||
imap_port INTEGER,
|
||||
from_email VARCHAR(255) NOT NULL,
|
||||
from_email_encrypted TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Для простоты предполагаем, что настройки всегда одни (id=1)
|
||||
INSERT INTO email_settings (smtp_host, smtp_port, smtp_user, smtp_password, imap_host, imap_port, from_email)
|
||||
VALUES ('smtp.example.com', 465, 'user@example.com', 'password', 'imap.example.com', 993, 'noreply@example.com')
|
||||
ON CONFLICT DO NOTHING;
|
||||
-- Пропускаем INSERT, так как данные должны быть зашифрованы
|
||||
-- INSERT INTO email_settings (smtp_host, smtp_port, smtp_user, smtp_password, imap_host, imap_port, from_email)
|
||||
-- VALUES ('smtp.example.com', 465, 'user@example.com', 'password', 'imap.example.com', 993, 'noreply@example.com')
|
||||
-- ON CONFLICT DO NOTHING;
|
||||
@@ -1,12 +1,13 @@
|
||||
-- Создаем таблицу telegram_settings если она не существует
|
||||
CREATE TABLE IF NOT EXISTS telegram_settings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
bot_token VARCHAR(255) NOT NULL,
|
||||
bot_username VARCHAR(255) NOT NULL,
|
||||
bot_token_encrypted TEXT,
|
||||
bot_username_encrypted TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Для простоты предполагаем, что настройки всегда одни (id=1)
|
||||
INSERT INTO telegram_settings (bot_token, bot_username)
|
||||
VALUES ('your-telegram-bot-token', 'your_bot_username')
|
||||
ON CONFLICT DO NOTHING;
|
||||
-- Пропускаем INSERT, так как данные должны быть зашифрованы
|
||||
-- INSERT INTO telegram_settings (bot_token, bot_username)
|
||||
-- VALUES ('your-telegram-bot-token', 'your_bot_username')
|
||||
-- ON CONFLICT DO NOTHING;
|
||||
@@ -1,15 +1,16 @@
|
||||
-- Создаем таблицу db_settings если она не существует
|
||||
CREATE TABLE IF NOT EXISTS db_settings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
db_host VARCHAR(255) NOT NULL,
|
||||
db_host_encrypted TEXT,
|
||||
db_port INTEGER NOT NULL,
|
||||
db_name VARCHAR(255) NOT NULL,
|
||||
db_user VARCHAR(255) NOT NULL,
|
||||
db_password VARCHAR(255) NOT NULL,
|
||||
db_name_encrypted TEXT,
|
||||
db_user_encrypted TEXT,
|
||||
db_password_encrypted TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Для простоты предполагаем, что настройки всегда одни (id=1)
|
||||
INSERT INTO db_settings (db_host, db_port, db_name, db_user, db_password)
|
||||
VALUES ('postgres', 5432, 'dapp_db', 'dapp_user', 'dapp_password')
|
||||
ON CONFLICT DO NOTHING;
|
||||
-- Пропускаем INSERT, так как данные должны быть зашифрованы
|
||||
-- INSERT INTO db_settings (db_host, db_port, db_name, db_user, db_password)
|
||||
-- VALUES ('postgres', 5432, 'dapp_db', 'dapp_user', 'dapp_password')
|
||||
-- ON CONFLICT DO NOTHING;
|
||||
@@ -1,14 +1,16 @@
|
||||
-- Создаем таблицу ai_providers_settings если она не существует
|
||||
CREATE TABLE IF NOT EXISTS ai_providers_settings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
provider VARCHAR(32) NOT NULL UNIQUE, -- openai, anthropic, google, ollama
|
||||
api_key VARCHAR(255),
|
||||
base_url VARCHAR(255),
|
||||
selected_model VARCHAR(128),
|
||||
provider_encrypted TEXT,
|
||||
api_key_encrypted TEXT,
|
||||
base_url_encrypted TEXT,
|
||||
selected_model_encrypted TEXT,
|
||||
embedding_model_encrypted TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Пример заполнения для Ollama (без ключа)
|
||||
INSERT INTO ai_providers_settings (provider, base_url, selected_model)
|
||||
VALUES ('ollama', 'http://localhost:11434', 'qwen2.5')
|
||||
ON CONFLICT (provider) DO NOTHING;
|
||||
-- Пропускаем INSERT, так как данные должны быть зашифрованы
|
||||
-- INSERT INTO ai_providers_settings (provider, base_url, selected_model)
|
||||
-- VALUES ('ollama', 'http://localhost:11434', 'qwen2.5')
|
||||
-- ON CONFLICT (provider) DO NOTHING;
|
||||
@@ -1,21 +1,22 @@
|
||||
-- Создаем таблицу ai_assistant_settings если она не существует
|
||||
CREATE TABLE IF NOT EXISTS ai_assistant_settings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
system_prompt TEXT,
|
||||
system_prompt_encrypted TEXT,
|
||||
selected_rag_tables INTEGER[],
|
||||
languages TEXT[],
|
||||
model TEXT,
|
||||
model_encrypted TEXT,
|
||||
rules JSONB,
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_by INTEGER
|
||||
);
|
||||
|
||||
-- Вставить дефолтную строку (глобальные настройки)
|
||||
INSERT INTO ai_assistant_settings (system_prompt, selected_rag_tables, languages, model, rules)
|
||||
VALUES (
|
||||
'Вы — полезный ассистент. Отвечайте на русском языке.',
|
||||
ARRAY[]::INTEGER[],
|
||||
ARRAY['ru'],
|
||||
'qwen2.5',
|
||||
'{"checkUserTags": true, "searchRagFirst": true, "generateIfNoRag": true, "requireAdminApproval": true}'
|
||||
)
|
||||
ON CONFLICT DO NOTHING;
|
||||
-- Пропускаем INSERT, так как данные должны быть зашифрованы
|
||||
-- INSERT INTO ai_assistant_settings (system_prompt, selected_rag_tables, languages, model, rules)
|
||||
-- VALUES (
|
||||
-- 'Вы — полезный ассистент. Отвечайте на русском языке.',
|
||||
-- ARRAY[]::INTEGER[],
|
||||
-- ARRAY['ru'],
|
||||
-- 'qwen2.5',
|
||||
-- '{"checkUserTags": true, "searchRagFirst": true, "generateIfNoRag": true, "requireAdminApproval": true}'
|
||||
-- )
|
||||
-- ON CONFLICT DO NOTHING;
|
||||
@@ -1,11 +1,11 @@
|
||||
-- Создание справочной таблицы is_rag_source
|
||||
CREATE TABLE IF NOT EXISTS is_rag_source (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(64) NOT NULL UNIQUE
|
||||
name_encrypted TEXT
|
||||
);
|
||||
|
||||
-- Заполнение начальными значениями
|
||||
INSERT INTO is_rag_source (name) VALUES
|
||||
('Да'),
|
||||
('Нет')
|
||||
ON CONFLICT (name) DO NOTHING;
|
||||
-- Пропускаем INSERT, так как данные должны быть зашифрованы
|
||||
-- INSERT INTO is_rag_source (name) VALUES
|
||||
-- ('Да'),
|
||||
-- ('Нет')
|
||||
-- ON CONFLICT (name) DO NOTHING;
|
||||
@@ -1,2 +1,11 @@
|
||||
ALTER TABLE user_tables
|
||||
ADD COLUMN is_rag_source_id INTEGER REFERENCES is_rag_source(id) DEFAULT 2; -- 2 = 'Нет'
|
||||
-- Добавляем колонку is_rag_source_id если она не существует
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'user_tables' AND column_name = 'is_rag_source_id'
|
||||
) THEN
|
||||
ALTER TABLE user_tables
|
||||
ADD COLUMN is_rag_source_id INTEGER REFERENCES is_rag_source(id) DEFAULT 2; -- 2 = 'Нет'
|
||||
END IF;
|
||||
END $$;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- Добавляем колонку options в таблицу user_columns
|
||||
ALTER TABLE user_columns ADD COLUMN IF NOT EXISTS options JSONB DEFAULT '{}'::jsonb;
|
||||
|
||||
-- Создаем индекс для быстрого поиска по options
|
||||
CREATE INDEX IF NOT EXISTS idx_user_columns_options ON user_columns USING GIN (options);
|
||||
@@ -1,21 +1,22 @@
|
||||
-- Миграция: наполнение таблиц rpc_providers и auth_tokens начальными значениями
|
||||
-- Пропускаем INSERT, так как данные должны быть зашифрованы
|
||||
|
||||
-- Добавление RPC-провайдеров
|
||||
INSERT INTO rpc_providers (network_id, rpc_url, chain_id)
|
||||
VALUES
|
||||
('bsc', 'https://bsc-mainnet.nodereal.io/v1/56dec8028bae4f26b76099a42dae2b52', 56),
|
||||
('ethereum', 'https://eth-mainnet.nodereal.io/v1/56dec8028bae4f26b76099a42dae2b52', 1),
|
||||
('arbitrum', 'https://arb1.arbitrum.io/rpc', 42161),
|
||||
('polygon', 'https://polygon.drpc.org', 137),
|
||||
('sepolia', 'https://eth-sepolia.nodereal.io/v1/56dec8028bae4f26b76099a42dae2b52', 11155111)
|
||||
ON CONFLICT (network_id) DO NOTHING;
|
||||
-- Добавление RPC-провайдеров (пропускаем, данные должны быть зашифрованы)
|
||||
-- INSERT INTO rpc_providers (network_id, rpc_url, chain_id)
|
||||
-- VALUES
|
||||
-- ('bsc', 'https://bsc-mainnet.nodereal.io/v1/56dec8028bae4f26b76099a42dae2b52', 56),
|
||||
-- ('ethereum', 'https://eth-mainnet.nodereal.io/v1/56dec8028bae4f26b76099a42dae2b52', 1),
|
||||
-- ('arbitrum', 'https://arb1.arbitrum.io/rpc', 42161),
|
||||
-- ('polygon', 'https://polygon.drpc.org', 137),
|
||||
-- ('sepolia', 'https://eth-sepolia.nodereal.io/v1/56dec8028bae4f26b76099a42dae2b52', 11155111)
|
||||
-- ON CONFLICT (network_id) DO NOTHING;
|
||||
|
||||
-- Добавление токенов для аутентификации админа
|
||||
INSERT INTO auth_tokens (name, address, network, min_balance)
|
||||
VALUES
|
||||
('HB3A', '0x4b294265720b09ca39bfba18c7e368413c0f68eb', 'bsc', 10.0),
|
||||
('HB3A', '0xd95a45fc46a7300e6022885afec3d618d7d3f27c', 'ethereum', 10.0),
|
||||
('test2', '0xef49261169B454f191678D2aFC5E91Ad2e85dfD8', 'sepolia', 50.0),
|
||||
('HB3A', '0x351f59de4fedbdf7601f5592b93db3b9330c1c1d', 'polygon', 10.0),
|
||||
('HB3A', '0xdCe769b847a0a697239777D0B1C7dd33b6012ba0', 'arbitrum', 100.0)
|
||||
ON CONFLICT (address, network) DO NOTHING;
|
||||
-- Добавление токенов для аутентификации админа (пропускаем, данные должны быть зашифрованы)
|
||||
-- INSERT INTO auth_tokens (name, address, network, min_balance)
|
||||
-- VALUES
|
||||
-- ('HB3A', '0x4b294265720b09ca39bfba18c7e368413c0f68eb', 'bsc', 10.0),
|
||||
-- ('HB3A', '0xd95a45fc46a7300e6022885afec3d618d7d3f27c', 'ethereum', 10.0),
|
||||
-- ('test2', '0xef49261169B454f191678D2aFC5E91Ad2e85dfD8', 'sepolia', 50.0),
|
||||
-- ('HB3A', '0x351f59de4fedbdf7601f5592b93db3b9330c1c1d', 'polygon', 10.0),
|
||||
-- ('HB3A', '0xdCe769b847a0a697239777D0B1C7dd33b6012ba0', 'arbitrum', 100.0)
|
||||
-- ON CONFLICT (address, network) DO NOTHING;
|
||||
@@ -1,16 +1,24 @@
|
||||
-- 048_add_order_to_user_rows.sql
|
||||
-- Добавляет поле order в user_rows для поддержки сортировки строк
|
||||
|
||||
ALTER TABLE user_rows ADD COLUMN "order" INTEGER DEFAULT 0;
|
||||
|
||||
-- Проставить уникальные значения order для существующих строк (по id)
|
||||
-- Добавляем колонку order если она не существует
|
||||
DO $$
|
||||
DECLARE
|
||||
r RECORD;
|
||||
idx INTEGER := 1;
|
||||
BEGIN
|
||||
FOR r IN SELECT id FROM user_rows ORDER BY id LOOP
|
||||
UPDATE user_rows SET "order" = idx WHERE id = r.id;
|
||||
idx := idx + 1;
|
||||
END LOOP;
|
||||
END$$;
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'user_rows' AND column_name = 'order'
|
||||
) THEN
|
||||
ALTER TABLE user_rows ADD COLUMN "order" INTEGER DEFAULT 0;
|
||||
|
||||
-- Проставить уникальные значения order для существующих строк (по id)
|
||||
DECLARE
|
||||
r RECORD;
|
||||
idx INTEGER := 1;
|
||||
BEGIN
|
||||
FOR r IN SELECT id FROM user_rows ORDER BY id LOOP
|
||||
UPDATE user_rows SET "order" = idx WHERE id = r.id;
|
||||
idx := idx + 1;
|
||||
END LOOP;
|
||||
END;
|
||||
END IF;
|
||||
END $$;
|
||||
@@ -1,40 +1,8 @@
|
||||
-- Скрипт для ручного исправления дублирующихся записей в базе данных
|
||||
-- Пропускаем операции с зашифрованными колонками
|
||||
|
||||
-- 1. Удаляем существующее ограничение уникальности
|
||||
ALTER TABLE user_identities DROP CONSTRAINT IF EXISTS user_identities_provider_provider_id_key;
|
||||
|
||||
-- 2. Получаем список идентификаторов с дублирующимися записями
|
||||
SELECT
|
||||
provider,
|
||||
LOWER(provider_id) as normalized_provider_id,
|
||||
array_agg(id) as id_list
|
||||
FROM user_identities
|
||||
WHERE provider IN ('wallet', 'email')
|
||||
GROUP BY provider, LOWER(provider_id)
|
||||
HAVING COUNT(*) > 1;
|
||||
|
||||
-- 3. Удаляем конкретные дублирующиеся записи по ID (например, ID=2)
|
||||
DELETE FROM user_identities WHERE id = 2;
|
||||
|
||||
-- 4. Обновляем все записи email и wallet к нижнему регистру
|
||||
UPDATE user_identities
|
||||
SET provider_id = LOWER(provider_id)
|
||||
WHERE provider IN ('wallet', 'email');
|
||||
|
||||
-- 5. Проверяем, что дубликаты удалены
|
||||
SELECT
|
||||
provider,
|
||||
provider_id,
|
||||
COUNT(*) as count
|
||||
FROM user_identities
|
||||
GROUP BY provider, provider_id
|
||||
HAVING COUNT(*) > 1;
|
||||
|
||||
-- 6. Добавляем обратно ограничение уникальности
|
||||
ALTER TABLE user_identities
|
||||
ADD CONSTRAINT user_identities_provider_provider_id_key
|
||||
UNIQUE (provider, provider_id);
|
||||
|
||||
-- 7. Создаем дополнительный индекс для (user_id, provider, provider_id)
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS unique_idx_user_identities_user_provider_provider_id
|
||||
ON user_identities(user_id, provider, provider_id);
|
||||
-- Логируем завершение миграции
|
||||
DO $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'Миграция fix_duplicates_manual.sql пропущена (колонки зашифрованы)';
|
||||
END $$;
|
||||
Reference in New Issue
Block a user