LANCommander/LANCommander.Server.Services/SetupService.cs
2025-12-11 01:58:28 -06:00

174 lines
6.2 KiB
C#

using LANCommander.SDK;
using LANCommander.SDK.Enums;
using LANCommander.Server.Data;
using LANCommander.Server.Data.Enums;
using LANCommander.Server.Data.Models;
using LANCommander.Server.Settings.Enums;
using Microsoft.AspNetCore.Identity;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MySqlConnector;
using Npgsql;
namespace LANCommander.Server.Services
{
public class SetupService(
ILogger<SetupService> logger,
SettingsProvider<Settings.Settings> settingsProvider,
UserManager<User> userManager,
IServiceProvider serviceProvider) : BaseService(logger, settingsProvider), IDisposable
{
public async Task<bool> IsSetupInitialized()
{
try
{
if (DatabaseContext.Provider == DatabaseProvider.Unknown)
return false;
var admins = await userManager.GetUsersInRoleAsync(RoleService.AdministratorRoleName);
return admins.Any();
}
catch (Exception ex)
{
logger.LogError(ex, ex.Message);
return false;
}
}
public async Task ChangeProviderAsync(DatabaseProvider provider, string connectionString)
{
DatabaseContext.Provider = provider;
DatabaseContext.ConnectionString = connectionString;
using (var scope = serviceProvider.CreateScope())
{
var dbFactory = scope.ServiceProvider.GetService<IDbContextFactory<DatabaseContext>>();
var db = await dbFactory.CreateDbContextAsync();
if ((await db.Database.GetPendingMigrationsAsync()).Any())
{
if (provider == DatabaseProvider.SQLite)
{
var dataSource = new SqliteConnectionStringBuilder(connectionString).DataSource;
var backupName = AppPaths.GetConfigPath("Backups",
$"LANCommander.db.{DateTime.Now.ToString("dd-MM-yyyy-HH.mm.ss.bak")}");
if (File.Exists(dataSource))
{
_logger.LogInformation("Migrations pending, database will be backed up to {BackupName}", backupName);
File.Copy(dataSource, backupName);
}
}
await db.Database.MigrateAsync();
}
await db.DisposeAsync();
}
}
public static bool ValidateConnectionString(DatabaseProvider provider, string connectionString)
{
switch (provider)
{
case DatabaseProvider.SQLite:
return ValidateSqliteConnectionString(connectionString);
case DatabaseProvider.PostgreSQL:
return ValidatePostgreSqlConnectionString(connectionString);
case DatabaseProvider.MySQL:
return ValidateMySqlConnectionString(connectionString);
default:
return false;
}
}
public static bool ValidateSqliteConnectionString(string connectionString)
{
using (SqliteConnection connection = new SqliteConnection(connectionString))
{
connection.Open();
return true;
}
}
public static bool ValidatePostgreSqlConnectionString(string connectionString)
{
using (NpgsqlConnection connection = new NpgsqlConnection(connectionString))
{
connection.Open();
return true;
}
}
public static bool ValidateMySqlConnectionString(string connectionString)
{
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
return true;
}
}
public async Task UpdatePaths(IEnumerable<StorageLocation> storageLocations)
{
if (!storageLocations.Any(l => l.Type == StorageLocationType.Archive && l.Default))
throw new Exception("Missing a default archive location");
if (!storageLocations.Any(l => l.Type == StorageLocationType.Media && l.Default))
throw new Exception("Missing a default media location");
if (!storageLocations.Any(l => l.Type == StorageLocationType.Save && l.Default))
throw new Exception("Missing a default save location");
using (var scope = serviceProvider.CreateScope())
{
var dbFactory = scope.ServiceProvider.GetService<IDbContextFactory<DatabaseContext>>();
var db = await dbFactory.CreateDbContextAsync();
foreach (var storageLocation in storageLocations)
{
if (!Directory.Exists(storageLocation.Path))
Directory.CreateDirectory(storageLocation.Path);
try
{
if (storageLocation.Id == Guid.Empty)
{
await db.StorageLocations.AddAsync(storageLocation);
}
else
{
var existingStorageLocation = await db.StorageLocations.FindAsync(storageLocation.Id);
// Copy scalar values
db.Entry(existingStorageLocation).CurrentValues.SetValues(storageLocation);
}
await db.SaveChangesAsync();
}
catch (Exception ex)
{
logger.LogError(ex, "Could not create storage location {Path}", storageLocation.Path);
throw new Exception($"Could not create storage location {storageLocation.Path}");
}
}
}
}
public void Dispose()
{
}
}
}