init 1.0.0
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
using LehrerApp.Core.Interfaces;
|
||||
using LehrerApp.Core.Services;
|
||||
using LehrerApp.Data;
|
||||
using LehrerApp.Data.Repositories;
|
||||
using LehrerApp.Desktop.ViewModels;
|
||||
using LehrerApp.Desktop.ViewModels.Groups;
|
||||
using LehrerApp.Desktop.ViewModels.Students;
|
||||
using LehrerApp.Sync;
|
||||
using LehrerApp.Sync.Crypto;
|
||||
using LehrerApp.Sync.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace LehrerApp.Desktop;
|
||||
|
||||
/// <summary>
|
||||
/// Konfiguriert den DI-Container für den Desktop-Client.
|
||||
///
|
||||
/// WICHTIG: Alle Repositories sind Singleton – eine LiteDB-Datei pro Nutzer.
|
||||
/// Sync-Services werden nur registriert wenn eine Server-URL konfiguriert ist.
|
||||
/// </summary>
|
||||
public static class AppBootstrapper
|
||||
{
|
||||
public static string DbPath { get; private set; } = "";
|
||||
public static string AppDataPath { get; private set; } = "";
|
||||
|
||||
public static IServiceProvider BuildServices()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
// ── Pfade ─────────────────────────────────────────────────────────────
|
||||
var appData = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"LehrerApp");
|
||||
Directory.CreateDirectory(appData);
|
||||
AppDataPath = appData;
|
||||
DbPath = Path.Combine(appData, "lehrerapp.db");
|
||||
var queuePath = Path.Combine(appData, "syncqueue.db");
|
||||
var keyPath = Path.Combine(appData, "sync.key");
|
||||
|
||||
// ── Datenbank ─────────────────────────────────────────────────────────
|
||||
services.AddSingleton(_ => new LiteDbContext(DbPath));
|
||||
|
||||
// ── Repositories ──────────────────────────────────────────────────────
|
||||
services.AddSingleton<IStudentRepository, StudentRepository>();
|
||||
services.AddSingleton<IGroupRepository, GroupRepository>();
|
||||
services.AddSingleton<IEnrollmentRepository, EnrollmentRepository>();
|
||||
services.AddSingleton<IExamRepository, ExamRepository>();
|
||||
services.AddSingleton<IExamResultRepository, ExamResultRepository>();
|
||||
services.AddSingleton<IGradeRepository, GradeRepository>();
|
||||
services.AddSingleton<IUnitRepository, UnitRepository>();
|
||||
services.AddSingleton<ILessonRepository, LessonRepository>();
|
||||
services.AddSingleton<IDocumentationRepository, DocumentationRepository>();
|
||||
services.AddSingleton<IWorkTaskRepository, WorkTaskRepository>();
|
||||
services.AddSingleton<ITimeEntryRepository, TimeEntryRepository>();
|
||||
|
||||
// ── Services ──────────────────────────────────────────────────────────
|
||||
services.AddSingleton<GradingService>();
|
||||
services.AddSingleton<SchoolYearService>();
|
||||
|
||||
// ── Sync (optional – nur wenn Server konfiguriert) ────────────────────
|
||||
services.AddSingleton(_ => new EventQueue(queuePath));
|
||||
services.AddSingleton(sp => new ConflictResolver(sp.GetRequiredService<EventQueue>()));
|
||||
services.AddSingleton<byte[]>(_ =>
|
||||
{
|
||||
var key = SyncCrypto.LoadKey(keyPath) ?? SyncCrypto.GenerateKey();
|
||||
SyncCrypto.SaveKey(key, keyPath);
|
||||
return key;
|
||||
});
|
||||
|
||||
var serverUrl = LoadServerUrl(appData);
|
||||
var deviceId = LoadOrCreateDeviceId(appData);
|
||||
|
||||
if (!string.IsNullOrEmpty(serverUrl))
|
||||
{
|
||||
services.AddSingleton<SyncEngine>(sp => new SyncEngine(
|
||||
sp.GetRequiredService<EventQueue>(),
|
||||
sp.GetRequiredService<ConflictResolver>(),
|
||||
BuildHttp(serverUrl, appData),
|
||||
new SyncConfig
|
||||
{
|
||||
ServerUrl = serverUrl,
|
||||
DeviceId = deviceId,
|
||||
DeviceType = DeviceType.Desktop,
|
||||
AutoSyncIntervalMinutes = 5,
|
||||
}));
|
||||
|
||||
services.AddSingleton<SnapshotService>(sp => new SnapshotService(
|
||||
BuildHttp(serverUrl, appData),
|
||||
sp.GetRequiredService<LiteDbContext>(),
|
||||
sp.GetRequiredService<byte[]>(),
|
||||
DeviceType.Desktop, DbPath, keyPath));
|
||||
}
|
||||
|
||||
// ── ViewModels ────────────────────────────────────────────────────────
|
||||
// Singleton: einmal erstellt, überall dieselbe Instanz
|
||||
services.AddSingleton<MainWindowViewModel>();
|
||||
services.AddSingleton<DashboardViewModel>();
|
||||
services.AddSingleton<SyncStatusViewModel>();
|
||||
services.AddSingleton<GroupListViewModel>();
|
||||
services.AddSingleton<StudentListViewModel>();
|
||||
|
||||
// Transient: neue Instanz pro Navigation (für Detailseiten)
|
||||
services.AddTransient<GroupDetailViewModel>();
|
||||
services.AddTransient<StudentDetailViewModel>();
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
// ── Hilfsmethoden ─────────────────────────────────────────────────────────
|
||||
|
||||
private static HttpClient BuildHttp(string url, string appData)
|
||||
{
|
||||
var http = new HttpClient { BaseAddress = new Uri(url) };
|
||||
var tokenPath = Path.Combine(appData, "auth.token");
|
||||
if (File.Exists(tokenPath))
|
||||
http.DefaultRequestHeaders.Authorization =
|
||||
new System.Net.Http.Headers.AuthenticationHeaderValue(
|
||||
"Bearer", File.ReadAllText(tokenPath).Trim());
|
||||
return http;
|
||||
}
|
||||
|
||||
public static string LoadServerUrl(string? path = null) =>
|
||||
File.Exists(Path.Combine(path ?? AppDataPath, "server.txt"))
|
||||
? File.ReadAllText(Path.Combine(path ?? AppDataPath, "server.txt")).Trim()
|
||||
: "";
|
||||
|
||||
public static void SaveServerUrl(string url) =>
|
||||
File.WriteAllText(Path.Combine(AppDataPath, "server.txt"), url);
|
||||
|
||||
private static string LoadOrCreateDeviceId(string appData)
|
||||
{
|
||||
var p = Path.Combine(appData, "device.id");
|
||||
if (File.Exists(p)) return File.ReadAllText(p).Trim();
|
||||
var id = Guid.NewGuid().ToString();
|
||||
File.WriteAllText(p, id);
|
||||
return id;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user