feat(17-02): wire ISharePointGroupResolver into PermissionsViewModel export flow

- Add _groupResolver field (ISharePointGroupResolver?) with constructor injection
- ISharePointGroupResolver added as optional last parameter in main constructor
- ExportHtmlAsync resolves SharePoint group names before calling WriteAsync
- Gracefully handles resolution failure with LogWarning, exports without expansion
- Both WriteAsync call sites pass groupMembers dict (standard and simplified paths)
This commit is contained in:
Dev
2026-04-09 13:10:31 +02:00
parent 07ed6e2515
commit aab3aee3df

View File

@@ -27,6 +27,7 @@ public partial class PermissionsViewModel : FeatureViewModelBase
private readonly CsvExportService? _csvExportService;
private readonly HtmlExportService? _htmlExportService;
private readonly IBrandingService? _brandingService;
private readonly ISharePointGroupResolver? _groupResolver;
private readonly ILogger<FeatureViewModelBase> _logger;
// ── Observable properties ───────────────────────────────────────────────
@@ -134,7 +135,8 @@ public partial class PermissionsViewModel : FeatureViewModelBase
CsvExportService csvExportService,
HtmlExportService htmlExportService,
IBrandingService brandingService,
ILogger<FeatureViewModelBase> logger)
ILogger<FeatureViewModelBase> logger,
ISharePointGroupResolver? groupResolver = null)
: base(logger)
{
_permissionsService = permissionsService;
@@ -143,6 +145,7 @@ public partial class PermissionsViewModel : FeatureViewModelBase
_csvExportService = csvExportService;
_htmlExportService = htmlExportService;
_brandingService = brandingService;
_groupResolver = groupResolver;
_logger = logger;
ExportCsvCommand = new AsyncRelayCommand(ExportCsvAsync, CanExport);
@@ -330,10 +333,37 @@ public partial class PermissionsViewModel : FeatureViewModelBase
branding = new ReportBranding(mspLogo, clientLogo);
}
IReadOnlyDictionary<string, IReadOnlyList<ResolvedMember>>? groupMembers = null;
if (_groupResolver != null && Results.Count > 0)
{
var groupNames = Results
.Where(r => r.PrincipalType == "SharePointGroup")
.SelectMany(r => r.Users.Split(';', StringSplitOptions.RemoveEmptyEntries))
.Select(n => n.Trim())
.Where(n => n.Length > 0)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
if (groupNames.Count > 0 && _currentProfile != null)
{
try
{
var ctx = await _sessionManager.GetOrCreateContextAsync(
_currentProfile, CancellationToken.None);
groupMembers = await _groupResolver.ResolveGroupsAsync(
ctx, _currentProfile.ClientId, groupNames, CancellationToken.None);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Group resolution failed — exporting without member expansion.");
}
}
}
if (IsSimplifiedMode && SimplifiedResults.Count > 0)
await _htmlExportService.WriteAsync(SimplifiedResults.ToList(), dialog.FileName, CancellationToken.None, branding);
await _htmlExportService.WriteAsync(SimplifiedResults.ToList(), dialog.FileName, CancellationToken.None, branding, groupMembers);
else
await _htmlExportService.WriteAsync(Results, dialog.FileName, CancellationToken.None, branding);
await _htmlExportService.WriteAsync(Results, dialog.FileName, CancellationToken.None, branding, groupMembers);
OpenFile(dialog.FileName);
}
catch (Exception ex)