in src/governance/client/Controllers/WorkspacesController.cs [288:404]
public async Task<IActionResult> GetJSAppBundle()
{
// There is not direct API to retrieve the original bundle that was submitted via set_jsapp.
var ccfClient = await this.CcfClientManager.GetGovClient();
JsonObject modules, endpoints;
using (HttpResponseMessage response = await ccfClient.GetAsync(
$"gov/service/javascript-modules?" +
$"api-version={this.CcfClientManager.GetGovApiVersion()}"))
{
await response.ValidateStatusCodeAsync(this.Logger);
modules = (await response.Content.ReadFromJsonAsync<JsonObject>())!;
}
using (HttpResponseMessage response = await ccfClient.GetAsync(
$"gov/service/javascript-app?" +
$"api-version={this.CcfClientManager.GetGovApiVersion()}&case=original"))
{
await response.ValidateStatusCodeAsync(this.Logger);
endpoints = (await response.Content.ReadFromJsonAsync<JsonObject>())!;
}
List<string> moduleNames = new();
List<Task<string>> fetchModuleTasks = new();
foreach (var item in modules["value"]!.AsArray().AsEnumerable())
{
var moduleName = item!.AsObject()["moduleName"]!.ToString();
moduleNames.Add(moduleName);
}
// Sort the module names in alphabetical order so that we return the response ordered by
// name.
moduleNames = moduleNames.OrderBy(x => x, StringComparer.Ordinal).ToList();
foreach (var moduleName in moduleNames)
{
var escapedString = Uri.EscapeDataString(moduleName);
Task<string> fetchModuleTask = ccfClient.GetStringAsync(
$"gov/service/javascript-modules/{escapedString}?" +
$"api-version={this.CcfClientManager.GetGovApiVersion()}");
fetchModuleTasks.Add(fetchModuleTask);
}
var endpointsInProposalFormat = new JsonObject();
foreach (KeyValuePair<string, JsonNode?> apiSpec in
endpoints["endpoints"]!.AsObject().AsEnumerable())
{
// Need to transform the endpoints output to the format that the proposal expects.
// "/contracts": {
// "GET": {
// "authnPolicies": [
// "member_cert",
// "user_cert"
// ],
// "forwardingRequired": "sometimes",
// "jsModule": "/endpoints/contracts.js",
// =>
// "/contracts": {
// "get": {
// "authn_policies": [
// "member_cert",
// "user_cert"
// ],
// "forwarding_required": "sometimes",
// "js_module": "endpoints/contracts.js",=>
string api = apiSpec.Key;
if (endpointsInProposalFormat[api] == null)
{
endpointsInProposalFormat[api] = new JsonObject();
}
foreach (KeyValuePair<string, JsonNode?> verbSpec in
apiSpec.Value!.AsObject().AsEnumerable())
{
string verb = verbSpec.Key!.ToLower();
var value = new JsonObject();
foreach (var item3 in verbSpec.Value!.AsObject().AsEnumerable())
{
value[item3.Key] = item3.Value?.DeepClone();
}
// Remove leading / ie "js_module": "/foo/bar" => "js_module": "foo/bar"
value["js_module"] = value["js_module"]!.ToString().TrimStart('/');
// The /javascript-app API is not returning mode value for PUT/POST. Need to fill it
// or else proposal submission fails.
if ((verb == "put" || verb == "post") && value["mode"] == null)
{
value["mode"] = "readwrite";
}
endpointsInProposalFormat[api]!.AsObject()[verb] = value;
}
}
await Task.WhenAll(fetchModuleTasks);
var modulesArray = new JsonArray();
for (int i = 0; i < moduleNames.Count; i++)
{
#pragma warning disable VSTHRD003 // Avoid awaiting foreign Tasks
string content = (await fetchModuleTasks[i])!;
#pragma warning restore VSTHRD003 // Avoid awaiting foreign Tasks
modulesArray.Add(new JsonObject
{
["name"] = moduleNames[i].TrimStart('/'),
["module"] = content
});
}
return this.Ok(new JsonObject
{
["metadata"] = new JsonObject
{
["endpoints"] = endpointsInProposalFormat
},
["modules"] = modulesArray
});
}