chore: release v2.4
- Add theme system (Dark/Light palettes, ModernTheme, ThemeManager) - Add InputDialog, Spinner common view - Add DuplicatesCsvExportService - Refresh views, dialogs, and view models across tabs - Update localization strings (en/fr) - Tweak services (transfer, permissions, search, user access, ownership elevation, bulk operations) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,20 +2,40 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using CsvHelper;
|
||||
using CsvHelper.Configuration;
|
||||
using SharepointToolbox.Core.Models;
|
||||
using SharepointToolbox.Localization;
|
||||
|
||||
namespace SharepointToolbox.Services.Export;
|
||||
|
||||
/// <summary>
|
||||
/// Exports the failed subset of a <see cref="BulkOperationSummary{T}"/> run
|
||||
/// to CSV. CsvHelper is used so the <typeparamref name="T"/> payload's
|
||||
/// properties become columns automatically, plus one error-message and one
|
||||
/// timestamp column appended at the end.
|
||||
/// </summary>
|
||||
public class BulkResultCsvExportService
|
||||
{
|
||||
private static readonly CsvConfiguration CsvConfig = new(CultureInfo.InvariantCulture)
|
||||
{
|
||||
// Prevent CSV formula injection: prefix =, +, -, @, tab, CR with single quote
|
||||
InjectionOptions = InjectionOptions.Escape,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Builds a CSV containing only items whose <see cref="BulkItemResult{T}.IsSuccess"/>
|
||||
/// is <c>false</c>. Columns: every public property of <typeparamref name="T"/>
|
||||
/// followed by Error and Timestamp (ISO-8601).
|
||||
/// </summary>
|
||||
public string BuildFailedItemsCsv<T>(IReadOnlyList<BulkItemResult<T>> failedItems)
|
||||
{
|
||||
var TL = TranslationSource.Instance;
|
||||
using var writer = new StringWriter();
|
||||
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
|
||||
using var csv = new CsvWriter(writer, CsvConfig);
|
||||
|
||||
csv.WriteHeader<T>();
|
||||
csv.WriteField("Error");
|
||||
csv.WriteField("Timestamp");
|
||||
csv.WriteField(TL["report.col.error"]);
|
||||
csv.WriteField(TL["report.col.timestamp"]);
|
||||
csv.NextRecord();
|
||||
|
||||
foreach (var item in failedItems.Where(r => !r.IsSuccess))
|
||||
@@ -29,12 +49,13 @@ public class BulkResultCsvExportService
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Writes the failed-items CSV to <paramref name="filePath"/> with UTF-8 BOM.</summary>
|
||||
public async Task WriteFailedItemsCsvAsync<T>(
|
||||
IReadOnlyList<BulkItemResult<T>> failedItems,
|
||||
string filePath,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var content = BuildFailedItemsCsv(failedItems);
|
||||
await System.IO.File.WriteAllTextAsync(filePath, content, new UTF8Encoding(true), ct);
|
||||
await ExportFileWriter.WriteCsvAsync(filePath, content, ct);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user