using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text.RegularExpressions; using Newtonsoft.Json; using StardewModdingAPI.Toolkit.Utilities; using StardewModdingAPI.Web.Framework.LogParsing.Models; namespace StardewModdingAPI.Web.ViewModels { /// The view model for the log parser page. public class LogParserModel { /********* ** Fields *********/ /// A regex pattern matching characters to remove from a mod name to create the slug ID. private readonly Regex SlugInvalidCharPattern = new("[^a-z0-9]", RegexOptions.Compiled | RegexOptions.IgnoreCase); /********* ** Accessors *********/ /// The paste ID. public string? PasteID { get; } /// The viewer's detected OS, if known. public Platform? DetectedPlatform { get; } /// The parsed log info. public ParsedLog? ParsedLog { get; private set; } /// Whether to show the raw unparsed log. public bool ShowRaw { get; private set; } /// A non-blocking warning while uploading the log. public string? UploadWarning { get; set; } /// An error which occurred while uploading the log. public string? UploadError { get; set; } /// An error which occurred while parsing the log file. public string? ParseError => this.ParsedLog?.Error; /// When the uploaded file will no longer be available. public DateTimeOffset? Expiry { get; set; } /// Whether parsed log data is available. [MemberNotNullWhen(true, nameof(LogParserModel.PasteID), nameof(LogParserModel.ParsedLog))] public bool HasLog => this.ParsedLog != null; /********* ** Public methods *********/ /// Construct an instance. /// The paste ID. /// The viewer's detected OS, if known. public LogParserModel(string? pasteID, Platform? platform) { this.PasteID = pasteID; this.DetectedPlatform = platform; this.ParsedLog = null; this.ShowRaw = false; } /// Construct an instance. /// The paste ID. /// The viewer's detected OS, if known. /// The parsed log info. /// Whether to show the raw unparsed log. /// A non-blocking warning while uploading the log. /// An error which occurred while uploading the log. /// When the uploaded file will no longer be available. [JsonConstructor] public LogParserModel(string pasteId, Platform? detectedPlatform, ParsedLog? parsedLog, bool showRaw, string? uploadWarning, string? uploadError, DateTime? expiry) { this.PasteID = pasteId; this.DetectedPlatform = detectedPlatform; this.ParsedLog = parsedLog; this.ShowRaw = showRaw; this.UploadWarning = uploadWarning; this.UploadError = uploadError; this.Expiry = expiry; } /// Set the log parser result. /// The parsed log info. /// Whether to show the raw unparsed log. public LogParserModel SetResult(ParsedLog parsedLog, bool showRaw) { this.ParsedLog = parsedLog; this.ShowRaw = showRaw; return this; } /// Get all content packs in the log grouped by the mod they're for. public IDictionary GetContentPacksByMod() { // get all mods & content packs LogModInfo[]? mods = this.ParsedLog?.Mods; if (mods == null || !mods.Any()) return new Dictionary(); // group by mod return mods .Where(mod => mod.IsContentPack) .GroupBy(mod => mod.ContentPackFor!) .ToDictionary(group => group.Key, group => group.ToArray()); } /// Get a sanitized mod name that's safe to use in anchors, attributes, and URLs. /// The mod name. public string GetSlug(string modName) { return this.SlugInvalidCharPattern.Replace(modName, ""); } } }