Skip to content

Commit

Permalink
Prepare the resource viewer to be able to open resource projects (#1271)
Browse files Browse the repository at this point in the history
  • Loading branch information
lyonsil authored Nov 7, 2024
1 parent 63002a6 commit debbc3f
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 73 deletions.
11 changes: 7 additions & 4 deletions c-sharp/ParanextDataProvider.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
Expand All @@ -19,6 +19,7 @@
<PackageProjectUrl>https://github.com/paranext</PackageProjectUrl>
<RepositoryUrl>https://github.com/paranext/paranext-core</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<UserSecretsId>1860f020-31dd-4eb4-81c4-323eb0cb3e48</UserSecretsId>
<!-- Uncomment the following lines to help with debugging into .NET core
<DebugType>portable</DebugType>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
Expand All @@ -27,16 +28,18 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ParatextData" Version="9.5.0.6" />
<PackageReference Include="icu.net" Version="2.10.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.1" />
<PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="72.1.0.1" Condition="$([MSBuild]::IsOsPlatform('Windows'))" />
<PackageReference Include="ParatextChecks" Version="9.5.0.6" />
<PackageReference Include="ParatextData" Version="9.5.0.6" />
<PackageReference Include="SIL.Core" Version="14.2.0-beta0009" />
<PackageReference Include="SIL.Scripture" Version="14.2.0-beta0009" />
<PackageReference Include="SIL.WritingSystems" Version="14.2.0-beta0009" />
<PackageReference Include="StreamJsonRpc" Version="2.19.27" />
<PackageReference Include="System.Net.WebSockets" Version="4.3.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageReference Include="icu.net" Version="2.10.0" />
<PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="72.1.0.1" Condition="$([MSBuild]::IsOsPlatform('Windows'))" />
</ItemGroup>

<!--
Expand Down
3 changes: 3 additions & 0 deletions c-sharp/ParatextUtils/ParatextGlobals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public static void Initialize(string dataFolderPath)
if (s_initialized)
return;

// Override a few key functions for ScrTextCollection static methods to work
ScrTextCollection.Implementation = new PlatformScrTextCollection();

// Required for the Paratext.Data.Encodings.StringEncoders static constructor
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Expand Down
66 changes: 66 additions & 0 deletions c-sharp/ParatextUtils/PlatformScrTextCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Paranext.DataProvider.Projects.DigitalBibleLibrary;
using Paratext.Data;
using Paratext.Data.Users;
using SIL.WritingSystems;

namespace Paranext.DataProvider.ParatextUtils;

/// <summary>
/// Adapted from ParatextScrTextCollection
/// </summary>
public class PlatformScrTextCollection : ScrTextCollection
{
// keep track of languages that weren't found in SLDR so we don't call over and over for the same bad code
private static readonly HashSet<string> s_sldrLookupFailed = [];

protected override ScrText CreateResourceProject(ProjectName name)
{
return new ResourceScrText(
name,
RegistrationInfo.DefaultUser,
new DblResourcePasswordProvider()
);
}

protected override ScrText CreateXmlResourceProject(ProjectName name)
{
return new XmlResourceScrText(
name,
RegistrationInfo.DefaultUser,
new DblResourcePasswordProvider()
);
}

protected override UnsupportedReason MigrateProjectIfNeeded(ScrText scrText)
{
return scrText.NeedsMigration
? UnsupportedReason.CannotUpgrade
: UnsupportedReason.Supported;
}

protected override WritingSystemDefinition CreateWsDef(string languageId, bool allowSldr)
{
// only check SLDR if allowed for this call and all internet access is enabled - SLDR isn't set up to use proxy
WritingSystemDefinition? wsDef = null;
if (
allowSldr
&& InternetAccess.Status == InternetUse.Enabled
&& !s_sldrLookupFailed.Contains(languageId)
)
{
try
{
var sldrFactory = new SldrWritingSystemFactory();
sldrFactory.Create(languageId, out wsDef);
}
catch (Exception e)
{
// ignore any SLDR errors - there have been problems with entries on the server failing to parse.
// also the id being provided may not be valid
Console.WriteLine("Getting {0} from SLDR failed: {1}", languageId, e);
s_sldrLookupFailed.Add(languageId);
}
}
return wsDef!;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Microsoft.Extensions.Configuration;
using Paranext.DataProvider.Users;
using Paratext.Data.ProjectFileAccess;
using Paratext.Data.Users;
using PtxUtils;

namespace Paranext.DataProvider.Projects.DigitalBibleLibrary;

/// <summary>
/// Adapted from ParatextZippedResourcePasswordProvider
/// </summary>
internal class DblResourcePasswordProvider : IZippedResourcePasswordProvider
{
private string? _cachedValue;

public string GetPassword()
{
if (!RegistrationInfo.DefaultUser.IsValid)
{
// Throwing an exception here is invisible to users because ParatextData swallows it
// Log the message instead in case it is helpful for someone troubleshooting
Console.WriteLine(RegistrationRequiredException.ExceptionMessage);
return "This is not the correct password";
}

IConfigurationRoot config = new ConfigurationBuilder()
.AddUserSecrets<DblResourcePasswordProvider>()
.Build();

// Run the following from the command line to set a config value (quotes are important):
// dotnet user-secrets set "<secret name>" "<secret value>"
// DO NOT share the secret values, including checking in code, texts, emails, DMs, etc.
_cachedValue ??= StringUtils.DecryptStringFromBase64(
config["DblResourceBase64-DO-NOT-SHARE"] ?? "",
config["DblResourceHash-DO-NOT-SHARE"] ?? ""
);
return _cachedValue;
}
}
11 changes: 9 additions & 2 deletions c-sharp/Projects/LocalParatextProjects.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Xml;
using Paranext.DataProvider.ParatextUtils;
using Paranext.DataProvider.Users;
using Paratext.Data;
using Paratext.Data.Users;

Expand Down Expand Up @@ -116,7 +117,10 @@ public virtual void Initialize(bool shouldIncludePT9ProjectsOnWindows)

public IEnumerable<ProjectDetails> GetAllProjectDetails()
{
return GetScrTexts().Select(scrText => scrText.GetProjectDetails());
var allScrTexts = GetScrTexts();
if (!RegistrationInfo.DefaultUser.IsValid)
allScrTexts = allScrTexts.Where((scrText) => !scrText.IsResourceProject);
return allScrTexts.Select(scrText => scrText.GetProjectDetails());
}

public ProjectDetails GetProjectDetails(string projectId)
Expand All @@ -126,7 +130,10 @@ public ProjectDetails GetProjectDetails(string projectId)

public static ScrText GetParatextProject(string projectId)
{
return ScrTextCollection.GetById(HexId.FromStr(projectId));
var retVal = ScrTextCollection.GetById(HexId.FromStr(projectId));
if (retVal.IsResourceProject && !RegistrationInfo.DefaultUser.IsValid)
throw new RegistrationRequiredException();
return retVal;
}

public static List<string> GetParatextProjectInterfaces()
Expand Down
7 changes: 7 additions & 0 deletions c-sharp/Projects/ParatextProjectDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,11 @@ private void RegisterSettingsValidators()
if (paratextSettingName == ProjectSettingsNames.PT_NAME)
return scrText.Name;

// Some resource projects are marked as editable in their settings, but we want to treat
// them as read-only projects
if (scrText.IsResourceProject && paratextSettingName == ProjectSettingsNames.PT_IS_EDITABLE)
return false;

if (
scrText.Settings.ParametersDictionary.TryGetValue(
paratextSettingName,
Expand Down Expand Up @@ -324,6 +329,8 @@ out string? settingValue
public bool SetProjectSetting(string settingName, object? value)
{
var scrText = LocalParatextProjects.GetParatextProject(ProjectDetails.Metadata.Id);
if (scrText.IsResourceProject)
throw new Exception("Cannot change settings on resources");

// If there is no Paratext setting for the name given, we'll create one lower down
object? currentValue = null;
Expand Down
11 changes: 11 additions & 0 deletions c-sharp/Users/ParatextRegistrationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ await PapiClient.RegisterRequestHandlerAsync(
"command:paratextRegistration.setParatextRegistrationData",
SetParatextRegistrationData
);
await PapiClient.RegisterRequestHandlerAsync(
"command:paratextRegistration.doesUserHaveValidRegistration",
() => RegistrationInfo.DefaultUser.IsValid
);

// Lookup localized strings where they may be needed by callers without access to PapiClient
RegistrationRequiredException.ExceptionMessage = LocalizationService.GetLocalizedString(
PapiClient,
"%paratextRegistration_exception_register_before_accessing_dbl_resources%",
RegistrationRequiredException.ExceptionMessage
);
}

#endregion
Expand Down
22 changes: 22 additions & 0 deletions c-sharp/Users/RegistrationRequiredException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Paranext.DataProvider.Users;

/// <summary>
/// Exception to inform callers that a valid Paratext registration is required before DBL resources can be opened
/// </summary>
public class RegistrationRequiredException : Exception
{
/// <summary>
/// Exception to inform callers that a valid Paratext registration is required before DBL resources can be opened
/// </summary>
public RegistrationRequiredException()
: base(ExceptionMessage) { }

/// <summary>
/// Exception to inform callers that a valid Paratext registration is required before DBL resources can be opened
/// </summary>
public RegistrationRequiredException(string? customMessage = null)
: base(customMessage ?? ExceptionMessage) { }

public static string ExceptionMessage { get; set; } =
"You must provide a valid Paratext registration before opening resources from the Digital Bible Library.";
}
7 changes: 4 additions & 3 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"appdata",
"asyncs",
"autodocs",
"BBBCCCVVV",
"bbbcccvvv",
"biblionexus",
"camelcase",
"consts",
Expand All @@ -51,7 +51,7 @@
"iusfm",
"iusj",
"iusx",
"JSONRPCID",
"jsonrpcid",
"localizable",
"localstorage",
"maximizable",
Expand All @@ -74,6 +74,7 @@
"reserialized",
"shadcn",
"sillsdev",
"sldr",
"sonner",
"steenwyk",
"stringifiable",
Expand All @@ -94,7 +95,7 @@
"verseref",
"versification",
"vref",
"VSTHRD"
"vsthrd"
],
"ignoreWords": [],
"import": []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"%paratextRegistration_warning_invalid_registration%": "This registration code is not correct for this user.",
"%paratextRegistration_webView_title%": "Paratext Registration Information",
"%paratextRegistration_webView_tooltip%": "Enter your Paratext Registration Information into this form.",
"%paratextRegistration_exception_register_before_accessing_dbl_resources%": "You must provide a valid Paratext registration before opening resources from the Digital Bible Library.",
"%settings_paratextRegistration_registration_internet_group_label%": "Paratext Registration and Internet Settings",
"%settings_paratextRegistration_registration_internet_group_description%": "Settings related to the user's Paratext Registry connection and some internet access controls",
"%settings_paratextRegistration_shouldShowOnStartup_label%": "Show Paratext Registration Web View on Startup",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ declare module 'papi-shared-types' {
'paratextRegistration.setParatextRegistrationData': (
newRegistrationData: RegistrationData,
) => Promise<void>;
/**
* Gets the validity status of the user's Paratext registration
*
* @returns True if the user has a valid Paratext registration, false otherwise
*/
'command:paratextRegistration.doesUserHaveValidRegistration': () => Promise<boolean>;
}

export interface SettingTypes {
Expand Down
Loading

0 comments on commit debbc3f

Please sign in to comment.