From 540259593adfc2496eaf35fcfe9719d2ebb97d6a Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Fri, 8 Nov 2024 13:16:04 +0100 Subject: [PATCH 1/7] Getting works, installing is almost there --- c-sharp/Program.cs | 3 + .../DblDownloadableDataProvider.cs | 116 ++++++++++++++++++ .../DblMigrationOperations.cs | 36 ++++++ .../DigitalBibleLibrary/DblProjectDeleter.cs | 20 +++ .../DblResourcePasswordProvider.cs | 11 ++ src/extension-host/data/menu.data.json | 2 +- .../components/platform-bible-menu.data.ts | 2 +- 7 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs create mode 100644 c-sharp/Projects/DigitalBibleLibrary/DblMigrationOperations.cs create mode 100644 c-sharp/Projects/DigitalBibleLibrary/DblProjectDeleter.cs create mode 100644 c-sharp/Projects/DigitalBibleLibrary/DblResourcePasswordProvider.cs diff --git a/c-sharp/Program.cs b/c-sharp/Program.cs index 62ac75cc89..16a96ce396 100644 --- a/c-sharp/Program.cs +++ b/c-sharp/Program.cs @@ -1,6 +1,7 @@ using Paranext.DataProvider.Checks; using Paranext.DataProvider.NetworkObjects; using Paranext.DataProvider.Projects; +using Paranext.DataProvider.Projects.DigitalBibleLibrary; using Paranext.DataProvider.Services; using Paranext.DataProvider.Users; using Paratext.Data; @@ -32,10 +33,12 @@ public static async Task Main() var paratextFactory = new ParatextProjectDataProviderFactory(papi, paratextProjects); var checkRunner = new CheckRunner(papi); + var downloadResources = new DblDownloadableDataProvider(papi); var paratextRegistrationService = new ParatextRegistrationService(papi); await Task.WhenAll( paratextFactory.InitializeAsync(), checkRunner.RegisterDataProviderAsync(), + downloadResources.InitializeAsync(), paratextRegistrationService.InitializeAsync() ); diff --git a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs new file mode 100644 index 0000000000..7952b0b60e --- /dev/null +++ b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs @@ -0,0 +1,116 @@ +using Paratext.Data; +using Paratext.Data.Archiving; +using Paratext.Data.Users; + +namespace Paranext.DataProvider.Projects.DigitalBibleLibrary; + +internal class DblDownloadableDataProvider(PapiClient papiClient) +{ + private readonly object _installLock = new(); + + private List _resources = new List(); + + #region Public properties and methods + + public async Task InitializeAsync() + { + // Set up commands on the PAPI + await PapiClient.RegisterRequestHandlerAsync( + "command:paratextBibleDownloadResources.getDBLResources", + GetDBLResources + ); + await PapiClient.RegisterRequestHandlerAsync( + "command:paratextBibleDownloadResources.installDBLResource", + InstallDBLResource + ); + } + + #endregion + + #region Private properties and methods + + private PapiClient PapiClient { get; } = papiClient; + + private class ExtendedInstallableResource : InstallableResource + { + public ExtendedInstallableResource( + bool UpdateAvailable, + string DBLEntryUidString, + string BestLanguageName + ) + { + this.UpdateAvailable = UpdateAvailable; + this.DBLEntryUidString = DBLEntryUidString; + this.BestLanguageName = BestLanguageName; + } + + public bool UpdateAvailable { get; set; } + public string DBLEntryUidString { get; set; } + public new string BestLanguageName { get; set; } + } + + private void FetchAvailableDBLResources() + { + _resources = InstallableDBLResource.GetInstallableDBLResources( + RegistrationInfo.DefaultUser, + new DBLRESTClientFactory(), + new DblProjectDeleter(), + new DblMigrationOperations(), + new DblResourcePasswordProvider() + ); + } + + private List GetDBLResources() + { + if (!RegistrationInfo.DefaultUser.IsValid) + { + throw new Exception( + $"User registration is not valid. Cannot retrieve resources from DBL" + ); + } + + FetchAvailableDBLResources(); + + return _resources + .Select(resource => new ExtendedInstallableResource( + resource.IsNewerThanCurrentlyInstalled(), + resource.DBLEntryUid.Id, + resource.BestLanguageName + ) + { + DisplayName = resource.DisplayName, + FullName = resource.FullName, + }) + .ToList(); + } + + private bool TryFindResource(string dblEntryUid, out InstallableResource? resource) + { + resource = _resources?.FirstOrDefault(r => r.DBLEntryUid.Id == dblEntryUid); + return resource != null; + } + + private bool InstallDBLResource(string DBLEntryUid) + { + Console.Write("Id:", DBLEntryUid); + + if (!TryFindResource(DBLEntryUid, out var installableResource)) + { + Console.WriteLine("Resource not found"); + return false; + } + + lock (_installLock) + { + if (installableResource.Installed) + return true; + + bool retVal = installableResource.Install(); + if (retVal) + ScrTextCollection.RefreshScrTexts(); + return retVal; + } + } + + #endregion +} diff --git a/c-sharp/Projects/DigitalBibleLibrary/DblMigrationOperations.cs b/c-sharp/Projects/DigitalBibleLibrary/DblMigrationOperations.cs new file mode 100644 index 0000000000..4d2eaf6796 --- /dev/null +++ b/c-sharp/Projects/DigitalBibleLibrary/DblMigrationOperations.cs @@ -0,0 +1,36 @@ +using Paratext.Data; +using Paratext.Data.Archiving; +using Paratext.Data.Languages; + +namespace Paranext.DataProvider.Projects.DigitalBibleLibrary; + +public class DblMigrationOperations : IMigrationOperations +{ + /// + /// See `Paratext.Migration.PTMigration.Migrate` for steps involved in migrating data + /// + public UnsupportedReason MigrateProjectIfNeeded(ScrText scrText) + { + return scrText.NeedsMigration + ? UnsupportedReason.CannotUpgrade + : UnsupportedReason.Supported; + } + + /// + /// Adapted from `Paratext.Migration.MigrateLanguage` + /// + public LanguageId DetermineBestLangIdToUseForResource( + string ldmlLanguageId, + string dblLanguageId + ) + { + LanguageId ethnologueDblLanguageId = LanguageId.FromEthnologueCode(dblLanguageId); + if (string.IsNullOrEmpty(ldmlLanguageId)) + return ethnologueDblLanguageId; + + LanguageId ethnologueLdmlLanguageId = LanguageId.FromEthnologueCode(ldmlLanguageId); + if (ethnologueLdmlLanguageId.Code == ethnologueDblLanguageId.Code) + return ethnologueLdmlLanguageId; + return ethnologueDblLanguageId; + } +} diff --git a/c-sharp/Projects/DigitalBibleLibrary/DblProjectDeleter.cs b/c-sharp/Projects/DigitalBibleLibrary/DblProjectDeleter.cs new file mode 100644 index 0000000000..21af2a9b0b --- /dev/null +++ b/c-sharp/Projects/DigitalBibleLibrary/DblProjectDeleter.cs @@ -0,0 +1,20 @@ +using Paratext.Data; +using Paratext.Data.Archiving; +using Paratext.Data.ProjectComments; +using Paratext.Data.Repository; + +namespace Paranext.DataProvider.Projects.DigitalBibleLibrary; + +/// +/// Adapted from `Paratext.ProjectMenu.DeleteProjectForm.DeleteProject` +/// +public class DblProjectDeleter : IProjectDeleter +{ + public void DeleteProject(ScrText scrText) + { + CommentManager.RemoveCommentManager(scrText); + VersioningManager.RemoveVersionedText(scrText); + if (!scrText.Settings.IsMarbleResource) + ScrTextCollection.DeleteProject(scrText); + } +} diff --git a/c-sharp/Projects/DigitalBibleLibrary/DblResourcePasswordProvider.cs b/c-sharp/Projects/DigitalBibleLibrary/DblResourcePasswordProvider.cs new file mode 100644 index 0000000000..731f9207ed --- /dev/null +++ b/c-sharp/Projects/DigitalBibleLibrary/DblResourcePasswordProvider.cs @@ -0,0 +1,11 @@ +using Paratext.Data.ProjectFileAccess; + +namespace Paranext.DataProvider.Projects.DigitalBibleLibrary; + +internal class DblResourcePasswordProvider : IZippedResourcePasswordProvider +{ + public string GetPassword() + { + return "NotTheRealPassword"; + } +} diff --git a/src/extension-host/data/menu.data.json b/src/extension-host/data/menu.data.json index ec38ace803..beafaab3bd 100644 --- a/src/extension-host/data/menu.data.json +++ b/src/extension-host/data/menu.data.json @@ -31,7 +31,7 @@ "localizeNotes": "Application main menu > Project > Download/Install Resources", "group": "platform.projectResources", "order": 1, - "command": "platform.downloadAndInstallResources" + "command": "paratextBibleDownloadResources.openDownloadResources" }, { "label": "%mainMenu_settings%", diff --git a/src/renderer/components/platform-bible-menu.data.ts b/src/renderer/components/platform-bible-menu.data.ts index ef0842632f..b57610a36a 100644 --- a/src/renderer/components/platform-bible-menu.data.ts +++ b/src/renderer/components/platform-bible-menu.data.ts @@ -30,7 +30,7 @@ const supportAndDevelopmentMenuLayout: LocalizedMainMenu = { localizeNotes: 'Main application menu > Paratext column > Download/Install Resources', group: 'paratext.sendReceive', order: 1, - command: 'platform.downloadAndInstallResources', + command: 'paratextBibleDownloadResources.openDownloadResources', }, { label: 'Open Project...', From 6fd4c4c8211486c167fe3b1c4a05f419426a0d8b Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Mon, 11 Nov 2024 17:07:42 +0100 Subject: [PATCH 2/7] Switched to dataprovider --- c-sharp/Program.cs | 4 +- .../DblDownloadableDataProvider.cs | 119 +++++++++--------- cspell.json | 1 + 3 files changed, 66 insertions(+), 58 deletions(-) diff --git a/c-sharp/Program.cs b/c-sharp/Program.cs index 16a96ce396..7e4cfce959 100644 --- a/c-sharp/Program.cs +++ b/c-sharp/Program.cs @@ -33,12 +33,12 @@ public static async Task Main() var paratextFactory = new ParatextProjectDataProviderFactory(papi, paratextProjects); var checkRunner = new CheckRunner(papi); - var downloadResources = new DblDownloadableDataProvider(papi); + var dblResources = new DblResourcesDataProvider(papi); var paratextRegistrationService = new ParatextRegistrationService(papi); await Task.WhenAll( paratextFactory.InitializeAsync(), checkRunner.RegisterDataProviderAsync(), - downloadResources.InitializeAsync(), + dblResources.RegisterDataProviderAsync(), paratextRegistrationService.InitializeAsync() ); diff --git a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs index 7952b0b60e..57cb5be22c 100644 --- a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs +++ b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs @@ -1,56 +1,59 @@ +using System.Text.Json; using Paratext.Data; using Paratext.Data.Archiving; using Paratext.Data.Users; namespace Paranext.DataProvider.Projects.DigitalBibleLibrary; -internal class DblDownloadableDataProvider(PapiClient papiClient) +internal class DblResourcesDataProvider(PapiClient papiClient) + : NetworkObjects.DataProvider("platformBibleDownloadResources.dblResourcesProvider", papiClient) { - private readonly object _installLock = new(); - - private List _resources = new List(); - - #region Public properties and methods - - public async Task InitializeAsync() + #region Internal classes + + private class DblResourceData( + string DblEntryUid, + string DisplayName, + string FullName, + string BestLanguageName, + bool Installed, + bool UpdateAvailable + ) { - // Set up commands on the PAPI - await PapiClient.RegisterRequestHandlerAsync( - "command:paratextBibleDownloadResources.getDBLResources", - GetDBLResources - ); - await PapiClient.RegisterRequestHandlerAsync( - "command:paratextBibleDownloadResources.installDBLResource", - InstallDBLResource - ); + public string DblEntryUid { get; set; } = DblEntryUid; + public string DisplayName { get; set; } = DisplayName; + public string FullName { get; set; } = FullName; + public string BestLanguageName { get; set; } = BestLanguageName; + public bool Installed { get; set; } = Installed; + public bool UpdateAvailable { get; set; } = UpdateAvailable; } #endregion - #region Private properties and methods + #region Consts and member variables - private PapiClient PapiClient { get; } = papiClient; + private List _resources = []; - private class ExtendedInstallableResource : InstallableResource + #endregion + + #region DataProvider methods + + protected override List<(string functionName, Delegate function)> GetFunctions() { - public ExtendedInstallableResource( - bool UpdateAvailable, - string DBLEntryUidString, - string BestLanguageName - ) - { - this.UpdateAvailable = UpdateAvailable; - this.DBLEntryUidString = DBLEntryUidString; - this.BestLanguageName = BestLanguageName; - } + return [("getDblResources", GetDblResources)]; + } - public bool UpdateAvailable { get; set; } - public string DBLEntryUidString { get; set; } - public new string BestLanguageName { get; set; } + protected override Task StartDataProviderAsync() + { + return Task.CompletedTask; } + #endregion + + #region Private properties and methods + private void FetchAvailableDBLResources() { + Console.WriteLine("Fetching"); _resources = InstallableDBLResource.GetInstallableDBLResources( RegistrationInfo.DefaultUser, new DBLRESTClientFactory(), @@ -58,10 +61,13 @@ private void FetchAvailableDBLResources() new DblMigrationOperations(), new DblResourcePasswordProvider() ); + Console.WriteLine("Fetching done"); + Console.WriteLine(_resources.First().ToString()); } - private List GetDBLResources() + private List GetDblResources(JsonElement _ignore) { + Console.WriteLine("Rolf"); if (!RegistrationInfo.DefaultUser.IsValid) { throw new Exception( @@ -70,17 +76,17 @@ private List GetDBLResources() } FetchAvailableDBLResources(); + Console.WriteLine("Fetching done"); return _resources - .Select(resource => new ExtendedInstallableResource( - resource.IsNewerThanCurrentlyInstalled(), + .Select(resource => new DblResourceData( resource.DBLEntryUid.Id, - resource.BestLanguageName - ) - { - DisplayName = resource.DisplayName, - FullName = resource.FullName, - }) + resource.DisplayName, + resource.FullName, + resource.BestLanguageName, + resource.Installed, + resource.IsNewerThanCurrentlyInstalled() + )) .ToList(); } @@ -90,26 +96,27 @@ private bool TryFindResource(string dblEntryUid, out InstallableResource? resour return resource != null; } - private bool InstallDBLResource(string DBLEntryUid) + private bool InstallDBLResource(JsonElement _ignore, string DBLEntryUid) { - Console.Write("Id:", DBLEntryUid); - if (!TryFindResource(DBLEntryUid, out var installableResource)) { - Console.WriteLine("Resource not found"); - return false; + throw new Exception($"Resource not available from DBL"); } - lock (_installLock) - { - if (installableResource.Installed) - return true; + if (installableResource == null) + return false; + if (installableResource.Installed) + return true; - bool retVal = installableResource.Install(); - if (retVal) - ScrTextCollection.RefreshScrTexts(); - return retVal; - } + installableResource.Install(); + // Note that we don't get any info telling if the installation succeeded or failed + + ScrTextCollection.RefreshScrTexts(); + SendDataUpdateEvent("*", "DBL resources data updated"); + // DblResources + return true; + + // see paratextprojectdataprovider } #endregion diff --git a/cspell.json b/cspell.json index 02641c07ed..7f0eeeacb0 100644 --- a/cspell.json +++ b/cspell.json @@ -37,6 +37,7 @@ "biblionexus", "camelcase", "consts", + "deleter", "deuterocanon", "dockbox", "electronmon", From f3720ba39b42de0c8ba264543c03627ab13b7a96 Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Mon, 11 Nov 2024 17:35:21 +0100 Subject: [PATCH 3/7] Add install resource function --- .../DigitalBibleLibrary/DblDownloadableDataProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs index 57cb5be22c..bb423d5133 100644 --- a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs +++ b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs @@ -39,7 +39,7 @@ bool UpdateAvailable protected override List<(string functionName, Delegate function)> GetFunctions() { - return [("getDblResources", GetDblResources)]; + return [("getDblResources", GetDblResources), ("installDblResource", InstallDblResource)]; } protected override Task StartDataProviderAsync() @@ -96,7 +96,7 @@ private bool TryFindResource(string dblEntryUid, out InstallableResource? resour return resource != null; } - private bool InstallDBLResource(JsonElement _ignore, string DBLEntryUid) + private bool InstallDblResource(string DBLEntryUid) { if (!TryFindResource(DBLEntryUid, out var installableResource)) { From 9902432200961115e35b7fd5dcd68c60d4f86755 Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Mon, 11 Nov 2024 18:56:30 +0100 Subject: [PATCH 4/7] Add uninstall function and size prop --- .../DblDownloadableDataProvider.cs | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs index bb423d5133..7b87872378 100644 --- a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs +++ b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs @@ -15,6 +15,7 @@ private class DblResourceData( string DisplayName, string FullName, string BestLanguageName, + long Size, bool Installed, bool UpdateAvailable ) @@ -23,6 +24,7 @@ bool UpdateAvailable public string DisplayName { get; set; } = DisplayName; public string FullName { get; set; } = FullName; public string BestLanguageName { get; set; } = BestLanguageName; + public long Size { get; set; } = Size; public bool Installed { get; set; } = Installed; public bool UpdateAvailable { get; set; } = UpdateAvailable; } @@ -39,7 +41,12 @@ bool UpdateAvailable protected override List<(string functionName, Delegate function)> GetFunctions() { - return [("getDblResources", GetDblResources), ("installDblResource", InstallDblResource)]; + return + [ + ("getDblResources", GetDblResources), + ("installDblResource", InstallDblResource), + ("uninstallDblResource", UninstallDblResource), + ]; } protected override Task StartDataProviderAsync() @@ -53,7 +60,6 @@ protected override Task StartDataProviderAsync() private void FetchAvailableDBLResources() { - Console.WriteLine("Fetching"); _resources = InstallableDBLResource.GetInstallableDBLResources( RegistrationInfo.DefaultUser, new DBLRESTClientFactory(), @@ -61,13 +67,10 @@ private void FetchAvailableDBLResources() new DblMigrationOperations(), new DblResourcePasswordProvider() ); - Console.WriteLine("Fetching done"); - Console.WriteLine(_resources.First().ToString()); } private List GetDblResources(JsonElement _ignore) { - Console.WriteLine("Rolf"); if (!RegistrationInfo.DefaultUser.IsValid) { throw new Exception( @@ -76,7 +79,6 @@ private List GetDblResources(JsonElement _ignore) } FetchAvailableDBLResources(); - Console.WriteLine("Fetching done"); return _resources .Select(resource => new DblResourceData( @@ -84,6 +86,7 @@ private List GetDblResources(JsonElement _ignore) resource.DisplayName, resource.FullName, resource.BestLanguageName, + resource.Size, resource.Installed, resource.IsNewerThanCurrentlyInstalled() )) @@ -105,18 +108,39 @@ private bool InstallDblResource(string DBLEntryUid) if (installableResource == null) return false; - if (installableResource.Installed) + if (installableResource.Installed && !installableResource.IsNewerThanCurrentlyInstalled()) return true; installableResource.Install(); // Note that we don't get any info telling if the installation succeeded or failed ScrTextCollection.RefreshScrTexts(); - SendDataUpdateEvent("*", "DBL resources data updated"); + SendDataUpdateEvent("DblResources", "DBL resources data updated"); + // see paratextprojectdataprovider // DblResources return true; + } - // see paratextprojectdataprovider + private bool UninstallDblResource(string DBLEntryUid) + { + if (!TryFindResource(DBLEntryUid, out var installableResource)) + { + throw new Exception($"Resource not available from DBL"); + } + + if (installableResource == null) + return false; + if (!installableResource.Installed) + return false; + + ScrTextCollection.DeleteProject( + installableResource.ExistingScrText ?? installableResource.ExistingDictionary + // Note that we don't get any info telling if uninstalling succeeded or failed + ); + + ScrTextCollection.RefreshScrTexts(); + SendDataUpdateEvent("*", "DBL resources data updated"); + return true; } #endregion From 0ed73699b7ed1188d07d71e4016c33e0502a249a Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Mon, 11 Nov 2024 19:10:31 +0100 Subject: [PATCH 5/7] Small clean-up --- .../DigitalBibleLibrary/DblDownloadableDataProvider.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs index 7b87872378..d13333645e 100644 --- a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs +++ b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs @@ -111,13 +111,11 @@ private bool InstallDblResource(string DBLEntryUid) if (installableResource.Installed && !installableResource.IsNewerThanCurrentlyInstalled()) return true; - installableResource.Install(); // Note that we don't get any info telling if the installation succeeded or failed + installableResource.Install(); ScrTextCollection.RefreshScrTexts(); SendDataUpdateEvent("DblResources", "DBL resources data updated"); - // see paratextprojectdataprovider - // DblResources return true; } @@ -134,12 +132,12 @@ private bool UninstallDblResource(string DBLEntryUid) return false; ScrTextCollection.DeleteProject( + // Note that we don't get any info telling if uninstalling succeeded or failed installableResource.ExistingScrText ?? installableResource.ExistingDictionary - // Note that we don't get any info telling if uninstalling succeeded or failed ); ScrTextCollection.RefreshScrTexts(); - SendDataUpdateEvent("*", "DBL resources data updated"); + SendDataUpdateEvent("DblResources", "DBL resources data updated"); return true; } From 7286b377f7fae81fbd683f5b4de5b40380a08b44 Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Tue, 12 Nov 2024 20:17:28 +0100 Subject: [PATCH 6/7] Review comments --- .../DblDownloadableDataProvider.cs | 79 +++++++++++++++---- src/extension-host/data/menu.data.json | 7 -- .../components/platform-bible-menu.data.ts | 7 -- 3 files changed, 65 insertions(+), 28 deletions(-) diff --git a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs index d13333645e..f8bca39185 100644 --- a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs +++ b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs @@ -5,8 +5,11 @@ namespace Paranext.DataProvider.Projects.DigitalBibleLibrary; +/// +/// Data provider that can install, update and uninstall DBL (Digital Bible Library) resources +/// internal class DblResourcesDataProvider(PapiClient papiClient) - : NetworkObjects.DataProvider("platformBibleDownloadResources.dblResourcesProvider", papiClient) + : NetworkObjects.DataProvider("paratextBibleDownloadResources.dblResourcesProvider", papiClient) { #region Internal classes @@ -33,6 +36,8 @@ bool UpdateAvailable #region Consts and member variables + public const string DBL_RESOURCES = "DblResources"; + private List _resources = []; #endregion @@ -58,6 +63,13 @@ protected override Task StartDataProviderAsync() #region Private properties and methods + /// + /// Fetch list DBL resources + /// + /// + /// A list of all available resources on the DBL, along with information about their + /// installation status on the local machine + /// private void FetchAvailableDBLResources() { _resources = InstallableDBLResource.GetInstallableDBLResources( @@ -69,6 +81,14 @@ private void FetchAvailableDBLResources() ); } + /// + /// Check user registration and, if registration is valid, return a list of information about + /// available DBL resources + /// + /// + /// A list with some information about all available resources on the DBL, for the purpose of + /// presenting the resources and their installation status on the front-end + /// private List GetDblResources(JsonElement _ignore) { if (!RegistrationInfo.DefaultUser.IsValid) @@ -99,6 +119,12 @@ private bool TryFindResource(string dblEntryUid, out InstallableResource? resour return resource != null; } + /// + /// Try to install DBL resource with specified DBL id + /// + /// + /// True if successful. False/throws if unsuccessful. + /// private bool InstallDblResource(string DBLEntryUid) { if (!TryFindResource(DBLEntryUid, out var installableResource)) @@ -106,38 +132,63 @@ private bool InstallDblResource(string DBLEntryUid) throw new Exception($"Resource not available from DBL"); } - if (installableResource == null) - return false; +#pragma warning disable CS8602 // Dereference of a possibly null reference. + // We've already checked if installableResource is null if (installableResource.Installed && !installableResource.IsNewerThanCurrentlyInstalled()) - return true; + throw new Exception( + $"Resource is already installed and up to date. Installation skipped." + ); +#pragma warning restore CS8602 // Dereference of a possibly null reference. // Note that we don't get any info telling if the installation succeeded or failed installableResource.Install(); ScrTextCollection.RefreshScrTexts(); - SendDataUpdateEvent("DblResources", "DBL resources data updated"); + + if (!ScrTextCollection.IsPresent(installableResource.ExistingScrText)) + throw new Exception($"Resource cannot be found. Installation failed."); + + SendDataUpdateEvent(DBL_RESOURCES, "DBL resources data updated"); + return true; } + /// + /// Try to uninstall DBL resource with specified DBL id + /// + /// + /// True if successful. False/throws if unsuccessful. + /// private bool UninstallDblResource(string DBLEntryUid) { if (!TryFindResource(DBLEntryUid, out var installableResource)) { - throw new Exception($"Resource not available from DBL"); + throw new Exception($"Resource not found on list of DBL resources."); } - if (installableResource == null) - return false; +#pragma warning disable CS8602 // Dereference of a possibly null reference. + // We've already checked if installableResource is null if (!installableResource.Installed) - return false; + throw new Exception($"Resource is not currently installed, so it can't be removed."); +#pragma warning restore CS8602 // Dereference of a possibly null reference. - ScrTextCollection.DeleteProject( - // Note that we don't get any info telling if uninstalling succeeded or failed - installableResource.ExistingScrText ?? installableResource.ExistingDictionary - ); + var objectToBeDeleted = installableResource.ExistingScrText; + + var isPresent = ScrTextCollection.IsPresent(objectToBeDeleted); + if (!isPresent) + throw new Exception($"Resource cannot be located, so it can't be removed."); + + // Note that we don't get any info telling if uninstalling succeeded or failed + ScrTextCollection.DeleteProject(objectToBeDeleted); ScrTextCollection.RefreshScrTexts(); - SendDataUpdateEvent("DblResources", "DBL resources data updated"); + + isPresent = ScrTextCollection.IsPresent(objectToBeDeleted); + if (isPresent) + throw new Exception($"Resource is still present. Removing failed."); + + SendDataUpdateEvent(DBL_RESOURCES, "DBL resources data updated"); + return true; } diff --git a/src/extension-host/data/menu.data.json b/src/extension-host/data/menu.data.json index beafaab3bd..827a8eadea 100644 --- a/src/extension-host/data/menu.data.json +++ b/src/extension-host/data/menu.data.json @@ -26,13 +26,6 @@ "platform.helpMisc": { "column": "platform.help", "order": 2 } }, "items": [ - { - "label": "%mainMenu_downloadSlashInstallResources%", - "localizeNotes": "Application main menu > Project > Download/Install Resources", - "group": "platform.projectResources", - "order": 1, - "command": "paratextBibleDownloadResources.openDownloadResources" - }, { "label": "%mainMenu_settings%", "localizeNotes": "Application main menu > Project > Settings", diff --git a/src/renderer/components/platform-bible-menu.data.ts b/src/renderer/components/platform-bible-menu.data.ts index b57610a36a..7b37b6f860 100644 --- a/src/renderer/components/platform-bible-menu.data.ts +++ b/src/renderer/components/platform-bible-menu.data.ts @@ -25,13 +25,6 @@ const supportAndDevelopmentMenuLayout: LocalizedMainMenu = { 'paratext.helpSubgroup': { menuItem: 'paratext.helpRoot', order: 1 }, }, items: [ - { - label: 'Download/Install Resources', - localizeNotes: 'Main application menu > Paratext column > Download/Install Resources', - group: 'paratext.sendReceive', - order: 1, - command: 'paratextBibleDownloadResources.openDownloadResources', - }, { label: 'Open Project...', tooltip: 'Open project or resource text(s)', From 26fe15782923ef6697a14a87104c5d8c69b00b01 Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Wed, 13 Nov 2024 17:12:39 +0100 Subject: [PATCH 7/7] Added localization for exceptions --- assets/localization/en.json | 8 ++ .../DblDownloadableDataProvider.cs | 102 ++++++++++++------ 2 files changed, 75 insertions(+), 35 deletions(-) diff --git a/assets/localization/en.json b/assets/localization/en.json index 675cc44c20..4517499d4d 100644 --- a/assets/localization/en.json +++ b/assets/localization/en.json @@ -1,6 +1,14 @@ { "%about_versionLabel_format%": "Version: {version}", "%about_licenseLabel_format%": "License: {license}", + "%downloadResources_errorRegistrationInvalid%": "User registration is not valid. Cannot retrieve resources from DBL.", + "%downloadResources_errorInstallResource_resourceNotFound%": "Resource not available from DBL", + "%downloadResources_errorInstallResource_resourceAlreadyInstalled%": "Resource is already installed and up to date. Installation skipped.", + "%downloadResources_errorInstallResource_installationFailed%": "Resource cannot be found after attempted installation. Installation failed.", + "%downloadResources_errorUninstallResource_resourceNotFound%": "Resource not found on list of DBL resources.", + "%downloadResources_errorUninstallResource_resourceNotInstalled%": "Resource is not currently installed, so it can't be removed.", + "%downloadResources_errorUninstallResource_localResourceNotFound%": "Resource cannot be located, so it can't be removed.", + "%downloadResources_errorUninstallResource_localResourceStillPresent%": "Resource is still present. Removing failed.", "%downloadUpdateProjectTab_aria_downloadable%": "downloadable projects", "%downloadUpdateProjectTab_aria_downloaded%": "downloaded projects", "%downloadUpdateProjectTab_button_delete%": "Delete", diff --git a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs index f8bca39185..2c0cd5f998 100644 --- a/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs +++ b/c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using Paranext.DataProvider.Services; using Paratext.Data; using Paratext.Data.Archiving; using Paratext.Data.Users; @@ -94,7 +95,11 @@ private List GetDblResources(JsonElement _ignore) if (!RegistrationInfo.DefaultUser.IsValid) { throw new Exception( - $"User registration is not valid. Cannot retrieve resources from DBL" + LocalizationService.GetLocalizedString( + PapiClient, + "%downloadResources_errorRegistrationInvalid%", + $"User registration is not valid. Cannot retrieve resources from DBL." + ) ); } @@ -113,32 +118,40 @@ private List GetDblResources(JsonElement _ignore) .ToList(); } - private bool TryFindResource(string dblEntryUid, out InstallableResource? resource) + private void FindResource( + string dblEntryUid, + string messageToThrowIfNotFound, + out InstallableResource resource + ) { - resource = _resources?.FirstOrDefault(r => r.DBLEntryUid.Id == dblEntryUid); - return resource != null; + resource = + _resources?.FirstOrDefault(r => r.DBLEntryUid.Id == dblEntryUid) + ?? throw new Exception(messageToThrowIfNotFound); } /// /// Try to install DBL resource with specified DBL id /// - /// - /// True if successful. False/throws if unsuccessful. - /// - private bool InstallDblResource(string DBLEntryUid) + private void InstallDblResource(string DBLEntryUid) { - if (!TryFindResource(DBLEntryUid, out var installableResource)) - { - throw new Exception($"Resource not available from DBL"); - } + FindResource( + DBLEntryUid, + LocalizationService.GetLocalizedString( + PapiClient, + "%downloadResources_errorInstallResource_resourceNotFound%", + $"Resource not available from DBL." + ), + out var installableResource + ); -#pragma warning disable CS8602 // Dereference of a possibly null reference. - // We've already checked if installableResource is null if (installableResource.Installed && !installableResource.IsNewerThanCurrentlyInstalled()) throw new Exception( - $"Resource is already installed and up to date. Installation skipped." + LocalizationService.GetLocalizedString( + PapiClient, + "%downloadResources_errorInstallResource_resourceAlreadyInstalled%", + $"Resource is already installed and up to date. Installation skipped." + ) ); -#pragma warning restore CS8602 // Dereference of a possibly null reference. // Note that we don't get any info telling if the installation succeeded or failed installableResource.Install(); @@ -146,37 +159,52 @@ private bool InstallDblResource(string DBLEntryUid) ScrTextCollection.RefreshScrTexts(); if (!ScrTextCollection.IsPresent(installableResource.ExistingScrText)) - throw new Exception($"Resource cannot be found. Installation failed."); + throw new Exception( + LocalizationService.GetLocalizedString( + PapiClient, + "%downloadResources_errorInstallResource_installationFailed%", + $"Resource cannot be found after attempted installation. Installation failed." + ) + ); SendDataUpdateEvent(DBL_RESOURCES, "DBL resources data updated"); - - return true; } /// /// Try to uninstall DBL resource with specified DBL id /// - /// - /// True if successful. False/throws if unsuccessful. - /// - private bool UninstallDblResource(string DBLEntryUid) + private void UninstallDblResource(string DBLEntryUid) { - if (!TryFindResource(DBLEntryUid, out var installableResource)) - { - throw new Exception($"Resource not found on list of DBL resources."); - } + FindResource( + DBLEntryUid, + LocalizationService.GetLocalizedString( + PapiClient, + "%downloadResources_errorUninstallResource_resourceNotFound%", + $"Resource not found on list of DBL resources." + ), + out var installableResource + ); -#pragma warning disable CS8602 // Dereference of a possibly null reference. - // We've already checked if installableResource is null if (!installableResource.Installed) - throw new Exception($"Resource is not currently installed, so it can't be removed."); -#pragma warning restore CS8602 // Dereference of a possibly null reference. + throw new Exception( + LocalizationService.GetLocalizedString( + PapiClient, + "%downloadResources_errorUninstallResource_resourceNotInstalled%", + $"Resource is not currently installed, so it can't be removed." + ) + ); var objectToBeDeleted = installableResource.ExistingScrText; var isPresent = ScrTextCollection.IsPresent(objectToBeDeleted); if (!isPresent) - throw new Exception($"Resource cannot be located, so it can't be removed."); + throw new Exception( + LocalizationService.GetLocalizedString( + PapiClient, + "%downloadResources_errorUninstallResource_localResourceNotFound%", + $"Resource cannot be located, so it can't be removed." + ) + ); // Note that we don't get any info telling if uninstalling succeeded or failed ScrTextCollection.DeleteProject(objectToBeDeleted); @@ -185,11 +213,15 @@ private bool UninstallDblResource(string DBLEntryUid) isPresent = ScrTextCollection.IsPresent(objectToBeDeleted); if (isPresent) - throw new Exception($"Resource is still present. Removing failed."); + throw new Exception( + LocalizationService.GetLocalizedString( + PapiClient, + "%downloadResources_errorUninstallResource_localResourceStillPresent%", + $"Resource is still present. Removing failed." + ) + ); SendDataUpdateEvent(DBL_RESOURCES, "DBL resources data updated"); - - return true; } #endregion