using System.Text; using Microsoft.AspNetCore.Mvc; using SQLInsight.Contracts; using SQLInsight.Repository; namespace SQLInsight.Web; /// /// Support cases with SEOSoft (Professional/Enterprise). The form posts here; the request is stored in the repository /// and the agent sends it to SQLInsight Hub, which gives it a case number. The web UI never talks to the hub itself. /// public static class Support { public static void Map(IEndpointRouteBuilder app) => app.MapPost("/support", CreateAsync); /// Title and description for a case about . Sensitive measurements are left out. public static (string Title, string Description) Prefill(StoredFinding finding) { ArgumentNullException.ThrowIfNull(finding); var text = new StringBuilder(); text.Append("Instans: ").Append(finding.InstanceName).Append('\n'); text.Append("Regel: ").Append(finding.RuleId).Append('\n'); text.Append("Alvor: ").Append(Display.SeverityName(finding.Severity)).Append('\n'); if (!string.IsNullOrEmpty(finding.Subject)) { text.Append("Emne: ").Append(finding.Subject).Append('\n'); } text.Append('\n').Append(finding.Explanation).Append('\n'); var evidence = finding.Evidence.Where(e => !e.Sensitive).Take(10).ToList(); if (evidence.Count > 0) { text.Append("\nMålinger:\n"); foreach (var e in evidence) { text.Append("- ").Append(e.Name).Append(": ").Append(e.Value.Length > 200 ? e.Value[..200] + "…" : e.Value).Append('\n'); } } text.Append("\nHvad har I prøvet, og hvad har ændret sig?\n"); var title = finding.Title.Length > SupportCaseRequest.MaxTitle ? finding.Title[..SupportCaseRequest.MaxTitle] : finding.Title; var description = text.ToString(); return (title, description.Length > SupportCaseRequest.MaxDescription ? description[..SupportCaseRequest.MaxDescription] : description); } /// The user part of DOMAIN\user, as a starting point for the contact name. public static string ContactNameFrom(string? windowsUser) => windowsUser is { Length: > 0 } user ? user[(user.LastIndexOf('\\') + 1)..] : string.Empty; public static string StatusText(SupportCaseRow row) { ArgumentNullException.ThrowIfNull(row); return row.Status switch { SupportCaseStatus.Pending => row.Attempts > 0 ? "Venter på hubben (prøver igen)" : "Sendes", SupportCaseStatus.Open => "Åben", SupportCaseStatus.Closed => "Lukket", _ => "Afvist", }; } private static async Task CreateAsync( HttpContext http, InsightRepository repository, [FromForm] string? title, [FromForm] string? description, [FromForm] string? contactName, [FromForm] string? contactEmail, [FromForm] string? contactPhone, [FromForm] long? findingId) { var back = findingId is { } id ? $"&fund={id}" : string.Empty; if ((await repository.GetHubStatusAsync(http.RequestAborted))?.AllowsSupportCases != true) { return Results.Redirect("/support?fejl=" + Uri.EscapeDataString("Supportsager kræver Professional eller Enterprise og at deling med SQLInsight Hub er slået til.")); } var finding = findingId is { } fid ? await repository.GetFindingAsync(fid, http.RequestAborted) : null; var request = new SupportCaseRequest(Guid.NewGuid(), title?.Trim() ?? string.Empty, Blank(description), contactName?.Trim() ?? string.Empty, contactEmail?.Trim() ?? string.Empty, Blank(contactPhone), http.User.Identity?.Name, finding?.InstanceName, finding?.RuleId, finding?.Subject); if (request.Validate() is { } invalid) { return Results.Redirect("/support?fejl=" + Uri.EscapeDataString(invalid) + back); } await repository.AddSupportRequestAsync(new NewSupportRequest(request.ClientRequestId, request.Title, request.Description, request.ContactName, request.ContactEmail, request.ContactPhone, request.RequestedBy, finding?.FindingId, finding?.InstanceName, finding?.RuleId, finding?.Subject), DateTimeOffset.UtcNow, http.RequestAborted); return Results.Redirect("/support?sendt=1"); } private static string? Blank(string? value) => string.IsNullOrWhiteSpace(value) ? null : value.Trim(); }