Skip to content

Commit

Permalink
Reworked PDPs to enable layering PDPs, added platform.base, added Scr…
Browse files Browse the repository at this point in the history
…ipture extender layering PDP, replaced name from ProjectMetadata with project setting platform.name
  • Loading branch information
tjcouch-sil committed Jun 7, 2024
1 parent 46b4853 commit 8b645fe
Show file tree
Hide file tree
Showing 125 changed files with 14,223 additions and 32,723 deletions.
6 changes: 6 additions & 0 deletions assets-excluded/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Currently Excluded Assets

This folder's contents:

- Folder of logos not currently used.
- `custom.sty` file containing the custom milestone used to mark comment anchors. Currently you must add this file (or append its content if the file already exists) to a project to enable comments to be anchored.
20 changes: 20 additions & 0 deletions assets-excluded/custom.sty
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# ********************************************************************
# * custom.sty is the custom stylesheet for this Paratext project *
# * using USFM markup. *
# * Latest documentation and stylesheets are maintained at: *
# * http://markups.paratext.org/usfm *
# ********************************************************************

# WARNING: Using a custom stylesheet will likely make it more difficult to publish your project
# or submit it to the Digital Bible Library (DBL), especially if you add any custom markers.

# You must copy this file to the project directory (e.g. c:\My Paratext 9 Projects\XYZ)
# for it to take effect.

\Marker zmsc-s
\Endmarker zmsc-e
\Name Custom - Platform.Bible comment anchor start/end
\Description For anchoring comments (revision notes)
\OccursUnder ip im ipi imi ipq imq ipr iq iq1 iq2 iq3 io io1 io2 io3 io4 ms ms1 ms2 s s1 s2 s3 s4 cd sp d lh li li1 li2 li3 li4 lf lim lim1 lim2 lim3 lim4 m mi nb p pc ph phi pi pi1 pi2 pi3 pr pmo pm pmc pmr po q q1 q2 q3 q4 qc qr qd qm qm1 qm2 qm3 tr th1 th2 th3 th4 thr1 thr2 thr3 thr4 tc1 tc2 tc3 tc4 tcr1 tcr2 tcr3 tcr4 f fe NEST
\StyleType Milestone
\Attributes ?who ?sid ?eid
3 changes: 3 additions & 0 deletions assets/localization/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
"%settings_platform_interfaceLanguage_label%": "Interface Language",
"%project_settings_platform_group1_label%": "Platform Settings",
"%project_settings_platform_group1_description%": "Project settings pertaining to the software overall",
"%project_settings_platform_name_label%": "Project Short Name",
"%project_name_missing%": "_NoName_",
"%project_settings_platform_fullName_label%": "Project Full Name",
"%project_full_name_missing%": "*Name Missing*",
"%project_settings_platform_language_label%": "Project Primary Language",
"%project_settings_platform_isEditable_label%": "Is Editable",
"%project_settings_platform_isEditable_description%": "Whether this project is editable. A project that is not editable is sometimes called a resource."
Expand Down
4 changes: 2 additions & 2 deletions c-sharp-tests/DummyLocalParatextProjects.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Paranext.DataProvider.Projects;
using System.Diagnostics.CodeAnalysis;
using Paranext.DataProvider.Projects;

namespace TestParanextDataProvider
{
Expand All @@ -11,7 +11,7 @@ public void FakeAddProject(ProjectDetails details)
_projectDetailsMap[details.Metadata.ID] = details;
}

public override void Initialize()
public override void Initialize(bool shouldIncludePT9ProjectsOnWindows)
{
// Nothing to do
}
Expand Down
208 changes: 139 additions & 69 deletions c-sharp-tests/DummyPapiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@
using Paranext.DataProvider.MessageHandlers;
using Paranext.DataProvider.Messages;
using Paranext.DataProvider.MessageTransports;
using Paranext.DataProvider.Projects;
using Paranext.DataProvider.Services;

