211 lines
7.6 KiB
C#
211 lines
7.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Data.SqlClient;
|
|
using Dapper;
|
|
|
|
namespace MotoresArgentinosV2.MigrationTool;
|
|
|
|
class Program
|
|
{
|
|
// --- CONFIGURACIÓN ---
|
|
public const string ConnectionStringAutos = "Server=localhost;Database=autos;Trusted_Connection=True;TrustServerCertificate=True;";
|
|
public const string ConnectionStringV2 = "Server=localhost;Database=MotoresV2;Trusted_Connection=True;TrustServerCertificate=True;";
|
|
|
|
// Fecha de corte para usuarios inactivos
|
|
static readonly DateTime FechaCorte = new DateTime(2021, 01, 01);
|
|
|
|
static async Task Main(string[] args)
|
|
{
|
|
Console.OutputEncoding = Encoding.UTF8;
|
|
|
|
while (true)
|
|
{
|
|
Console.Clear();
|
|
Console.WriteLine("==================================================");
|
|
Console.WriteLine("🚀 HERRAMIENTA DE MIGRACIÓN MOTORES V2");
|
|
Console.WriteLine("==================================================");
|
|
Console.WriteLine("1. Migrar USUARIOS (Desde 2021)");
|
|
Console.WriteLine("2. Migrar AVISOS DE AUTOS (Activos)");
|
|
Console.WriteLine("3. Migrar AVISOS DE MOTOS (Activos)");
|
|
Console.WriteLine("4. Salir");
|
|
Console.Write("\nSeleccione una opción: ");
|
|
|
|
var key = Console.ReadLine();
|
|
|
|
if (key == "1")
|
|
{
|
|
await RunUserMigration();
|
|
Console.WriteLine("\nPresione Enter para volver...");
|
|
Console.ReadLine();
|
|
}
|
|
else if (key == "2")
|
|
{
|
|
var adMigrator = new AdMigrator(ConnectionStringAutos, ConnectionStringV2);
|
|
await adMigrator.ExecuteAsync();
|
|
Console.WriteLine("\nPresione Enter para volver...");
|
|
Console.ReadLine();
|
|
}
|
|
else if (key == "3")
|
|
{
|
|
var adMigrator = new AdMigrator(ConnectionStringAutos, ConnectionStringV2);
|
|
await adMigrator.MigrateMotosAsync();
|
|
Console.WriteLine("\nPresione Enter para volver...");
|
|
Console.ReadLine();
|
|
}
|
|
else if (key == "4")
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- LÓGICA DE MIGRACIÓN DE USUARIOS (Encapsulada) ---
|
|
static async Task RunUserMigration()
|
|
{
|
|
Console.WriteLine("\n🔍 Iniciando migración de usuarios...");
|
|
|
|
try
|
|
{
|
|
using var dbAutos = new SqlConnection(ConnectionStringAutos);
|
|
using var dbV2 = new SqlConnection(ConnectionStringV2);
|
|
|
|
var queryLegacy = @"
|
|
SELECT
|
|
u.UserName,
|
|
m.Email,
|
|
m.Password as PasswordHash,
|
|
m.PasswordSalt,
|
|
u.LastActivityDate,
|
|
1 as UserType
|
|
FROM aspnet_Users u
|
|
INNER JOIN aspnet_Membership m ON u.UserId = m.UserId
|
|
WHERE u.LastActivityDate >= @FechaCorte";
|
|
|
|
var usersLegacy = (await dbAutos.QueryAsync<UserLegacy>(queryLegacy, new { FechaCorte })).ToList();
|
|
|
|
Console.WriteLine($"✅ Encontrados {usersLegacy.Count} usuarios activos para procesar.");
|
|
|
|
var processedUsernames = new HashSet<string>();
|
|
int migrados = 0;
|
|
int saltados = 0;
|
|
int passReset = 0;
|
|
|
|
foreach (var user in usersLegacy)
|
|
{
|
|
// A. NORMALIZACIÓN
|
|
string cleanUsername = NormalizeUsername(user.UserName);
|
|
if (cleanUsername.Contains("@"))
|
|
{
|
|
cleanUsername = cleanUsername.Split('@')[0];
|
|
cleanUsername = NormalizeUsername(cleanUsername);
|
|
}
|
|
|
|
string finalUsername = cleanUsername;
|
|
int counter = 1;
|
|
|
|
while (processedUsernames.Contains(finalUsername) || await UserExistsInDb(dbV2, finalUsername))
|
|
{
|
|
finalUsername = $"{cleanUsername}{counter}";
|
|
counter++;
|
|
}
|
|
|
|
processedUsernames.Add(finalUsername);
|
|
|
|
// B. LÓGICA DE CONTRASEÑAS
|
|
bool isPlainText = user.PasswordHash.Length < 20;
|
|
string finalHash = user.PasswordHash;
|
|
string? finalSalt = user.PasswordSalt;
|
|
byte migrationStatus = 0;
|
|
|
|
if (isPlainText)
|
|
{
|
|
finalHash = "INVALID_PASSWORD_NEEDS_RESET";
|
|
finalSalt = null;
|
|
passReset++;
|
|
}
|
|
|
|
// C. INSERCIÓN
|
|
var existeEmail = await dbV2.ExecuteScalarAsync<int>(
|
|
"SELECT COUNT(1) FROM Users WHERE Email = @Email", new { user.Email });
|
|
|
|
if (existeEmail == 0)
|
|
{
|
|
var insertQuery = @"
|
|
INSERT INTO Users (
|
|
UserName, Email, PasswordHash, PasswordSalt, MigrationStatus,
|
|
UserType, CreatedAt, IsMFAEnabled, FirstName, LastName
|
|
)
|
|
VALUES (
|
|
@UserName, @Email, @PasswordHash, @PasswordSalt, @MigrationStatus,
|
|
@UserType, @CreatedAt, 0, NULL, NULL
|
|
)";
|
|
|
|
await dbV2.ExecuteAsync(insertQuery, new
|
|
{
|
|
UserName = finalUsername,
|
|
user.Email,
|
|
PasswordHash = finalHash,
|
|
PasswordSalt = finalSalt,
|
|
MigrationStatus = migrationStatus,
|
|
user.UserType,
|
|
CreatedAt = user.LastActivityDate
|
|
});
|
|
|
|
migrados++;
|
|
}
|
|
else
|
|
{
|
|
saltados++;
|
|
}
|
|
}
|
|
|
|
Console.WriteLine($"🏁 FIN: {migrados} migrados, {saltados} saltados (email duplicado).");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"❌ ERROR: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
static async Task<bool> UserExistsInDb(SqlConnection db, string username)
|
|
{
|
|
var count = await db.ExecuteScalarAsync<int>(
|
|
"SELECT COUNT(1) FROM Users WHERE UserName = @username", new { username });
|
|
return count > 0;
|
|
}
|
|
|
|
static string NormalizeUsername(string text)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(text)) return "usuario_desconocido";
|
|
text = text.ToLowerInvariant();
|
|
var normalizedString = text.Normalize(NormalizationForm.FormD);
|
|
var stringBuilder = new StringBuilder();
|
|
|
|
foreach (var c in normalizedString)
|
|
{
|
|
if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
|
|
stringBuilder.Append(c);
|
|
}
|
|
|
|
text = stringBuilder.ToString().Normalize(NormalizationForm.FormC);
|
|
text = Regex.Replace(text, "[^a-z0-9]", "");
|
|
if (string.IsNullOrEmpty(text)) return "usuario";
|
|
return text;
|
|
}
|
|
}
|
|
|
|
public class UserLegacy
|
|
{
|
|
public string UserName { get; set; } = string.Empty;
|
|
public string Email { get; set; } = string.Empty;
|
|
public string PasswordHash { get; set; } = string.Empty;
|
|
public string PasswordSalt { get; set; } = string.Empty;
|
|
public DateTime LastActivityDate { get; set; }
|
|
public int UserType { get; set; }
|
|
} |