- Register IUserAccessAuditService, IGraphUserSearchService, export services, ViewModel and View in App.xaml.cs - Create UserAccessAuditView.xaml with two-panel layout: people picker, site picker, scan options, color-coded DataGrid with grouping, summary banner - Create UserAccessAuditView.xaml.cs code-behind with ViewModel constructor injection - [Rule 3] UserAccessAuditView was missing (07-05 not executed); created inline to unblock 07-07
165 lines
6.9 KiB
C#
165 lines
6.9 KiB
C#
using System.IO;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Serilog;
|
|
using SharepointToolbox.Core.Models;
|
|
using SharepointToolbox.Infrastructure.Auth;
|
|
using SharepointToolbox.Infrastructure.Logging;
|
|
using SharepointToolbox.Infrastructure.Persistence;
|
|
using SharepointToolbox.Services;
|
|
using SharepointToolbox.Services.Export;
|
|
using SharepointToolbox.ViewModels;
|
|
using SharepointToolbox.ViewModels.Tabs;
|
|
using SharepointToolbox.Views.Dialogs;
|
|
using SharepointToolbox.Views.Tabs;
|
|
using System.Windows;
|
|
|
|
namespace SharepointToolbox;
|
|
|
|
public partial class App : Application
|
|
{
|
|
[STAThread]
|
|
public static void Main(string[] args)
|
|
{
|
|
using IHost host = Host.CreateDefaultBuilder(args)
|
|
.UseSerilog((ctx, cfg) => cfg
|
|
.WriteTo.File(
|
|
Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
|
"SharepointToolbox", "logs", "app-.log"),
|
|
rollingInterval: RollingInterval.Day,
|
|
retainedFileCountLimit: 30))
|
|
.ConfigureServices(RegisterServices)
|
|
.Build();
|
|
|
|
host.Start();
|
|
App app = new();
|
|
app.InitializeComponent();
|
|
|
|
var mainWindow = host.Services.GetRequiredService<MainWindow>();
|
|
|
|
// Wire LogPanelSink now that we have the RichTextBox
|
|
Log.Logger = new LoggerConfiguration()
|
|
.WriteTo.File(
|
|
Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
|
"SharepointToolbox", "logs", "app-.log"),
|
|
rollingInterval: RollingInterval.Day,
|
|
retainedFileCountLimit: 30)
|
|
.WriteTo.Sink(new LogPanelSink(mainWindow.GetLogPanel()))
|
|
.CreateLogger();
|
|
|
|
// Global exception handlers
|
|
app.DispatcherUnhandledException += (s, e) =>
|
|
{
|
|
Log.Fatal(e.Exception, "Unhandled UI exception");
|
|
MessageBox.Show(
|
|
$"A fatal error occurred:\n{e.Exception.Message}\n\nCheck log for details.",
|
|
"Fatal Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
e.Handled = true;
|
|
};
|
|
TaskScheduler.UnobservedTaskException += (s, e) =>
|
|
{
|
|
Log.Fatal(e.Exception, "Unobserved task exception");
|
|
e.SetObserved();
|
|
};
|
|
|
|
app.MainWindow = mainWindow;
|
|
app.MainWindow.Visibility = Visibility.Visible;
|
|
app.Run();
|
|
}
|
|
|
|
private static void RegisterServices(HostBuilderContext ctx, IServiceCollection services)
|
|
{
|
|
var appData = Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
|
"SharepointToolbox");
|
|
services.AddSingleton(_ => new ProfileRepository(Path.Combine(appData, "profiles.json")));
|
|
services.AddSingleton(_ => new SettingsRepository(Path.Combine(appData, "settings.json")));
|
|
services.AddSingleton<MsalClientFactory>();
|
|
services.AddSingleton<SessionManager>();
|
|
services.AddSingleton<ISessionManager>(sp => sp.GetRequiredService<SessionManager>());
|
|
services.AddSingleton<ProfileService>();
|
|
services.AddSingleton<SettingsService>();
|
|
services.AddSingleton<MainWindowViewModel>();
|
|
services.AddTransient<ProfileManagementViewModel>();
|
|
services.AddTransient<SettingsViewModel>();
|
|
services.AddTransient<ProfileManagementDialog>();
|
|
services.AddTransient<SettingsView>();
|
|
|
|
// Phase 3: Storage
|
|
services.AddTransient<IStorageService, StorageService>();
|
|
services.AddTransient<StorageCsvExportService>();
|
|
services.AddTransient<StorageHtmlExportService>();
|
|
services.AddTransient<StorageViewModel>();
|
|
services.AddTransient<StorageView>();
|
|
|
|
// Phase 3: File Search
|
|
services.AddTransient<ISearchService, SearchService>();
|
|
services.AddTransient<SearchCsvExportService>();
|
|
services.AddTransient<SearchHtmlExportService>();
|
|
services.AddTransient<SearchViewModel>();
|
|
services.AddTransient<SearchView>();
|
|
|
|
// Phase 3: Duplicates
|
|
services.AddTransient<IDuplicatesService, DuplicatesService>();
|
|
services.AddTransient<DuplicatesHtmlExportService>();
|
|
services.AddTransient<DuplicatesViewModel>();
|
|
services.AddTransient<DuplicatesView>();
|
|
|
|
// Phase 2: Permissions
|
|
services.AddTransient<IPermissionsService, PermissionsService>();
|
|
services.AddTransient<ISiteListService, SiteListService>();
|
|
services.AddTransient<CsvExportService>();
|
|
services.AddTransient<HtmlExportService>();
|
|
services.AddTransient<PermissionsViewModel>();
|
|
services.AddTransient<PermissionsView>();
|
|
services.AddTransient<SitePickerDialog>();
|
|
services.AddTransient<Func<TenantProfile, SitePickerDialog>>(sp =>
|
|
profile => new SitePickerDialog(sp.GetRequiredService<ISiteListService>(), profile));
|
|
|
|
// Phase 4: Bulk Operations Infrastructure
|
|
var templatesDir = Path.Combine(appData, "templates");
|
|
services.AddSingleton(_ => new TemplateRepository(templatesDir));
|
|
services.AddSingleton<GraphClientFactory>();
|
|
services.AddTransient<ICsvValidationService, CsvValidationService>();
|
|
services.AddTransient<BulkResultCsvExportService>();
|
|
|
|
// Phase 4: File Transfer
|
|
services.AddTransient<IFileTransferService, FileTransferService>();
|
|
services.AddTransient<TransferViewModel>();
|
|
services.AddTransient<TransferView>();
|
|
|
|
// Phase 4: Bulk Members
|
|
services.AddTransient<IBulkMemberService, BulkMemberService>();
|
|
services.AddTransient<BulkMembersViewModel>();
|
|
services.AddTransient<BulkMembersView>();
|
|
|
|
// Phase 4: Bulk Sites
|
|
services.AddTransient<IBulkSiteService, BulkSiteService>();
|
|
services.AddTransient<BulkSitesViewModel>();
|
|
services.AddTransient<BulkSitesView>();
|
|
|
|
// Phase 4: Templates
|
|
services.AddTransient<ITemplateService, TemplateService>();
|
|
services.AddTransient<TemplatesViewModel>();
|
|
services.AddTransient<TemplatesView>();
|
|
|
|
// Phase 4: Folder Structure
|
|
services.AddTransient<IFolderStructureService, FolderStructureService>();
|
|
services.AddTransient<FolderStructureViewModel>();
|
|
services.AddTransient<FolderStructureView>();
|
|
|
|
// Phase 7: User Access Audit
|
|
services.AddTransient<IUserAccessAuditService, UserAccessAuditService>();
|
|
services.AddTransient<IGraphUserSearchService, GraphUserSearchService>();
|
|
services.AddTransient<UserAccessCsvExportService>();
|
|
services.AddTransient<UserAccessHtmlExportService>();
|
|
services.AddTransient<UserAccessAuditViewModel>();
|
|
services.AddTransient<UserAccessAuditView>();
|
|
|
|
services.AddSingleton<MainWindow>();
|
|
}
|
|
}
|