ваше сообщение коммита

This commit is contained in:
2025-04-21 18:03:43 +03:00
parent 4648aab7d5
commit 43569ea38c
37 changed files with 7226 additions and 1425 deletions

View File

@@ -15,19 +15,19 @@ class IdentityService {
if (!provider || !providerId) {
return { provider, providerId };
}
// Приводим провайдер к нижнему регистру
const normalizedProvider = provider.toLowerCase();
// Для email и wallet приводим значение к нижнему регистру
let normalizedProviderId = providerId;
if (normalizedProvider === 'wallet' || normalizedProvider === 'email') {
normalizedProviderId = providerId.toLowerCase();
}
return {
provider: normalizedProvider,
providerId: normalizedProviderId
return {
provider: normalizedProvider,
providerId: normalizedProviderId,
};
}
@@ -42,21 +42,25 @@ class IdentityService {
async saveIdentity(userId, provider, providerId, verified = true) {
try {
if (!userId || !provider || !providerId) {
logger.warn(`[IdentityService] Missing required parameters: userId=${userId}, provider=${provider}, providerId=${providerId}`);
logger.warn(
`[IdentityService] Missing required parameters: userId=${userId}, provider=${provider}, providerId=${providerId}`
);
return {
success: false,
error: 'Missing required parameters'
error: 'Missing required parameters',
};
}
// Нормализуем значения
const { provider: normalizedProvider, providerId: normalizedProviderId } =
const { provider: normalizedProvider, providerId: normalizedProviderId } =
this.normalizeIdentity(provider, providerId);
// Проверяем тип провайдера и перенаправляем гостевые идентификаторы в guest_user_mapping
if (normalizedProvider === 'guest') {
logger.info(`[IdentityService] Converting guest identity for user ${userId} to guest_user_mapping: ${normalizedProviderId}`);
logger.info(
`[IdentityService] Converting guest identity for user ${userId} to guest_user_mapping: ${normalizedProviderId}`
);
try {
await db.query(
'INSERT INTO guest_user_mapping (user_id, guest_id) VALUES ($1, $2) ON CONFLICT (guest_id) DO UPDATE SET user_id = $1',
@@ -64,41 +68,50 @@ class IdentityService {
);
return { success: true };
} catch (guestError) {
logger.error(`[IdentityService] Error saving guest identity for user ${userId}:`, guestError);
logger.error(
`[IdentityService] Error saving guest identity for user ${userId}:`,
guestError
);
return { success: false, error: guestError.message };
}
}
// Проверяем, разрешен ли такой тип провайдера
const allowedProviders = ['email', 'wallet', 'telegram', 'username'];
if (!allowedProviders.includes(normalizedProvider)) {
logger.warn(`[IdentityService] Invalid provider type: ${normalizedProvider}`);
return {
success: false,
error: `Invalid provider type. Allowed types: ${allowedProviders.join(', ')}`
error: `Invalid provider type. Allowed types: ${allowedProviders.join(', ')}`,
};
}
logger.info(`[IdentityService] Saving identity for user ${userId}: ${normalizedProvider}:${normalizedProviderId}`);
logger.info(
`[IdentityService] Saving identity for user ${userId}: ${normalizedProvider}:${normalizedProviderId}`
);
// Проверяем, существует ли уже такой идентификатор
const existingResult = await db.query(
`SELECT user_id FROM user_identities WHERE provider = $1 AND provider_id = $2`,
[normalizedProvider, normalizedProviderId]
);
if (existingResult.rows.length > 0) {
const existingUserId = existingResult.rows[0].user_id;
// Если идентификатор уже принадлежит этому пользователю, ничего не делаем
if (existingUserId === userId) {
logger.info(`[IdentityService] Identity ${normalizedProvider}:${normalizedProviderId} already exists for user ${userId}`);
logger.info(
`[IdentityService] Identity ${normalizedProvider}:${normalizedProviderId} already exists for user ${userId}`
);
} else {
// Если идентификатор принадлежит другому пользователю, логируем это
logger.warn(`[IdentityService] Identity ${normalizedProvider}:${normalizedProviderId} already belongs to user ${existingUserId}, not user ${userId}`);
logger.warn(
`[IdentityService] Identity ${normalizedProvider}:${normalizedProviderId} already belongs to user ${existingUserId}, not user ${userId}`
);
return {
success: false,
error: `Identity already belongs to another user (${existingUserId})`
error: `Identity already belongs to another user (${existingUserId})`,
};
}
} else {
@@ -108,16 +121,21 @@ class IdentityService {
VALUES ($1, $2, $3)`,
[userId, normalizedProvider, normalizedProviderId]
);
logger.info(`[IdentityService] Created new identity ${normalizedProvider}:${normalizedProviderId} for user ${userId}`);
logger.info(
`[IdentityService] Created new identity ${normalizedProvider}:${normalizedProviderId} for user ${userId}`
);
}
return { success: true };
} catch (error) {
logger.error(`[IdentityService] Error saving identity ${provider}:${providerId} for user ${userId}:`, error);
logger.error(
`[IdentityService] Error saving identity ${provider}:${providerId} for user ${userId}:`,
error
);
return { success: false, error: error.message };
}
}
/**
* Получает все идентификаторы пользователя
* @param {number} userId - ID пользователя
@@ -129,12 +147,12 @@ class IdentityService {
logger.warn('[IdentityService] Missing userId parameter');
return [];
}
const result = await db.query(
`SELECT provider, provider_id FROM user_identities WHERE user_id = $1`,
[userId]
);
logger.info(`[IdentityService] Found ${result.rows.length} identities for user ${userId}`);
return result.rows;
} catch (error) {
@@ -142,7 +160,7 @@ class IdentityService {
return [];
}
}
/**
* Получает все идентификаторы пользователя определенного типа
* @param {number} userId - ID пользователя
@@ -155,20 +173,25 @@ class IdentityService {
logger.warn(`[IdentityService] Missing parameters: userId=${userId}, provider=${provider}`);
return [];
}
const result = await db.query(
`SELECT provider_id FROM user_identities WHERE user_id = $1 AND provider = $2`,
[userId, provider]
);
logger.info(`[IdentityService] Found ${result.rows.length} ${provider} identities for user ${userId}`);
return result.rows.map(row => row.provider_id);
logger.info(
`[IdentityService] Found ${result.rows.length} ${provider} identities for user ${userId}`
);
return result.rows.map((row) => row.provider_id);
} catch (error) {
logger.error(`[IdentityService] Error getting ${provider} identities for user ${userId}:`, error);
logger.error(
`[IdentityService] Error getting ${provider} identities for user ${userId}:`,
error
);
return [];
}
}
/**
* Находит пользователя по идентификатору
* @param {string} provider - Тип идентификатора
@@ -178,34 +201,43 @@ class IdentityService {
async findUserByIdentity(provider, providerId) {
try {
if (!provider || !providerId) {
logger.warn(`[IdentityService] Missing parameters: provider=${provider}, providerId=${providerId}`);
logger.warn(
`[IdentityService] Missing parameters: provider=${provider}, providerId=${providerId}`
);
return null;
}
// Нормализуем значения
const { provider: normalizedProvider, providerId: normalizedProviderId } =
const { provider: normalizedProvider, providerId: normalizedProviderId } =
this.normalizeIdentity(provider, providerId);
const result = await db.query(
`SELECT u.id, u.role FROM users u
JOIN user_identities ui ON u.id = ui.user_id
WHERE ui.provider = $1 AND ui.provider_id = $2`,
[normalizedProvider, normalizedProviderId]
);
if (result.rows.length === 0) {
logger.info(`[IdentityService] No user found with identity ${normalizedProvider}:${normalizedProviderId}`);
logger.info(
`[IdentityService] No user found with identity ${normalizedProvider}:${normalizedProviderId}`
);
return null;
}
logger.info(`[IdentityService] Found user ${result.rows[0].id} with identity ${normalizedProvider}:${normalizedProviderId}`);
logger.info(
`[IdentityService] Found user ${result.rows[0].id} with identity ${normalizedProvider}:${normalizedProviderId}`
);
return result.rows[0];
} catch (error) {
logger.error(`[IdentityService] Error finding user by identity ${provider}:${providerId}:`, error);
logger.error(
`[IdentityService] Error finding user by identity ${provider}:${providerId}:`,
error
);
return null;
}
}
/**
* Сохраняет идентификаторы из сессии для пользователя
* @param {object} session - Объект сессии
@@ -218,25 +250,30 @@ class IdentityService {
logger.warn(`[IdentityService] Missing parameters: session=${!!session}, userId=${userId}`);
return { success: false, error: 'Missing required parameters' };
}
const results = [];
// Сохраняем все постоянные идентификаторы из сессии
if (session.email) {
const emailResult = await this.saveIdentity(userId, 'email', session.email, true);
results.push({ type: 'email', result: emailResult });
}
if (session.address) {
const walletResult = await this.saveIdentity(userId, 'wallet', session.address, true);
results.push({ type: 'wallet', result: walletResult });
}
if (session.telegramId) {
const telegramResult = await this.saveIdentity(userId, 'telegram', session.telegramId, true);
const telegramResult = await this.saveIdentity(
userId,
'telegram',
session.telegramId,
true
);
results.push({ type: 'telegram', result: telegramResult });
}
// Сохраняем гостевые идентификаторы в guest_user_mapping
if (session.guestId) {
try {
@@ -250,7 +287,7 @@ class IdentityService {
results.push({ type: 'guest', result: { success: false, error: error.message } });
}
}
if (session.previousGuestId && session.previousGuestId !== session.guestId) {
try {
await db.query(
@@ -259,19 +296,27 @@ class IdentityService {
);
results.push({ type: 'previousGuest', result: { success: true } });
} catch (error) {
logger.error(`[IdentityService] Error saving previous guest ID for user ${userId}:`, error);
logger.error(
`[IdentityService] Error saving previous guest ID for user ${userId}:`,
error
);
results.push({ type: 'previousGuest', result: { success: false, error: error.message } });
}
}
logger.info(`[IdentityService] Saved ${results.length} identities from session for user ${userId}`);
logger.info(
`[IdentityService] Saved ${results.length} identities from session for user ${userId}`
);
return { success: true, results };
} catch (error) {
logger.error(`[IdentityService] Error saving identities from session for user ${userId}:`, error);
logger.error(
`[IdentityService] Error saving identities from session for user ${userId}:`,
error
);
return { success: false, error: error.message };
}
}
/**
* Мигрирует все идентификаторы и сообщения от одного пользователя к другому
* @param {number} fromUserId - ID исходного пользователя
@@ -281,7 +326,9 @@ class IdentityService {
async migrateUserData(fromUserId, toUserId) {
try {
if (!fromUserId || !toUserId) {
logger.warn(`[IdentityService] Missing parameters: fromUserId=${fromUserId}, toUserId=${toUserId}`);
logger.warn(
`[IdentityService] Missing parameters: fromUserId=${fromUserId}, toUserId=${toUserId}`
);
return { success: false, error: 'Missing required parameters' };
}
@@ -295,7 +342,7 @@ class IdentityService {
`SELECT provider, provider_id FROM user_identities WHERE user_id = $1`,
[fromUserId]
);
// Переносим каждый идентификатор
for (const identity of identitiesResult.rows) {
await client.query(
@@ -304,7 +351,7 @@ class IdentityService {
ON CONFLICT (provider, provider_id) DO NOTHING`,
[toUserId, identity.provider, identity.provider_id]
);
// Удаляем старый идентификатор
await client.query(
`DELETE FROM user_identities
@@ -312,13 +359,13 @@ class IdentityService {
[fromUserId, identity.provider, identity.provider_id]
);
}
// Мигрируем гостевые идентификаторы из новой таблицы guest_user_mapping
const guestMappingsResult = await client.query(
`SELECT guest_id, processed FROM guest_user_mapping WHERE user_id = $1`,
[fromUserId]
);
// Переносим каждый гостевой идентификатор
for (const mapping of guestMappingsResult.rows) {
await client.query(
@@ -329,12 +376,9 @@ class IdentityService {
[toUserId, mapping.guest_id, mapping.processed]
);
}
// Удаляем старые гостевые маппинги
await client.query(
`DELETE FROM guest_user_mapping WHERE user_id = $1`,
[fromUserId]
);
await client.query(`DELETE FROM guest_user_mapping WHERE user_id = $1`, [fromUserId]);
// Переносим все сообщения
await client.query(
@@ -351,7 +395,7 @@ class IdentityService {
WHERE user_id = $2`,
[toUserId, fromUserId]
);
// Переносим настройки пользователя
await client.query(
`UPDATE user_preferences
@@ -362,8 +406,10 @@ class IdentityService {
// Завершаем транзакцию
await client.query('COMMIT');
logger.info(`[IdentityService] Successfully migrated data from user ${fromUserId} to ${toUserId}`);
logger.info(
`[IdentityService] Successfully migrated data from user ${fromUserId} to ${toUserId}`
);
return { success: true };
} catch (error) {
await client.query('ROLLBACK');
@@ -386,20 +432,20 @@ class IdentityService {
async findRelatedUsers(identities) {
try {
const userIds = new Set();
for (const [provider, providerId] of Object.entries(identities)) {
if (!providerId) continue;
const result = await db.query(
`SELECT DISTINCT user_id
FROM user_identities
WHERE provider = $1 AND provider_id = $2`,
[provider, providerId]
);
result.rows.forEach(row => userIds.add(row.user_id));
result.rows.forEach((row) => userIds.add(row.user_id));
}
return Array.from(userIds);
} catch (error) {
logger.error(`[IdentityService] Error finding related users:`, error);
@@ -408,4 +454,4 @@ class IdentityService {
}
}
module.exports = new IdentityService();
module.exports = new IdentityService();