Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ csharp_style_namespace_declarations = file_scoped:warning
# CA2007 (missing ConfigureAwait) is not actionable here — suppress app-wide.
dotnet_diagnostic.CA2007.severity = none

# CA1716 is a cross-language (VB/C# interop) naming rule with no value for this C#-only app:
# interface members Get/Stop/Operator and parameters set/to are idiomatic here, and the
# LageBuch.App.Shared namespace root cannot be sanely renamed. Suppress app-wide.
dotnet_diagnostic.CA1716.severity = none

[tests/**/*.cs]
# xUnit method names with underscores are idiomatic.
dotnet_diagnostic.CA1707.severity = none
Expand Down
2 changes: 2 additions & 0 deletions src/LageBuch.App.Shared/App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
using Avalonia.Markup.Xaml;
using LageBuch.App.Shared.Views;
using LageBuch.AppLogic.ViewModels;
using System.Diagnostics.CodeAnalysis;

namespace LageBuch.App.Shared;

[SuppressMessage("Naming", "CA1724", Justification = "The Avalonia App class sits in the LageBuch.App.Shared namespace by design; the collision with the LageBuch.App namespace is inherent to the app's name.")]
public partial class App : Application
{
/// <summary>
Expand Down
10 changes: 5 additions & 5 deletions src/LageBuch.App/AppPaths.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ namespace LageBuch.App;

internal static class AppPaths
{
public static string AppDataDir =>
public static string Root =>
GetAppDataDir(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));

public static string MasterDataDbPath => Path.Combine(AppDataDir, "masterdata.db");
public static string MasterDataDbPath => Path.Combine(Root, "masterdata.db");

public static string RecentFilesJsonPath => Path.Combine(AppDataDir, "recent.json");
public static string RecentFilesJsonPath => Path.Combine(Root, "recent.json");

public static string LastSaveFolderJsonPath => Path.Combine(AppDataDir, "last-save-folder.json");
public static string LastSaveFolderJsonPath => Path.Combine(Root, "last-save-folder.json");

public static string AttachmentCacheDir => Path.Combine(AppDataDir, "attachment-cache");
public static string AttachmentCacheDir => Path.Combine(Root, "attachment-cache");

public static string GetAppDataDir(string baseDir)
{
Expand Down
3 changes: 3 additions & 0 deletions src/LageBuch.AppLogic/Services/IFileDialogService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Diagnostics.CodeAnalysis;

namespace LageBuch.AppLogic.Services;

public interface IFileDialogService
Expand Down Expand Up @@ -25,6 +27,7 @@ public interface IFileDialogService
Task OpenFileAsync(string path);

/// <summary>Opens an http(s) URL in the OS's default browser.</summary>
[SuppressMessage("Design", "CA1054", Justification = "URLs are free-form launch strings end-to-end (persisted master data, test data); System.Uri would reject non-parseable values and force churn in every caller.")]
Task OpenUrlAsync(string url);

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions src/LageBuch.AppLogic/ViewModels/AboutViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public AboutViewModel(IFileDialogService dialogs, string version)
[SuppressMessage("Performance", "CA1822", Justification = "XAML {Binding} target in AboutView; binding requires an instance property.")]
public string Descriptor => "Einsatzdokumentation";
public string Version { get; }
[SuppressMessage("Design", "CA1056", Justification = "RepositoryUrl is a display/launch string handed to IFileDialogService.OpenUrlAsync; System.Uri would add parse/validation behavior with no benefit here.")]
[SuppressMessage("Performance", "CA1822", Justification = "XAML {Binding} target in AboutView; binding requires an instance property.")]
public string RepositoryUrl => RepoUrl;

Expand Down
2 changes: 2 additions & 0 deletions src/LageBuch.AppLogic/ViewModels/LinkRow.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System.Diagnostics.CodeAnalysis;

namespace LageBuch.AppLogic.ViewModels;

Expand All @@ -7,6 +8,7 @@ public sealed partial class LinkRow : ObservableObject
{
private readonly Action _onChanged;

[SuppressMessage("Design", "CA1054", Justification = "URLs are free-form display strings in the domain; System.Uri would reject non-parseable values like relay links.")]
public LinkRow(string name, string url, Action onChanged)
{
_onChanged = onChanged;
Expand Down
4 changes: 2 additions & 2 deletions src/LageBuch.Documents/IncidentReportDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ public IncidentReportDocument(Incident incident, IReadOnlyDictionary<Guid, byte[

public DocumentMetadata GetMetadata() => DocumentMetadata.Default;

public void Compose(IDocumentContainer document)
public void Compose(IDocumentContainer container)
{
PdfLicense.Ensure();

document.Page(page =>
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(1.5f, Unit.Centimetre);
Expand Down
3 changes: 3 additions & 0 deletions src/LageBuch.Persistence/MasterData/MasterDataSet.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Encodings.Web;
using System.Text.Json;
using LageBuch.Domain.Atemschutz;
Expand All @@ -7,6 +8,8 @@ namespace LageBuch.Persistence.MasterData;
public sealed record Street(string Name, string District);

/// <summary>A named link — Stammdaten entry so useful external resources can be opened from an Einsatz.</summary>
[SuppressMessage("Design", "CA1054", Justification = "Link URLs are free-form display data in persisted master data; System.Uri would make non-parseable values (relay or relative links) fail to load.")]
[SuppressMessage("Design", "CA1056", Justification = "Link URLs are free-form display data in persisted master data; System.Uri would make non-parseable values (relay or relative links) fail to load.")]
public sealed record Link(string Name, string Url);

/// <summary>One Checkliste template entry — the Stammdaten-editable source an incident's Aufbau/Abbau
Expand Down
2 changes: 2 additions & 0 deletions src/LageBuch.Sync/IIncidentSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using LageBuch.Domain.Etb;
using LageBuch.Domain.Tasks;
using LageBuch.Domain.ValueObjects;
using System.Diagnostics.CodeAnalysis;

namespace LageBuch.Sync;

Expand Down Expand Up @@ -35,6 +36,7 @@ public interface IIncidentSession
bool IsRemote { get; }

/// <summary>Raised after the incident state changes (a local mutation, or a host broadcast).</summary>
[SuppressMessage("Design", "CA1003", Justification = "In-process fire-and-forget event with C#-only subscribers; Action matches the pervasive Action event convention (GoHomeRequested etc.).")]
event Action? Changed;

void AddJournalEntry(EtbDirection direction, string text, string? from = null, string? to = null);
Expand Down
5 changes: 5 additions & 0 deletions src/LageBuch.Sync/RemoteIncidentSession.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Net;
using System.Text;
using System.Text.Json.Serialization;
using System.Diagnostics.CodeAnalysis;
using LageBuch.Domain;
using LageBuch.Domain.Atemschutz;
using LageBuch.Domain.CoMeasurement;
Expand Down Expand Up @@ -39,22 +40,26 @@ public sealed class RemoteIncidentSession : IIncidentSession, IAsyncDisposable
public bool IsRemote => true;

/// <summary>Raised after the cached incident is replaced by a host broadcast (or a resync).</summary>
[SuppressMessage("Design", "CA1003", Justification = "In-process fire-and-forget event with C#-only subscribers; see IIncidentSession.Changed.")]
public event Action? Changed;

/// <summary>
/// Raised when the connection drops but automatic reconnect is still trying — the UI should
/// disable input and show "Verbindung getrennt — verbinde neu…". A successful retry raises
/// <see cref="Reconnected"/>; giving up raises <see cref="Ended"/>.
/// </summary>
[SuppressMessage("Design", "CA1003", Justification = "In-process fire-and-forget event with C#-only subscribers; see IIncidentSession.Changed.")]
public event Action? Disconnected;

/// <summary>Raised after a reconnect + full resync — the UI can re-enable input.</summary>
[SuppressMessage("Design", "CA1003", Justification = "In-process fire-and-forget event with C#-only subscribers; see IIncidentSession.Changed.")]
public event Action? Reconnected;

/// <summary>
/// Raised when the connection is gone for good — reconnect attempts were exhausted or the host
/// stopped sharing. The UI returns to Home (§7); nothing further arrives on this session.
/// </summary>
[SuppressMessage("Design", "CA1003", Justification = "In-process fire-and-forget event with C#-only subscribers; see IIncidentSession.Changed.")]
public event Action? Ended;

private RemoteIncidentSession(HttpClient http, HubConnection hub, IUiDispatcher ui, SessionOperator op, Incident initial, string? cacheRoot)
Expand Down
2 changes: 2 additions & 0 deletions tests/LageBuch.AppLogic.Tests/LinksViewModelTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using LageBuch.AppLogic.Services;
using LageBuch.AppLogic.ViewModels;
using LageBuch.Persistence.MasterData;
using System.Diagnostics.CodeAnalysis;

namespace LageBuch.AppLogic.Tests;

Expand Down Expand Up @@ -52,6 +53,7 @@ public async Task OpenAsync_prepends_https_to_a_bare_domain()
[InlineData("file:///etc/passwd")]
[InlineData("javascript:alert(1)")]
[InlineData("ftp://example.org")]
[SuppressMessage("Design", "CA1054", Justification = "Test exercises links with free-form (even hostile) URL strings — that is the point of the test.")]
public async Task OpenAsync_refuses_a_non_http_scheme(string url)
{
var dialogs = new FakeDialogs();
Expand Down
Loading