namespace TestParanextDataProvider
{
[ExcludeFromCodeCoverage]
internal class DummyPapiClient : PapiClient
{
private readonly Dictionary<string, Func<MessageEvent, Message?>> _eventHandlers = new();
private readonly Dictionary<string, List<(string newValue, string oldValue)>> _validSettings = new();
private readonly Dictionary<
string,
List<(string newValue, string oldValue)>
> _validSettings = new();

public Stack<Message?> EventMessages { get; } = new();

Expand All @@ -32,7 +35,11 @@ public IEnumerable<Message> FakeMessageFromServer(Message message)
return handler.HandleMessage(message);
}

public void AddSettingValueToTreatAsValid(string pbSettingName, string newValue, string oldValue)
public void AddSettingValueToTreatAsValid(
string pbSettingName,
string newValue,
string oldValue
)
{
if (!_validSettings.TryGetValue(pbSettingName, out var values))
{
Expand Down Expand Up @@ -91,89 +98,152 @@ public override void SendEvent(MessageEvent message)
EventMessages.Push(result);
}

public override void SendRequest(string requestType, object requestContents,
Action<bool, object?> responseCallback)
public override void SendRequest(
string requestType,
object requestContents,
Action<bool, object?> responseCallback
)
{
Task.Delay(1).ContinueWith(async _ =>
{
bool success = false;
object? result = null;
if ((requestType == "object:ProjectSettingsService.function") &&
(requestContents is string[] details) &&
(details.Length > 2))
Task.Delay(1)
.ContinueWith(async _ =>
{
// If this is a setting known to both Platform.Bible and Paratext, do the
// translation from the Paratext settings key to the PB setting id.
// If it's a custom settings key, then perhaps it's one we've registered to
// handle, and no translation is needed.
var ourSettingName = details[1];
var pbSettingName = ProjectSettings
.GetPlatformBibleSettingNameFromParatextSettingName(ourSettingName);
if (ourSettingName != null)
bool success = false;
object? result = null;
// Try to run registered request handlers
var responder = (MessageHandlerRequestByRequestType)
_messageHandlersByMessageType[MessageType.REQUEST];
var requestMessage =
(requestContents is JsonElement jse)
? new MessageRequest(requestType, 0, jse)
: new MessageRequest(requestType, 0, requestContents);
var response = responder.HandleMessage(requestMessage);
// There should be just one response message
if (response.Count() > 1)
throw new Exception(
$"Somehow there were multiple response messages for request {requestType}"
);
// If there were no responses, there isn't a registered request handler
if (response.Count() == 1)
{
switch (details[0])
if (response.First() is MessageResponse messageResponse)
{
case "isValid":
if (details.Length == 6 && details[4] == ProjectType.Paratext)
{
success = true;
// Might be a setting we've registered to handle.
var isValidRequestContents = new []
{details[2], details[3], details[5]};
if (TryValidationUsingRegisteredHandler(isValidRequestContents,
ourSettingName, out var isValid))
{
result = isValid;
}
else if (pbSettingName == null)
success = messageResponse.Success;
result = messageResponse.Contents;
}
else
{
throw new Exception(
$"Somehow the message handler for {requestType} responded with a message that was not a MessageResponse"
);
}
}
// Special hard-coded request handlers. We should probably try to get rid of these over time
else if (
(requestType == "object:ProjectSettingsService.function")
&& (requestContents is object[] details)
&& (details.Length >= 2)
)
{
// If this is a setting known to both Platform.Bible and Paratext, do the
// translation from the Paratext settings key to the PB setting id.
// If it's a custom settings key, then perhaps it's one we've registered to
// handle, and no translation is needed.
var ourSettingName = (string)details[1];
var pbSettingName =
ProjectSettings.GetPlatformBibleSettingNameFromParatextSettingName(
ourSettingName
);
if (ourSettingName != null)
{
switch (details[0])
{
case "isValid":
if (details.Length == 5)
{
// Per comment in isValid (in
// project-settings.service-host.ts), if there is no
// validator just let the change go through
result = true;
success = true;
// Might be a setting we've registered to handle.
var isValidRequestContents = new[]
{
// From ProjectSettingsService.IsValid
// new value
details[2],
// current value
details[3],
// all changes?
details[4]
};
if (
TryValidationUsingRegisteredHandler(
isValidRequestContents,
ourSettingName,
out var isValid
)
)
{
result = isValid;
}
else if (pbSettingName == null)
{
// Per comment in isValid (in
// project-settings.service-host.ts), if there is no
// validator just let the change go through
result = true;
}
else
{
result =
_validSettings.TryGetValue(
pbSettingName,
out var validValues
)
&& validValues.Any(vv =>
vv.newValue == (string)details[2]
&& vv.oldValue == (string)details[3]
);
}
}
else
break;
case "getDefault":
if (details.Length == 2 && pbSettingName != null)
{
result = _validSettings.TryGetValue(pbSettingName,
out var validValues) && validValues.Any(vv =>
vv.newValue == details[2] &&
vv.oldValue == details[3]);
success = true;
result = $"default value for {pbSettingName}";
}
}
break;
case "getDefault":
if (details.Length == 3 &&
details[2] == ProjectType.Paratext &&
pbSettingName != null)
{
success = true;
result = $"default value for {pbSettingName}";
}
break;
default:
break;
break;
default:
break;
}
}
}
}
// Otherwise we didn't find a request handler, so it should just be a request
// failure. Can keep the original values
await Task.Run(() => responseCallback(success,
JsonSerializer.SerializeToElement(result)));
});
await Task.Run(
() => responseCallback(success, JsonSerializer.SerializeToElement(result))
);
});
}

private bool TryValidationUsingRegisteredHandler(string[] requestContents, string settingName,
out bool isValid)
private bool TryValidationUsingRegisteredHandler(
object[] requestContents,
string settingName,
out bool isValid
)
{
isValid = true;
if (!_messageHandlersByMessageType.TryGetValue(
MessageType.REQUEST, out var responder))
if (!_messageHandlersByMessageType.TryGetValue(MessageType.REQUEST, out var responder))
return false;

var msgRequest = new MessageRequest(ProjectSettingsService.GetValidatorKey(settingName),
GetRequestId(), requestContents);
var responseMsg = responder.HandleMessage(msgRequest).OfType<MessageResponse>()
var msgRequest = new MessageRequest(
ProjectSettingsService.GetValidatorKey(settingName),
GetRequestId(),
requestContents
);
var responseMsg = responder
.HandleMessage(msgRequest)
.OfType<MessageResponse>()
.FirstOrDefault();

if (responseMsg == null)
Expand Down
50 changes: 50 additions & 0 deletions c-sharp-tests/NetworkObjects/DummySettingsService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Nodes;
using Paranext.DataProvider.MessageHandlers;
using Paranext.DataProvider.MessageTransports;
using Paranext.DataProvider.NetworkObjects;
using Paranext.DataProvider.Services;

namespace TestParanextDataProvider;

[ExcludeFromCodeCoverage]
internal class DummySettingsService : DataProvider
{
private readonly Dictionary<string, object> _settingValues = [];
private readonly List<string> _supportedFunctions = ["get"];

public DummySettingsService(PapiClient papiClient)
: base(SettingsService.SETTINGS_SERVICE_NAME, papiClient) { }

public void AddSettingValue(string key, object value)
{
_settingValues.Add(key, value);
}

public void ClearSettingValues()
{
_settingValues.Clear();
}

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

protected override List<string> GetFunctionNames()
{
return _supportedFunctions;
}

protected override ResponseToRequest HandleRequest(string functionName, JsonArray args)
{
return functionName switch
{
"get"
=> _settingValues.ContainsKey(args[0]!.ToString())
? ResponseToRequest.Succeeded(_settingValues[args[0]!.ToString()])
: ResponseToRequest.Failed($"Could not find value for setting {args[0]}"),
_ => ResponseToRequest.Failed($"Unexpected function: {functionName}")
};
}
}
11 changes: 7 additions & 4 deletions c-sharp-tests/PapiTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@ internal abstract class PapiTestBase
#endregion

#region Test setup/teardown
// Ignore warning here because child classes need this to be async
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
[SetUp]
public virtual void TestSetup()
public virtual async Task TestSetup()
{
if (OperatingSystem.IsMacOS())
Assert.Ignore("Mac is missing ICU support so these tests will not work");

_projects = new DummyLocalParatextProjects();
_client = new DummyPapiClient();
}
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously

[TearDown]
public virtual void TestTearDown()
Expand Down Expand Up @@ -97,11 +100,11 @@ protected static ProjectDetails CreateProjectDetails(ScrText scrText)
protected static ProjectDetails CreateProjectDetails(
string id,
string name,
string projectType = ""
List<string>? projectInterfaces = null
)
{
ProjectMetadata metadata = new(id, name, projectType);
return new ProjectDetails(metadata, "testDirectoryThatDoesNotExist");
ProjectMetadata metadata = new(id, projectInterfaces ?? []);
return new ProjectDetails(name, metadata, "testDirectoryThatDoesNotExist");
}

/// <summary>
Expand Down
Loading

0 comments on commit 8b645fe

Please sign in to comment.