Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Download DBL resources data provider #1282

Merged
merged 10 commits into from
Nov 13, 2024
8 changes: 8 additions & 0 deletions assets/localization/en.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
3 changes: 3 additions & 0 deletions c-sharp/Program.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -32,10 +33,12 @@ public static async Task Main()

var paratextFactory = new ParatextProjectDataProviderFactory(papi, paratextProjects);
var checkRunner = new CheckRunner(papi);
var dblResources = new DblResourcesDataProvider(papi);
var paratextRegistrationService = new ParatextRegistrationService(papi);
await Task.WhenAll(
paratextFactory.InitializeAsync(),
checkRunner.RegisterDataProviderAsync(),
dblResources.RegisterDataProviderAsync(),
paratextRegistrationService.InitializeAsync()
);

Expand Down
228 changes: 228 additions & 0 deletions c-sharp/Projects/DigitalBibleLibrary/DblDownloadableDataProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
using System.Text.Json;
using Paranext.DataProvider.Services;
using Paratext.Data;
using Paratext.Data.Archiving;
using Paratext.Data.Users;

namespace Paranext.DataProvider.Projects.DigitalBibleLibrary;

/// <summary>
/// Data provider that can install, update and uninstall DBL (Digital Bible Library) resources
/// </summary>
internal class DblResourcesDataProvider(PapiClient papiClient)
: NetworkObjects.DataProvider("paratextBibleDownloadResources.dblResourcesProvider", papiClient)
{
#region Internal classes

private class DblResourceData(
string DblEntryUid,
string DisplayName,
string FullName,
string BestLanguageName,
long Size,
bool Installed,
bool UpdateAvailable
)
{
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 long Size { get; set; } = Size;
public bool Installed { get; set; } = Installed;
public bool UpdateAvailable { get; set; } = UpdateAvailable;
}

#endregion

#region Consts and member variables

public const string DBL_RESOURCES = "DblResources";

private List<InstallableResource> _resources = [];

#endregion

#region DataProvider methods

protected override List<(string functionName, Delegate function)> GetFunctions()
{
return
[
("getDblResources", GetDblResources),
("installDblResource", InstallDblResource),
("uninstallDblResource", UninstallDblResource),
];
}

protected override Task StartDataProviderAsync()
{
return Task.CompletedTask;
}

#endregion

#region Private properties and methods

/// <summary>
/// Fetch list DBL resources
/// </summary>
/// <returns>
/// A list of all available resources on the DBL, along with information about their
/// installation status on the local machine
/// </returns>
private void FetchAvailableDBLResources()
{
_resources = InstallableDBLResource.GetInstallableDBLResources(
RegistrationInfo.DefaultUser,
new DBLRESTClientFactory(),
new DblProjectDeleter(),
new DblMigrationOperations(),
new DblResourcePasswordProvider()
);
}

/// <summary>
/// Check user registration and, if registration is valid, return a list of information about
/// available DBL resources
/// </summary>
/// <returns>
/// 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
/// </returns>
private List<DblResourceData> GetDblResources(JsonElement _ignore)
{
if (!RegistrationInfo.DefaultUser.IsValid)
{
throw new Exception(
LocalizationService.GetLocalizedString(
PapiClient,
"%downloadResources_errorRegistrationInvalid%",
$"User registration is not valid. Cannot retrieve resources from DBL."
)
);
}

FetchAvailableDBLResources();

return _resources
.Select(resource => new DblResourceData(
resource.DBLEntryUid.Id,
resource.DisplayName,
resource.FullName,
resource.BestLanguageName,
resource.Size,
resource.Installed,
resource.IsNewerThanCurrentlyInstalled()
))
.ToList();
}

private void FindResource(
string dblEntryUid,
string messageToThrowIfNotFound,
out InstallableResource resource
)
{
resource =
_resources?.FirstOrDefault(r => r.DBLEntryUid.Id == dblEntryUid)
?? throw new Exception(messageToThrowIfNotFound);
}

/// <summary>
/// Try to install DBL resource with specified DBL id
/// </summary>
private void InstallDblResource(string DBLEntryUid)
{
FindResource(
DBLEntryUid,
LocalizationService.GetLocalizedString(
PapiClient,
"%downloadResources_errorInstallResource_resourceNotFound%",
$"Resource not available from DBL."
),
out var installableResource
);

if (installableResource.Installed && !installableResource.IsNewerThanCurrentlyInstalled())
throw new Exception(
LocalizationService.GetLocalizedString(
PapiClient,
"%downloadResources_errorInstallResource_resourceAlreadyInstalled%",
$"Resource is already installed and up to date. Installation skipped."
)
);

// Note that we don't get any info telling if the installation succeeded or failed
installableResource.Install();

ScrTextCollection.RefreshScrTexts();

if (!ScrTextCollection.IsPresent(installableResource.ExistingScrText))
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");
}

/// <summary>
/// Try to uninstall DBL resource with specified DBL id
/// </summary>
private void UninstallDblResource(string DBLEntryUid)
{
FindResource(
DBLEntryUid,
LocalizationService.GetLocalizedString(
PapiClient,
"%downloadResources_errorUninstallResource_resourceNotFound%",
$"Resource not found on list of DBL resources."
),
out var installableResource
);

if (!installableResource.Installed)
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(
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);

ScrTextCollection.RefreshScrTexts();

isPresent = ScrTextCollection.IsPresent(objectToBeDeleted);
if (isPresent)
throw new Exception(
LocalizationService.GetLocalizedString(
PapiClient,
"%downloadResources_errorUninstallResource_localResourceStillPresent%",
$"Resource is still present. Removing failed."
)
);

SendDataUpdateEvent(DBL_RESOURCES, "DBL resources data updated");
}

#endregion
}
36 changes: 36 additions & 0 deletions c-sharp/Projects/DigitalBibleLibrary/DblMigrationOperations.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Paratext.Data;
using Paratext.Data.Archiving;
using Paratext.Data.Languages;

