diff --git a/SharepointToolbox/Services/Export/CsvExportService.cs b/SharepointToolbox/Services/Export/CsvExportService.cs index ee033a2..4f96c44 100644 --- a/SharepointToolbox/Services/Export/CsvExportService.cs +++ b/SharepointToolbox/Services/Export/CsvExportService.cs @@ -58,6 +58,60 @@ public class CsvExportService await File.WriteAllTextAsync(filePath, csv, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true), ct); } + /// + /// Header for simplified CSV export — includes "SimplifiedLabels" and "RiskLevel" columns. + /// + private const string SimplifiedHeader = + "\"Object\",\"Title\",\"URL\",\"HasUniquePermissions\",\"Users\",\"UserLogins\",\"Type\",\"Permissions\",\"SimplifiedLabels\",\"RiskLevel\",\"GrantedThrough\""; + + /// + /// Builds a CSV string from simplified permission entries. + /// Includes SimplifiedLabels and RiskLevel columns after raw Permissions. + /// Uses the same merge logic as the standard BuildCsv. + /// + public string BuildCsv(IReadOnlyList entries) + { + var sb = new StringBuilder(); + sb.AppendLine(SimplifiedHeader); + + var merged = entries + .GroupBy(e => (e.Users, e.PermissionLevels, e.GrantedThrough)) + .Select(g => new + { + ObjectType = g.First().ObjectType, + Title = string.Join(" | ", g.Select(e => e.Title).Distinct()), + Url = string.Join(" | ", g.Select(e => e.Url).Distinct()), + HasUnique = g.First().HasUniquePermissions, + Users = g.Key.Users, + UserLogins = g.First().UserLogins, + PrincipalType = g.First().PrincipalType, + Permissions = g.Key.PermissionLevels, + SimplifiedLabels = g.First().SimplifiedLabels, + RiskLevel = g.First().RiskLevel.ToString(), + GrantedThrough = g.Key.GrantedThrough + }); + + foreach (var row in merged) + sb.AppendLine(string.Join(",", new[] + { + Csv(row.ObjectType), Csv(row.Title), Csv(row.Url), + Csv(row.HasUnique.ToString()), Csv(row.Users), Csv(row.UserLogins), + Csv(row.PrincipalType), Csv(row.Permissions), Csv(row.SimplifiedLabels), + Csv(row.RiskLevel), Csv(row.GrantedThrough) + })); + + return sb.ToString(); + } + + /// + /// Writes simplified CSV to the specified file path. + /// + public async Task WriteAsync(IReadOnlyList entries, string filePath, CancellationToken ct) + { + var csv = BuildCsv(entries); + await File.WriteAllTextAsync(filePath, csv, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true), ct); + } + /// RFC 4180 CSV field escaping: wrap in double quotes, double internal quotes. private static string Csv(string value) {