From 5203e95141bfc35891a34eada3793bb14ff1a745 Mon Sep 17 00:00:00 2001 From: RobertBeekman Date: Sun, 25 Feb 2024 11:45:41 +0100 Subject: [PATCH] Core - Add migration to also migrate profile activation conditions --- .../Services/Storage/ProfileService.cs | 26 +++++++----- .../Migrations/IProfileMigration.cs | 2 +- .../Migrations/Profile/M0001NodeProviders.cs | 2 +- .../M0002NodeProvidersProfileConfig.cs | 35 ++++++++++++++++ .../M0025NodeProvidersProfileConfig.cs | 42 +++++++++++++++++++ 5 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 src/Artemis.Storage/Migrations/Profile/M0002NodeProvidersProfileConfig.cs create mode 100644 src/Artemis.Storage/Migrations/Storage/M0025NodeProvidersProfileConfig.cs diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index 90b25ea5f..d9f50cd1a 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -458,19 +458,23 @@ public async Task ImportProfile(Stream archiveStream, Prof if (profileEntry == null) throw new ArtemisCoreException("Could not import profile, profile.json missing"); + // Deserialize profile configuration to JObject await using Stream configurationStream = configurationEntry.Open(); using StreamReader configurationReader = new(configurationStream); - ProfileConfigurationEntity? configurationEntity = JsonConvert.DeserializeObject(await configurationReader.ReadToEndAsync(), IProfileService.ExportSettings); - if (configurationEntity == null) - throw new ArtemisCoreException("Could not import profile, failed to deserialize configuration.json"); - + JObject? configurationJson = JsonConvert.DeserializeObject(await configurationReader.ReadToEndAsync(), IProfileService.ExportSettings); + // Deserialize profile to JObject await using Stream profileStream = profileEntry.Open(); using StreamReader profileReader = new(profileStream); JObject? profileJson = JsonConvert.DeserializeObject(await profileReader.ReadToEndAsync(), IProfileService.ExportSettings); // Before deserializing, apply any pending migrations - MigrateProfile(configurationEntity, profileJson); + MigrateProfile(configurationJson, profileJson); + // Deserialize profile configuration to ProfileConfigurationEntity + ProfileConfigurationEntity? configurationEntity = configurationJson?.ToObject(JsonSerializer.Create(IProfileService.ExportSettings)); + if (configurationEntity == null) + throw new ArtemisCoreException("Could not import profile, failed to deserialize configuration.json"); + // Deserialize profile to ProfileEntity ProfileEntity? profileEntity = profileJson?.ToObject(JsonSerializer.Create(IProfileService.ExportSettings)); if (profileEntity == null) throw new ArtemisCoreException("Could not import profile, failed to deserialize profile.json"); @@ -555,18 +559,20 @@ private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEvent } } - private void MigrateProfile(ProfileConfigurationEntity configurationEntity, JObject? profileJson) + private void MigrateProfile(JObject? configurationJson, JObject? profileJson) { - if (profileJson == null) + if (configurationJson == null || profileJson == null) return; + configurationJson["Version"] ??= 0; + foreach (IProfileMigration profileMigrator in _profileMigrators.OrderBy(m => m.Version)) { - if (profileMigrator.Version <= configurationEntity.Version) + if (profileMigrator.Version <= configurationJson["Version"]!.Value()) continue; - profileMigrator.Migrate(profileJson); - configurationEntity.Version = profileMigrator.Version; + profileMigrator.Migrate(configurationJson, profileJson); + configurationJson["Version"] = profileMigrator.Version; } } diff --git a/src/Artemis.Storage/Migrations/IProfileMigration.cs b/src/Artemis.Storage/Migrations/IProfileMigration.cs index 1bb41c022..c4fb710ec 100644 --- a/src/Artemis.Storage/Migrations/IProfileMigration.cs +++ b/src/Artemis.Storage/Migrations/IProfileMigration.cs @@ -5,5 +5,5 @@ namespace Artemis.Storage.Migrations; public interface IProfileMigration { int Version { get; } - void Migrate(JObject profileJson); + void Migrate(JObject configurationJson, JObject profileJson); } \ No newline at end of file diff --git a/src/Artemis.Storage/Migrations/Profile/M0001NodeProviders.cs b/src/Artemis.Storage/Migrations/Profile/M0001NodeProviders.cs index 0dfab33a2..a1006bab8 100644 --- a/src/Artemis.Storage/Migrations/Profile/M0001NodeProviders.cs +++ b/src/Artemis.Storage/Migrations/Profile/M0001NodeProviders.cs @@ -12,7 +12,7 @@ internal class M0001NodeProviders : IProfileMigration public int Version => 1; /// - public void Migrate(JObject profileJson) + public void Migrate(JObject configurationJson, JObject profileJson) { JArray? folders = (JArray?) profileJson["Folders"]?["$values"]; JArray? layers = (JArray?) profileJson["Layers"]?["$values"]; diff --git a/src/Artemis.Storage/Migrations/Profile/M0002NodeProvidersProfileConfig.cs b/src/Artemis.Storage/Migrations/Profile/M0002NodeProvidersProfileConfig.cs new file mode 100644 index 000000000..9c35a961a --- /dev/null +++ b/src/Artemis.Storage/Migrations/Profile/M0002NodeProvidersProfileConfig.cs @@ -0,0 +1,35 @@ +using Newtonsoft.Json.Linq; + +namespace Artemis.Storage.Migrations.Profile; + +/// +/// Migrates nodes to be provider-based on profile configurations as well.. +/// This requires giving them a ProviderId and updating the their namespaces to match the namespace of the new plugin. +/// +internal class M0002NodeProvidersProfileConfig : IProfileMigration +{ + /// + public int Version => 2; + + /// + public void Migrate(JObject configurationJson, JObject profileJson) + { + MigrateNodeScript(configurationJson["ActivationCondition"]); + } + + private void MigrateNodeScript(JToken? nodeScript) + { + if (nodeScript == null || !nodeScript.HasValues) + return; + + JArray? nodes = (JArray?) nodeScript["Nodes"]?["$values"]; + if (nodes == null) + return; + + foreach (JToken node in nodes) + { + node["Type"] = node["Type"]?.Value()?.Replace("Artemis.VisualScripting.Nodes", "Artemis.Plugins.Nodes.General.Nodes"); + node["ProviderId"] = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78"; + } + } +} \ No newline at end of file diff --git a/src/Artemis.Storage/Migrations/Storage/M0025NodeProvidersProfileConfig.cs b/src/Artemis.Storage/Migrations/Storage/M0025NodeProvidersProfileConfig.cs new file mode 100644 index 000000000..b831bc03d --- /dev/null +++ b/src/Artemis.Storage/Migrations/Storage/M0025NodeProvidersProfileConfig.cs @@ -0,0 +1,42 @@ +using LiteDB; + +namespace Artemis.Storage.Migrations.Storage; + +public class M0025NodeProvidersProfileConfig : IStorageMigration +{ + public int UserVersion => 25; + + public void Apply(LiteRepository repository) + { + ILiteCollection categoryCollection = repository.Database.GetCollection("ProfileCategoryEntity"); + foreach (BsonDocument profileCategoryBson in categoryCollection.FindAll()) + { + BsonArray? profiles = profileCategoryBson["ProfileConfigurations"]?.AsArray; + if (profiles != null) + { + foreach (BsonValue profile in profiles) + { + profile["Version"] = 2; + MigrateNodeScript(profile["ActivationCondition"]?.AsDocument); + } + } + categoryCollection.Update(profileCategoryBson); + } + } + + private void MigrateNodeScript(BsonDocument? nodeScript) + { + if (nodeScript == null || nodeScript.Keys.Count == 0) + return; + + BsonArray? nodes = nodeScript["Nodes"]?.AsArray; + if (nodes == null) + return; + + foreach (BsonValue node in nodes) + { + node.AsDocument["Type"] = node.AsDocument["Type"]?.AsString?.Replace("Artemis.VisualScripting.Nodes", "Artemis.Plugins.Nodes.General.Nodes"); + node.AsDocument["ProviderId"] = "Artemis.Plugins.Nodes.General.GeneralNodesProvider-d9e1ee78"; + } + } +} \ No newline at end of file