using SharepointToolbox.Core.Models; using System.Text; namespace SharepointToolbox.Services.Export; /// /// Exports DuplicateGroup list to a self-contained HTML with collapsible group cards. /// Port of PS Export-DuplicatesToHTML (PS lines 2235-2406). /// Each group gets a card showing item count badge and a table of paths. /// public class DuplicatesHtmlExportService { public string BuildHtml(IReadOnlyList groups, ReportBranding? branding = null) { var sb = new StringBuilder(); sb.AppendLine(""" SharePoint Duplicate Detection Report """); sb.Append(BrandingHtmlHelper.BuildBrandingHeader(branding)); sb.AppendLine("""

Duplicate Detection Report

"""); sb.AppendLine($"

{groups.Count:N0} duplicate group(s) found.

"); for (int i = 0; i < groups.Count; i++) { var g = groups[i]; int count = g.Items.Count; string badgeClass = "badge-dup"; sb.AppendLine($"""
{H(g.Name)} {count} copies
"""); for (int j = 0; j < g.Items.Count; j++) { var item = g.Items[j]; string size = item.SizeBytes.HasValue ? FormatSize(item.SizeBytes.Value) : string.Empty; string created = item.Created.HasValue ? item.Created.Value.ToString("yyyy-MM-dd") : string.Empty; string modified = item.Modified.HasValue ? item.Modified.Value.ToString("yyyy-MM-dd") : string.Empty; sb.AppendLine($""" """); } sb.AppendLine("""
# Library Path Size Created Modified
{j + 1} {H(item.Library)} {H(item.Path)} {size} {created} {modified}
"""); } sb.AppendLine($"

Generated: {DateTime.Now:yyyy-MM-dd HH:mm}

"); sb.AppendLine(""); return sb.ToString(); } public async Task WriteAsync(IReadOnlyList groups, string filePath, CancellationToken ct, ReportBranding? branding = null) { var html = BuildHtml(groups, branding); await System.IO.File.WriteAllTextAsync(filePath, html, Encoding.UTF8, ct); } private static string H(string value) => System.Net.WebUtility.HtmlEncode(value ?? string.Empty); private static string FormatSize(long bytes) { if (bytes >= 1_073_741_824L) return $"{bytes / 1_073_741_824.0:F2} GB"; if (bytes >= 1_048_576L) return $"{bytes / 1_048_576.0:F2} MB"; if (bytes >= 1024L) return $"{bytes / 1024.0:F2} KB"; return $"{bytes} B"; } }