namespace Paranext.DataProvider.Projects.DigitalBibleLibrary;

public class DblMigrationOperations : IMigrationOperations
{
/// <summary>
/// See `Paratext.Migration.PTMigration.Migrate` for steps involved in migrating data
/// </summary>
public UnsupportedReason MigrateProjectIfNeeded(ScrText scrText)
{
return scrText.NeedsMigration
? UnsupportedReason.CannotUpgrade
: UnsupportedReason.Supported;
}

/// <summary>
/// Adapted from `Paratext.Migration.MigrateLanguage`
/// </summary>
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;
}
}
20 changes: 20 additions & 0 deletions c-sharp/Projects/DigitalBibleLibrary/DblProjectDeleter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Paratext.Data;
using Paratext.Data.Archiving;
using Paratext.Data.ProjectComments;
using Paratext.Data.Repository;

namespace Paranext.DataProvider.Projects.DigitalBibleLibrary;

/// <summary>
/// Adapted from `Paratext.ProjectMenu.DeleteProjectForm.DeleteProject`
/// </summary>
public class DblProjectDeleter : IProjectDeleter
{
public void DeleteProject(ScrText scrText)
{
CommentManager.RemoveCommentManager(scrText);
VersioningManager.RemoveVersionedText(scrText);
if (!scrText.Settings.IsMarbleResource)
ScrTextCollection.DeleteProject(scrText);
}
}
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"biblionexus",
"camelcase",
"consts",
"deleter",
"deuterocanon",
"dockbox",
"electronmon",
Expand Down
7 changes: 0 additions & 7 deletions src/extension-host/data/menu.data.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@
"platform.helpMisc": { "column": "platform.help", "order": 2 }
},
"items": [
{
"label": "%mainMenu_downloadInstallResources%",
"localizeNotes": "Application main menu > Project > Download/Install Resources",
"group": "platform.projectResources",
"order": 1,
"command": "platform.downloadAndInstallResources"
},
{
"label": "%mainMenu_settings%",
"localizeNotes": "Application main menu > Project > Settings",
Expand Down
7 changes: 0 additions & 7 deletions src/renderer/components/platform-bible-menu.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: 'platform.downloadAndInstallResources',
},
{
label: 'Open Project...',
tooltip: 'Open project or resource text(s)',
Expand Down
Loading