From 5d5e137e18249739afb8a0acf6c1660ce65d989c Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Wed, 8 Nov 2023 20:43:18 -0600 Subject: [PATCH 01/10] Add flag to mark save path as regex --- LANCommander.SDK/Models/GameManifest.cs | 1 + LANCommander.SDK/Models/SavePath.cs | 1 + LANCommander/Data/Models/SavePath.cs | 1 + ...6061719_AddRegexFlagToSavePath.Designer.cs | 1694 +++++++++++++++++ .../20231106061719_AddRegexFlagToSavePath.cs | 29 + .../DatabaseContextModelSnapshot.cs | 3 + .../Games/Components/SavePathEditor.razor | 3 + LANCommander/Services/GameService.cs | 1 + 8 files changed, 1733 insertions(+) create mode 100644 LANCommander/Migrations/20231106061719_AddRegexFlagToSavePath.Designer.cs create mode 100644 LANCommander/Migrations/20231106061719_AddRegexFlagToSavePath.cs diff --git a/LANCommander.SDK/Models/GameManifest.cs b/LANCommander.SDK/Models/GameManifest.cs index 21920d6..af24437 100644 --- a/LANCommander.SDK/Models/GameManifest.cs +++ b/LANCommander.SDK/Models/GameManifest.cs @@ -46,5 +46,6 @@ namespace LANCommander.SDK public Guid Id { get; set; } public string Type { get; set; } public string Path { get; set; } + public bool IsRegex { get; set; } } } diff --git a/LANCommander.SDK/Models/SavePath.cs b/LANCommander.SDK/Models/SavePath.cs index bb34a6a..d24c1c9 100644 --- a/LANCommander.SDK/Models/SavePath.cs +++ b/LANCommander.SDK/Models/SavePath.cs @@ -9,6 +9,7 @@ namespace LANCommander.SDK.Models { public SavePathType Type { get; set; } public string Path { get; set; } + public bool IsRegex { get; set; } public virtual Game Game { get; set; } } } diff --git a/LANCommander/Data/Models/SavePath.cs b/LANCommander/Data/Models/SavePath.cs index 8a77163..b3617e4 100644 --- a/LANCommander/Data/Models/SavePath.cs +++ b/LANCommander/Data/Models/SavePath.cs @@ -10,6 +10,7 @@ namespace LANCommander.Data.Models { public SavePathType Type { get; set; } public string Path { get; set; } + public bool IsRegex { get; set; } public Guid? GameId { get; set; } [JsonIgnore] diff --git a/LANCommander/Migrations/20231106061719_AddRegexFlagToSavePath.Designer.cs b/LANCommander/Migrations/20231106061719_AddRegexFlagToSavePath.Designer.cs new file mode 100644 index 0000000..d9e2a3a --- /dev/null +++ b/LANCommander/Migrations/20231106061719_AddRegexFlagToSavePath.Designer.cs @@ -0,0 +1,1694 @@ +// +using System; +using LANCommander.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace LANCommander.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20231106061719_AddRegexFlagToSavePath")] + partial class AddRegexFlagToSavePath + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.13") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true); + + modelBuilder.Entity("CategoryGame", b => + { + b.Property("CategoriesId") + .HasColumnType("TEXT"); + + b.Property("GamesId") + .HasColumnType("TEXT"); + + b.HasKey("CategoriesId", "GamesId"); + + b.HasIndex("GamesId"); + + b.ToTable("CategoryGame"); + }); + + modelBuilder.Entity("GameDeveloper", b => + { + b.Property("DeveloperId") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.HasKey("DeveloperId", "GameId"); + + b.HasIndex("GameId"); + + b.ToTable("GameDeveloper"); + }); + + modelBuilder.Entity("GameGenre", b => + { + b.Property("GamesId") + .HasColumnType("TEXT"); + + b.Property("GenresId") + .HasColumnType("TEXT"); + + b.HasKey("GamesId", "GenresId"); + + b.HasIndex("GenresId"); + + b.ToTable("GameGenre"); + }); + + modelBuilder.Entity("GamePublisher", b => + { + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("PublisherId") + .HasColumnType("TEXT"); + + b.HasKey("GameId", "PublisherId"); + + b.HasIndex("PublisherId"); + + b.ToTable("GamePublisher"); + }); + + modelBuilder.Entity("GameRedistributable", b => + { + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("RedistributableId") + .HasColumnType("TEXT"); + + b.HasKey("GameId", "RedistributableId"); + + b.HasIndex("RedistributableId"); + + b.ToTable("GameRedistributable"); + }); + + modelBuilder.Entity("GameTag", b => + { + b.Property("GamesId") + .HasColumnType("TEXT"); + + b.Property("TagsId") + .HasColumnType("TEXT"); + + b.HasKey("GamesId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("GameTag"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Action", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Arguments") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.Property("PrimaryAction") + .HasColumnType("INTEGER"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("WorkingDirectory") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Actions"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Archive", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Changelog") + .HasColumnType("TEXT"); + + b.Property("CompressedSize") + .HasColumnType("INTEGER"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("LastVersionId") + .HasColumnType("TEXT"); + + b.Property("ObjectKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RedistributableId") + .HasColumnType("TEXT"); + + b.Property("UncompressedSize") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("Version") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("LastVersionId"); + + b.HasIndex("RedistributableId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Archive"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ParentId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Company", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Companies"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Game", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("DirectoryName") + .HasColumnType("TEXT"); + + b.Property("IGDBId") + .HasColumnType("INTEGER"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("ReleasedOn") + .HasColumnType("TEXT"); + + b.Property("Singleplayer") + .HasColumnType("INTEGER"); + + b.Property("SortTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("ValidKeyRegex") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Games"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.GameSave", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.HasIndex("UserId"); + + b.ToTable("GameSaves"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Genres"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Key", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AllocationMethod") + .HasColumnType("INTEGER"); + + b.Property("ClaimedByComputerName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("ClaimedByIpv4Address") + .HasMaxLength(15) + .HasColumnType("TEXT"); + + b.Property("ClaimedByMacAddress") + .HasMaxLength(17) + .HasColumnType("TEXT"); + + b.Property("ClaimedByUserId") + .HasColumnType("TEXT"); + + b.Property("ClaimedOn") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ClaimedByUserId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Keys"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Media", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("FileId") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SourceUrl") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Media"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.MultiplayerMode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("GameId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("MaxPlayers") + .HasColumnType("INTEGER"); + + b.Property("MinPlayers") + .HasColumnType("INTEGER"); + + b.Property("NetworkProtocol") + .HasColumnType("INTEGER"); + + b.Property("Spectators") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("MultiplayerModes"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Redistributables"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("LANCommander.Data.Models.SavePath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("IsRegex") + .HasColumnType("INTEGER"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("SavePaths"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Script", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Contents") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RedistributableId") + .HasColumnType("TEXT"); + + b.Property("RequiresAdmin") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("RedistributableId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Scripts"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Server", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Arguments") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Autostart") + .HasColumnType("INTEGER"); + + b.Property("AutostartDelay") + .HasColumnType("INTEGER"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("GameId") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OnStartScriptPath") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("OnStopScriptPath") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.Property("UseShellExecute") + .HasColumnType("INTEGER"); + + b.Property("WorkingDirectory") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("GameId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Servers"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.ServerConsole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ServerId") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ServerId1") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ServerId"); + + b.HasIndex("ServerId1"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ServerConsoles"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.ServerHttpPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("LocalPath") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ServerId") + .HasColumnType("TEXT"); + + b.Property("ServerId1") + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ServerId"); + + b.HasIndex("ServerId1"); + + b.HasIndex("UpdatedById"); + + b.ToTable("ServerHttpPath"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UpdatedById") + .HasColumnType("TEXT"); + + b.Property("UpdatedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("Alias") + .HasColumnType("TEXT"); + + b.Property("Approved") + .HasColumnType("INTEGER"); + + b.Property("ApprovedOn") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RefreshToken") + .HasColumnType("TEXT"); + + b.Property("RefreshTokenExpiration") + .HasColumnType("TEXT"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("CategoryGame", b => + { + b.HasOne("LANCommander.Data.Models.Category", null) + .WithMany() + .HasForeignKey("CategoriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GamesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GameDeveloper", b => + { + b.HasOne("LANCommander.Data.Models.Company", null) + .WithMany() + .HasForeignKey("DeveloperId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GameGenre", b => + { + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GamesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GamePublisher", b => + { + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Company", null) + .WithMany() + .HasForeignKey("PublisherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GameRedistributable", b => + { + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Redistributable", null) + .WithMany() + .HasForeignKey("RedistributableId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GameTag", b => + { + b.HasOne("LANCommander.Data.Models.Game", null) + .WithMany() + .HasForeignKey("GamesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Action", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Actions") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Archive", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Archives") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LANCommander.Data.Models.Archive", "LastVersion") + .WithMany() + .HasForeignKey("LastVersionId"); + + b.HasOne("LANCommander.Data.Models.Redistributable", "Redistributable") + .WithMany("Archives") + .HasForeignKey("RedistributableId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("LastVersion"); + + b.Navigation("Redistributable"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Category", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Category", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Parent"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Company", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Game", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.GameSave", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("GameSaves") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.HasOne("LANCommander.Data.Models.User", "User") + .WithMany("GameSaves") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Genre", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Key", b => + { + b.HasOne("LANCommander.Data.Models.User", "ClaimedByUser") + .WithMany() + .HasForeignKey("ClaimedByUserId"); + + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Keys") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("ClaimedByUser"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Media", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Media") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.MultiplayerMode", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("MultiplayerModes") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.SavePath", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("SavePaths") + .HasForeignKey("GameId"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Script", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Scripts") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LANCommander.Data.Models.Redistributable", "Redistributable") + .WithMany("Scripts") + .HasForeignKey("RedistributableId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("Redistributable"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Server", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Game", "Game") + .WithMany("Servers") + .HasForeignKey("GameId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Game"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.ServerConsole", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Server", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Server", null) + .WithMany("ServerConsoles") + .HasForeignKey("ServerId1"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Server"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.ServerHttpPath", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.Server", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.Server", null) + .WithMany("HttpPaths") + .HasForeignKey("ServerId1"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Server"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Tag", b => + { + b.HasOne("LANCommander.Data.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("LANCommander.Data.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("LANCommander.Data.Models.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("LANCommander.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("LANCommander.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("LANCommander.Data.Models.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LANCommander.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("LANCommander.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Category", b => + { + b.Navigation("Children"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Game", b => + { + b.Navigation("Actions"); + + b.Navigation("Archives"); + + b.Navigation("GameSaves"); + + b.Navigation("Keys"); + + b.Navigation("Media"); + + b.Navigation("MultiplayerModes"); + + b.Navigation("SavePaths"); + + b.Navigation("Scripts"); + + b.Navigation("Servers"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b => + { + b.Navigation("Archives"); + + b.Navigation("Scripts"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.Server", b => + { + b.Navigation("HttpPaths"); + + b.Navigation("ServerConsoles"); + }); + + modelBuilder.Entity("LANCommander.Data.Models.User", b => + { + b.Navigation("GameSaves"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/LANCommander/Migrations/20231106061719_AddRegexFlagToSavePath.cs b/LANCommander/Migrations/20231106061719_AddRegexFlagToSavePath.cs new file mode 100644 index 0000000..ddf18e4 --- /dev/null +++ b/LANCommander/Migrations/20231106061719_AddRegexFlagToSavePath.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LANCommander.Migrations +{ + /// + public partial class AddRegexFlagToSavePath : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsRegex", + table: "SavePaths", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsRegex", + table: "SavePaths"); + } + } +} diff --git a/LANCommander/Migrations/DatabaseContextModelSnapshot.cs b/LANCommander/Migrations/DatabaseContextModelSnapshot.cs index 3b2a150..566001b 100644 --- a/LANCommander/Migrations/DatabaseContextModelSnapshot.cs +++ b/LANCommander/Migrations/DatabaseContextModelSnapshot.cs @@ -649,6 +649,9 @@ namespace LANCommander.Migrations b.Property("GameId") .HasColumnType("TEXT"); + b.Property("IsRegex") + .HasColumnType("INTEGER"); + b.Property("Path") .IsRequired() .HasColumnType("TEXT"); diff --git a/LANCommander/Pages/Games/Components/SavePathEditor.razor b/LANCommander/Pages/Games/Components/SavePathEditor.razor index 604b8dd..aa5e336 100644 --- a/LANCommander/Pages/Games/Components/SavePathEditor.razor +++ b/LANCommander/Pages/Games/Components/SavePathEditor.razor @@ -17,6 +17,9 @@ } + + + diff --git a/LANCommander/Services/GameService.cs b/LANCommander/Services/GameService.cs index 179ec5a..51d8e9a 100644 --- a/LANCommander/Services/GameService.cs +++ b/LANCommander/Services/GameService.cs @@ -113,6 +113,7 @@ namespace LANCommander.Services { Id = p.Id, Path = p.Path, + IsRegex = p.IsRegex, Type = p.Type.ToString() }); } From ce80dfa51f7747d64c0c0a7ffa43e8478ea9557d Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 30 Nov 2023 17:31:11 -0600 Subject: [PATCH 02/10] Fix pathing for save in download --- LANCommander/Services/GameSaveService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LANCommander/Services/GameSaveService.cs b/LANCommander/Services/GameSaveService.cs index 65e6a57..9fd9465 100644 --- a/LANCommander/Services/GameSaveService.cs +++ b/LANCommander/Services/GameSaveService.cs @@ -44,7 +44,7 @@ namespace LANCommander.Services public string GetSavePath(GameSave save) { - return Path.Combine(Settings.UserSaves.StoragePath, save.UserId.ToString(), $"{save.Id}.zip"); + return Path.Combine(Settings.UserSaves.StoragePath, save.UserId.ToString(), $"{save.Id}"); } } } From eb73885991fa1ca02518e5ddc0ca34ff200c9a74 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 30 Nov 2023 17:31:40 -0600 Subject: [PATCH 03/10] Add unknown to save file download if game doesn't exist. Add .zip file extension --- LANCommander/Controllers/SavesController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LANCommander/Controllers/SavesController.cs b/LANCommander/Controllers/SavesController.cs index 1b0780e..e4317df 100644 --- a/LANCommander/Controllers/SavesController.cs +++ b/LANCommander/Controllers/SavesController.cs @@ -30,7 +30,7 @@ namespace LANCommander.Controllers if (!System.IO.File.Exists(filename)) return NotFound(); - return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/zip", $"{save.User?.UserName} - {save.Game?.Title} - {save.CreatedOn.ToString("MM-dd-yyyy.hh-mm")}"); + return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/zip", $"{save.User?.UserName} - {(save.Game == null ? "Unknown" : save.Game?.Title)} - {save.CreatedOn.ToString("MM-dd-yyyy.hh-mm")}.zip"); } } } From 7c22aaa139e3ca407a62085dbfbdfb85bc554fb9 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 30 Nov 2023 18:25:37 -0600 Subject: [PATCH 04/10] Record save file paths in manifest. Support regex pathing in upload --- LANCommander.SDK/GameSaveManager.cs | 56 ++++++++++++++-------- LANCommander.SDK/Helpers/ManifestHelper.cs | 21 +++++--- LANCommander.SDK/Models/GameManifest.cs | 7 +++ 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/LANCommander.SDK/GameSaveManager.cs b/LANCommander.SDK/GameSaveManager.cs index caf53de..e229401 100644 --- a/LANCommander.SDK/GameSaveManager.cs +++ b/LANCommander.SDK/GameSaveManager.cs @@ -13,6 +13,7 @@ using System.IO; using System.Linq; using System.Net; using System.Text; +using System.Text.RegularExpressions; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; @@ -163,31 +164,42 @@ namespace LANCommander.SDK #region Add files from defined paths foreach (var savePath in manifest.SavePaths.Where(sp => sp.Type == "File")) { - var localPath = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', '\\').Replace("{InstallDir}", installDirectory)); + IEnumerable localPaths; - if (Directory.Exists(localPath)) + if (savePath.IsRegex) { - AddDirectoryToZip(archive, localPath, localPath, savePath.Id); + var regex = new Regex(Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', '\\').Replace("{InstallDir}", installDirectory))); + + localPaths = Directory.GetFiles(installDirectory, "*", SearchOption.AllDirectories) + .Where(p => regex.IsMatch(p)) + .ToList(); } - else if (File.Exists(localPath)) - { - archive.AddEntry(Path.Combine(savePath.Id.ToString(), savePath.Path.Replace("{InstallDir}/", "")), localPath); - } - } - #endregion + else + localPaths = new string[] { savePath.Path }; - #region Add files from defined paths - foreach (var savePath in manifest.SavePaths.Where(sp => sp.Type == "File")) - { - var localPath = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', '\\').Replace("{InstallDir}", installDirectory)); + var entries = new List(); - if (Directory.Exists(localPath)) + foreach (var localPath in localPaths) { - AddDirectoryToZip(archive, localPath, localPath, savePath.Id); - } - else if (File.Exists(localPath)) - { - archive.AddEntry(Path.Combine(savePath.Id.ToString(), savePath.Path.Replace("{InstallDir}/", "")), localPath); + var actualPath = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory)); + var relativePath = actualPath.Replace(installDirectory + Path.DirectorySeparatorChar, ""); + + if (Directory.Exists(actualPath)) + { + AddDirectoryToZip(archive, relativePath, actualPath, savePath.Id); + } + else if (File.Exists(actualPath)) + { + archive.AddEntry(Path.Combine(savePath.Id.ToString(), relativePath), actualPath); + } + + entries.Add(new SavePathEntry + { + ArchivePath = relativePath, + ActualPath = actualPath.Replace(installDirectory, "{InstallDir}") + }); + + savePath.Entries = entries; } } #endregion @@ -225,7 +237,11 @@ namespace LANCommander.SDK } #endregion - archive.AddEntry("_manifest.yml", ManifestHelper.GetPath(installDirectory)); + var tempManifest = Path.GetTempFileName(); + + File.WriteAllText(tempManifest, ManifestHelper.Serialize(manifest)); + + archive.AddEntry("_manifest.yml", tempManifest); using (var ms = new MemoryStream()) { diff --git a/LANCommander.SDK/Helpers/ManifestHelper.cs b/LANCommander.SDK/Helpers/ManifestHelper.cs index 34816b4..0875d64 100644 --- a/LANCommander.SDK/Helpers/ManifestHelper.cs +++ b/LANCommander.SDK/Helpers/ManifestHelper.cs @@ -43,13 +43,7 @@ namespace LANCommander.SDK.Helpers Logger?.LogTrace("Attempting to write manifest to path {Destination}", destination); - var serializer = new SerializerBuilder() - .WithNamingConvention(new PascalCaseNamingConvention()) - .Build(); - - Logger?.LogTrace("Serializing manifest"); - - var yaml = serializer.Serialize(manifest); + var yaml = Serialize(manifest); Logger?.LogTrace("Writing manifest file"); @@ -58,6 +52,19 @@ namespace LANCommander.SDK.Helpers return destination; } + public static string Serialize(GameManifest manifest) + { + var serializer = new SerializerBuilder() + .WithNamingConvention(new PascalCaseNamingConvention()) + .Build(); + + Logger?.LogTrace("Serializing manifest"); + + var yaml = serializer.Serialize(manifest); + + return yaml; + } + public static string GetPath(string installDirectory) { return Path.Combine(installDirectory, ManifestFilename); diff --git a/LANCommander.SDK/Models/GameManifest.cs b/LANCommander.SDK/Models/GameManifest.cs index 6457504..d8900a9 100644 --- a/LANCommander.SDK/Models/GameManifest.cs +++ b/LANCommander.SDK/Models/GameManifest.cs @@ -48,5 +48,12 @@ namespace LANCommander.SDK public string Type { get; set; } public string Path { get; set; } public bool IsRegex { get; set; } + public IEnumerable Entries { get; set; } + } + + public class SavePathEntry + { + public string ArchivePath { get; set; } + public string ActualPath { get; set; } } } From 745cf0cce6a8ec69ac29e30539a01c32f4f716d5 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 30 Nov 2023 18:29:11 -0600 Subject: [PATCH 05/10] Prefer Path.DirectorySeparatorChar. Remove unused deserializer --- LANCommander.SDK/GameSaveManager.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/LANCommander.SDK/GameSaveManager.cs b/LANCommander.SDK/GameSaveManager.cs index e229401..3b2957f 100644 --- a/LANCommander.SDK/GameSaveManager.cs +++ b/LANCommander.SDK/GameSaveManager.cs @@ -61,19 +61,15 @@ namespace LANCommander.SDK ExtractFilesFromZip(tempFile, tempLocation); - var deserializer = new DeserializerBuilder() - .WithNamingConvention(new PascalCaseNamingConvention()) - .Build(); - #region Move files foreach (var savePath in manifest.SavePaths.Where(sp => sp.Type == "File")) { bool inInstallDir = savePath.Path.StartsWith("{InstallDir}"); string tempSavePath = Path.Combine(tempLocation, savePath.Id.ToString()); - var tempSavePathFile = Path.Combine(tempSavePath, savePath.Path.Replace('/', '\\').Replace("{InstallDir}\\", "")); + var tempSavePathFile = Path.Combine(tempSavePath, savePath.Path.Replace('/', Path.DirectorySeparatorChar).Replace("{InstallDir}\\", "")); - destination = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', '\\').Replace("{InstallDir}", installDirectory)); + destination = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory)); if (File.Exists(tempSavePathFile)) { @@ -94,7 +90,7 @@ namespace LANCommander.SDK if (inInstallDir) { // Files are in the game's install directory. Move them there from the save path. - destination = file.Replace(tempSavePath, savePath.Path.Replace('/', '\\').TrimEnd('\\').Replace("{InstallDir}", installDirectory)); + destination = file.Replace(tempSavePath, savePath.Path.Replace('/', Path.DirectorySeparatorChar).TrimEnd(Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory)); if (File.Exists(destination)) File.Delete(destination); From 74d8790ee29f933c2eeb84db294030d524981b7f Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 30 Nov 2023 18:30:15 -0600 Subject: [PATCH 06/10] Fix files skipped over if not in install directory --- LANCommander.SDK/GameSaveManager.cs | 39 ++++++++++++----------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/LANCommander.SDK/GameSaveManager.cs b/LANCommander.SDK/GameSaveManager.cs index 3b2957f..5eb67d4 100644 --- a/LANCommander.SDK/GameSaveManager.cs +++ b/LANCommander.SDK/GameSaveManager.cs @@ -83,35 +83,28 @@ namespace LANCommander.SDK { var files = Directory.GetFiles(tempSavePath, "*", SearchOption.AllDirectories); - if (inInstallDir) + foreach (var file in files) { - foreach (var file in files) + if (inInstallDir) { - if (inInstallDir) - { - // Files are in the game's install directory. Move them there from the save path. - destination = file.Replace(tempSavePath, savePath.Path.Replace('/', Path.DirectorySeparatorChar).TrimEnd(Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory)); + // Files are in the game's install directory. Move them there from the save path. + destination = file.Replace(tempSavePath, savePath.Path.Replace('/', Path.DirectorySeparatorChar).TrimEnd(Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory)); - if (File.Exists(destination)) - File.Delete(destination); + if (File.Exists(destination)) + File.Delete(destination); - File.Move(file, destination); - } - else - { - // Specified path is probably an absolute path, maybe with environment variables. - destination = Environment.ExpandEnvironmentVariables(file.Replace(tempSavePathFile, savePath.Path.Replace('/', '\\'))); - - if (File.Exists(destination)) - File.Delete(destination); - - File.Move(file, destination); - } + File.Move(file, destination); } - } - else - { + else + { + // Specified path is probably an absolute path, maybe with environment variables. + destination = Environment.ExpandEnvironmentVariables(file.Replace(tempSavePathFile, savePath.Path.Replace('/', '\\'))); + if (File.Exists(destination)) + File.Delete(destination); + + File.Move(file, destination); + } } } } From 7b625b2f6013bef2848d4e5adf06a6feecc8151a Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 30 Nov 2023 18:31:05 -0600 Subject: [PATCH 07/10] Use Path.DirectorySeparatorChar --- LANCommander.SDK/GameSaveManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LANCommander.SDK/GameSaveManager.cs b/LANCommander.SDK/GameSaveManager.cs index 5eb67d4..1b4fe28 100644 --- a/LANCommander.SDK/GameSaveManager.cs +++ b/LANCommander.SDK/GameSaveManager.cs @@ -67,7 +67,7 @@ namespace LANCommander.SDK bool inInstallDir = savePath.Path.StartsWith("{InstallDir}"); string tempSavePath = Path.Combine(tempLocation, savePath.Id.ToString()); - var tempSavePathFile = Path.Combine(tempSavePath, savePath.Path.Replace('/', Path.DirectorySeparatorChar).Replace("{InstallDir}\\", "")); + var tempSavePathFile = Path.Combine(tempSavePath, savePath.Path.Replace('/', Path.DirectorySeparatorChar).Replace("{InstallDir}" + Path.DirectorySeparatorChar, "")); destination = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory)); @@ -98,7 +98,7 @@ namespace LANCommander.SDK else { // Specified path is probably an absolute path, maybe with environment variables. - destination = Environment.ExpandEnvironmentVariables(file.Replace(tempSavePathFile, savePath.Path.Replace('/', '\\'))); + destination = Environment.ExpandEnvironmentVariables(file.Replace(tempSavePathFile, savePath.Path.Replace('/', Path.DirectorySeparatorChar))); if (File.Exists(destination)) File.Delete(destination); From 82779bcc72e76b9aec9947b947847559b629cc6b Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 30 Nov 2023 18:37:23 -0600 Subject: [PATCH 08/10] Restore files from save archive based on entries in manifest --- LANCommander.SDK/GameSaveManager.cs | 58 +++++++++++++++-------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/LANCommander.SDK/GameSaveManager.cs b/LANCommander.SDK/GameSaveManager.cs index 1b4fe28..228c209 100644 --- a/LANCommander.SDK/GameSaveManager.cs +++ b/LANCommander.SDK/GameSaveManager.cs @@ -67,43 +67,45 @@ namespace LANCommander.SDK bool inInstallDir = savePath.Path.StartsWith("{InstallDir}"); string tempSavePath = Path.Combine(tempLocation, savePath.Id.ToString()); - var tempSavePathFile = Path.Combine(tempSavePath, savePath.Path.Replace('/', Path.DirectorySeparatorChar).Replace("{InstallDir}" + Path.DirectorySeparatorChar, "")); - - destination = Environment.ExpandEnvironmentVariables(savePath.Path.Replace('/', Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory)); - - if (File.Exists(tempSavePathFile)) + foreach (var entry in savePath.Entries) { - // Is file, move file - if (File.Exists(destination)) - File.Delete(destination); + var tempSavePathFile = Path.Combine(tempSavePath, entry.ArchivePath); - File.Move(tempSavePathFile, destination); - } - else if (Directory.Exists(tempSavePath)) - { - var files = Directory.GetFiles(tempSavePath, "*", SearchOption.AllDirectories); + destination = Environment.ExpandEnvironmentVariables(entry.ActualPath).Replace("{InstallDir}", installDirectory); - foreach (var file in files) + if (File.Exists(tempSavePathFile)) { - if (inInstallDir) + if (File.Exists(destination)) + File.Delete(destination); + + File.Move(tempSavePathFile, destination); + } + else if (Directory.Exists(tempSavePath)) + { + var files = Directory.GetFiles(tempSavePath, "*", SearchOption.AllDirectories); + + foreach (var file in files) { - // Files are in the game's install directory. Move them there from the save path. - destination = file.Replace(tempSavePath, savePath.Path.Replace('/', Path.DirectorySeparatorChar).TrimEnd(Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory)); + if (inInstallDir) + { + // Files are in the game's install directory. Move them there from the save path. + destination = file.Replace(tempSavePath, savePath.Path.Replace('/', Path.DirectorySeparatorChar).TrimEnd(Path.DirectorySeparatorChar).Replace("{InstallDir}", installDirectory)); - if (File.Exists(destination)) - File.Delete(destination); + if (File.Exists(destination)) + File.Delete(destination); - File.Move(file, destination); - } - else - { - // Specified path is probably an absolute path, maybe with environment variables. - destination = Environment.ExpandEnvironmentVariables(file.Replace(tempSavePathFile, savePath.Path.Replace('/', Path.DirectorySeparatorChar))); + File.Move(file, destination); + } + else + { + // Specified path is probably an absolute path, maybe with environment variables. + destination = Environment.ExpandEnvironmentVariables(file.Replace(tempSavePathFile, savePath.Path.Replace('/', Path.DirectorySeparatorChar))); - if (File.Exists(destination)) - File.Delete(destination); + if (File.Exists(destination)) + File.Delete(destination); - File.Move(file, destination); + File.Move(file, destination); + } } } } From 78168e94a5f93b945ec5200881afd477a5daedde Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Thu, 30 Nov 2023 19:08:20 -0600 Subject: [PATCH 09/10] Fix new scripts not being created --- LANCommander/Components/ScriptEditor.razor | 11 ++++++++--- LANCommander/Components/ScriptEditorDialog.razor | 10 ++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/LANCommander/Components/ScriptEditor.razor b/LANCommander/Components/ScriptEditor.razor index ab35a6d..c1f39b8 100644 --- a/LANCommander/Components/ScriptEditor.razor +++ b/LANCommander/Components/ScriptEditor.razor @@ -58,11 +58,18 @@ ICollection