Refactor document name sanitization for consistent filename generation

- Introduced FdsDocumentNames class to centralize the logic for sanitizing document names used in downloads.
- Updated FdsMfr to utilize the new SafeFileName method for generating safe filenames.
- Enhanced documentation for FdsDocumentNames and its methods to clarify usage and purpose.
- Added global.json file to configure testing framework settings.
This commit is contained in:
Stefan
2026-09-16 22:18:42 +02:00
parent a60d4c2eaf
commit 944a5bb442
18 changed files with 245 additions and 34 deletions
+6 -3
View File
@@ -205,9 +205,12 @@ public class FdsMfr : IFdsMfr
if (fl != null)
{
file = fl;
string safeName = fln.Replace("<p>", "").Replace("</p>", "").Replace("=", "_")
.Replace(">", "_").Replace("|", "_").Replace("!", "_").Replace("<", "_").Replace("/", "_");
return new FileInfo(Path.GetTempPath() + safeName);
// Same sanitiser as the regenerate-on-miss path (ADR 0025) so a stored and a
// regenerated document with the same DocumentName download under the same name.
// Fallback to the report id: an empty DocumentName used to yield the temp-dir
// segment ("Temp") as the download name.
string safeName = FdsDocumentNames.SafeFileName(fln, reportid);
return new FileInfo(Path.Combine(Path.GetTempPath(), safeName));
}
}
return null;
+27
View File
@@ -40,6 +40,33 @@ public static class FdsConfig
Current["Fds:MFR_host"] ?? "";
}
/// <summary>
/// Download-filename sanitising shared by every path that hands a document to the browser —
/// stored documents (<see cref="FdsMfr.GetReportDoc"/>) and documents regenerated on a miss
/// (<c>IntranetController.HandleReportDoc</c>, ADR 0025) — so both produce the same name for the
/// same DocumentName. DocumentName is derived from the user-typed invoice title, so it can carry
/// path separators ("Wartung 2025/26"), stray editor markup and characters Windows rejects.
/// </summary>
public static class FdsDocumentNames
{
// '=' and '!' are legal filename characters, but the stored-document path replaced them
// long before the regenerate path existed; kept so unifying the two never loosens either.
private static readonly char[] Replaced =
[.. Path.GetInvalidFileNameChars(), '=', '!'];
/// <param name="documentName">Raw DocumentName (may be null, empty, or wrapped in &lt;p&gt;).</param>
/// <param name="fallback">Used when nothing usable remains after cleanup.</param>
public static string SafeFileName(string? documentName, string fallback)
{
string name = (documentName ?? "").Replace("<p>", "").Replace("</p>", "").Trim();
if (name.Length == 0) return fallback;
foreach (char c in Replaced)
name = name.Replace(c, '_');
name = name.Trim();
return name.Length == 0 ? fallback : name;
}
}
internal static class FdsShared
{
internal static string FDSConnectionString() => FdsConfig.FDSConnectionString();
+13
View File
@@ -37,5 +37,18 @@
which <c>Program.cs</c> calls once at startup before any <see cref="T:fds.FdsMfr"/> use.
</summary>
</member>
<member name="T:fds.FdsDocumentNames">
<summary>
Download-filename sanitising shared by every path that hands a document to the browser —
stored documents (<see cref="M:fds.FdsMfr.GetReportDoc(System.Byte[]@,System.String,System.Boolean)"/>) and documents regenerated on a miss
(<c>IntranetController.HandleReportDoc</c>, ADR 0025) — so both produce the same name for the
same DocumentName. DocumentName is derived from the user-typed invoice title, so it can carry
path separators ("Wartung 2025/26"), stray editor markup and characters Windows rejects.
</summary>
</member>
<member name="M:fds.FdsDocumentNames.SafeFileName(System.String,System.String)">
<param name="documentName">Raw DocumentName (may be null, empty, or wrapped in &lt;p&gt;).</param>
<param name="fallback">Used when nothing usable remains after cleanup.</param>
</member>
</members>
</doc>