From b92d2a546f19b95046258e2a1312cd66184d67d5 Mon Sep 17 00:00:00 2001 From: Rushiraj Nenuji <19696935+rushirajnenuji@users.noreply.github.com> Date: Mon, 18 Dec 2023 19:34:07 +0530 Subject: [PATCH 1/3] Return serialized XML objects instead of String Return serialized XML objects instead of String Reference: https://github.com/NCEAS/metacatui/issues/2235 --- src/js/collections/AccessPolicy.js | 35 ++++++++------- src/js/models/AccessRule.js | 69 ++++++++++++++---------------- 2 files changed, 49 insertions(+), 55 deletions(-) diff --git a/src/js/collections/AccessPolicy.js b/src/js/collections/AccessPolicy.js index 7efe4703c..93222e1b4 100644 --- a/src/js/collections/AccessPolicy.js +++ b/src/js/collections/AccessPolicy.js @@ -124,28 +124,27 @@ define(["jquery", "underscore", "backbone", "models/AccessRule"], }, /** - * Creates an access policy XML from the values set on the member - * AccessRule models. - * @return {string} A string of the access policy XML - */ - serialize: function(){ - - if( this.length == 0 ) - return ""; + * Creates an access policy XML from the values set on the member + * AccessRule models. + * @returns {object} A XML object of the access policy or null if empty + */ + serialize: function() { + if (this.length === 0) { + return null; + } - //Create the access policy node which will contain all the rules - var xml = "\n"; + // Create the access policy node which will contain all the rules + var accessPolicyElement = document.createElement('accesspolicy'); - //Serialize each AccessRule member model and add to the policy DOM - this.each(function(accessRule){ - xml += accessRule.serialize(); + // Serialize each AccessRule member model and add to the policy DOM + this.each(function(accessRule) { + var accessRuleNode = accessRule.serialize(); + if (accessRuleNode) { + accessPolicyElement.appendChild(accessRuleNode); + } }); - xml += "\n" - - //Convert the access policy DOM to a string and return it - return xml; - + return accessPolicyElement; }, /** diff --git a/src/js/models/AccessRule.js b/src/js/models/AccessRule.js index 2bb6ade4c..108a2bd5d 100644 --- a/src/js/models/AccessRule.js +++ b/src/js/models/AccessRule.js @@ -53,46 +53,41 @@ define(['jquery', 'underscore', 'backbone'], }, /** - * Takes the values set on this model's attributes and creates an XML string - * to be inserted into a DataONEObject's system metadata access policy. - * @return {string} The access rule XML string - */ - serialize: function(){ - - var xml = ""; - - //Serialize the allow rules - if( this.get("read") || this.get("write") || this.get("changePermission") ){ - - //Start the "allow" node - xml += '\t\n'; - - //Add the subject - xml += '\t\t' + this.get("subject") + '\n'; - - //Add the read permission - if( this.get("read") ){ - xml += '\t\tread\n'; - } - - //Add the write permission - if( this.get("write") ){ - xml += '\t\twrite\n'; - } - - //Add the changePermission permission - if( this.get("changePermission") ){ - xml += '\t\tchangePermission\n'; - } - - //Close the "allow" node - xml += '\t\n'; + * Takes the values set on this model's attributes and creates an XML string + * to be inserted into a DataONEObject's system metadata access policy. + * @returns {object} The access rule XML object or null if not created + */ + serialize: function() { + // Serialize the allow rules + if (this.get("read") || this.get("write") || this.get("changePermission")) { + // Create the element + var allowElement = document.createElement('allow'); + + // Create the element and set its text content + var subjectElement = document.createElement('subject'); + subjectElement.textContent = this.get("subject"); + + // Append the and elements to + allowElement.appendChild(subjectElement); + + // Create the elements and set their text content + var permissions = ['read', 'write', 'changePermission']; + for (var i = 0; i < permissions.length; i++) { + if (this.get(permissions[i])) { + var permissionElement = document.createElement('permission'); + permissionElement.textContent = permissions[i]; + allowElement.appendChild(permissionElement); + } + } - } + // Return the element + return allowElement; + } - return xml; + // If no access rule is created, return null + return null; + }, - }, /** * Gets and sets the subject info for the subjects in this access policy. From 7b4c7d9177fa80518663426b260669dadc1e8dc0 Mon Sep 17 00:00:00 2001 From: Rushiraj Nenuji <19696935+rushirajnenuji@users.noreply.github.com> Date: Tue, 19 Dec 2023 19:38:26 +0530 Subject: [PATCH 2/3] Update AccessRule model Update AccessRule model to parse garbled XML Reference #2235 --- src/js/models/AccessRule.js | 65 +++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/src/js/models/AccessRule.js b/src/js/models/AccessRule.js index 108a2bd5d..f443b008d 100644 --- a/src/js/models/AccessRule.js +++ b/src/js/models/AccessRule.js @@ -28,29 +28,58 @@ define(['jquery', 'underscore', 'backbone'], }, /** - * Translates the access rule XML DOM into a JSON object to be set on the model. - * @param {Element} accessRuleXML An DOM element that contains a single access rule - * @return {JSON} The Access Rule values to be set on this model - */ - parse: function( accessRuleXML ){ - //If there is no access policy, do not attempt to parse anything - if( typeof accessRuleXML == "undefined" || !accessRuleXML) - return {}; + * Translates the access rule XML DOM into a JSON object to be set on the model. + * @param {Element} accessRuleXML An DOM element that contains a single access rule + * @return {JSON} The Access Rule values to be set on this model + */ + parse: function(accessRuleXML) { + // If there is no access policy, do not attempt to parse anything + if (typeof accessRuleXML === "undefined" || !accessRuleXML) { + return {}; + } - accessRuleXML = $(accessRuleXML); + var accessRuleXMLObj = $(accessRuleXML); - //Start an access rule object with the given subject - var parsedAccessRule = { - subject: accessRuleXML.find("subject").text() - } + // Start an access rule object with the given subject + var parsedAccessRule = { + subject: accessRuleXMLObj.find("subject").text() + }; - _.each( accessRuleXML.find("permission"), function( permissionNode ){ - parsedAccessRule[ $(permissionNode).text() ] = true; - }); + _.each(accessRuleXMLObj.find("permission"), function(permissionNode, idx) { + let permissionText = $(permissionNode).text().trim(); - return parsedAccessRule; + // Check if the permission text is not empty + if (permissionText.length) { + // Save the parsed permission + parsedAccessRule[permissionText] = true; + } else { + // This is added as a workaround for malformed permission XML + // introduced by Chromium 120.X + // See https://github.com/NCEAS/metacatui/issues/2235 - }, + // Define the regular expression + let globalPermRegex = /<\/permission>(.*)/g; + // Define the regular expression + let permRegex = /<\/permission>(.*)/; + + let accessRoleStr = accessRuleXMLObj.html(); + + let matches = accessRoleStr.match(globalPermRegex); + + // Check if matches exist and have a length + if (matches && matches.length && idx < matches.length) { + let permMatch = matches[idx].match(permRegex); + + // Check if permMatch exists and has a length + if (permMatch && permMatch.length) { + parsedAccessRule[permMatch[1]] = true; + } + } + } + }); + + return parsedAccessRule; + }, /** * Takes the values set on this model's attributes and creates an XML string From 758ff8e3710637d9fdf406a9c2383e56ff5be877 Mon Sep 17 00:00:00 2001 From: Robyn Thiessen-Bock Date: Tue, 19 Dec 2023 14:21:56 -0500 Subject: [PATCH 3/3] Update version to 2.27.1 and rebuild docs --- README.md | 2 +- docs/_config.yml | 2 +- docs/docs/AccessPolicy.html | 22 +-- docs/docs/AccessRule.html | 12 +- .../src_js_collections_AccessPolicy.js.html | 35 +++-- docs/docs/src_js_models_AccessRule.js.html | 126 +++++++++++------- docs/index.md | 2 +- package.json | 2 +- src/index.html | 2 +- 9 files changed, 114 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index af37378e1..cae39c75e 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ MetacatUI is an open source, community project. We [welcome contributions](http Cite this software as: -> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix. 2022. MetacatUI: A client-side web interface for DataONE data repositories (version 2.27.0). Arctic Data Center. [doi:10.18739/A25M6282K](https://doi.org/10.18739/A25M6282K) +> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix. 2023. MetacatUI: A client-side web interface for DataONE data repositories (version 2.27.1). Arctic Data Center. [doi:10.18739/A25M6282K](https://doi.org/10.18739/A25M6282K) ## Screenshots diff --git a/docs/_config.yml b/docs/_config.yml index f0b94ecb6..72dd93506 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,3 +1,3 @@ url: "/metacatui" highlighter: "rouge" -version: "2.27.0" +version: "2.27.1" diff --git a/docs/docs/AccessPolicy.html b/docs/docs/AccessPolicy.html index d25c63484..b1c57e29e 100644 --- a/docs/docs/AccessPolicy.html +++ b/docs/docs/AccessPolicy.html @@ -564,7 +564,7 @@

Source:
@@ -659,7 +659,7 @@

Source:
@@ -822,7 +822,7 @@

Parameters:
Source:
@@ -944,7 +944,7 @@

Source:
@@ -1057,7 +1057,7 @@

Source:
@@ -1170,7 +1170,7 @@

Source:
@@ -1265,7 +1265,7 @@

Source:
@@ -1553,7 +1553,7 @@

Parameters:
Source:
@@ -1594,7 +1594,7 @@

- serialize() → {string} + serialize() → {object}

@@ -1677,7 +1677,7 @@
Returns:
- A string of the access policy XML + A XML object of the access policy or null if empty
@@ -1688,7 +1688,7 @@
Returns:
-string +object
diff --git a/docs/docs/AccessRule.html b/docs/docs/AccessRule.html index 814f34118..3576b4611 100644 --- a/docs/docs/AccessRule.html +++ b/docs/docs/AccessRule.html @@ -234,7 +234,7 @@

Source:
@@ -328,7 +328,7 @@

Source:
@@ -552,7 +552,7 @@

- serialize() → {string} + serialize() → {object}

@@ -606,7 +606,7 @@

Source:
@@ -635,7 +635,7 @@

Returns:
- The access rule XML string + The access rule XML object or null if not created
@@ -646,7 +646,7 @@
Returns:
-string +object
diff --git a/docs/docs/src_js_collections_AccessPolicy.js.html b/docs/docs/src_js_collections_AccessPolicy.js.html index b8dfd9fb6..33f9633dd 100644 --- a/docs/docs/src_js_collections_AccessPolicy.js.html +++ b/docs/docs/src_js_collections_AccessPolicy.js.html @@ -170,28 +170,27 @@

Source: src/js/collections/AccessPolicy.js

}, /** - * Creates an access policy XML from the values set on the member - * AccessRule models. - * @return {string} A string of the access policy XML - */ - serialize: function(){ - - if( this.length == 0 ) - return ""; + * Creates an access policy XML from the values set on the member + * AccessRule models. + * @returns {object} A XML object of the access policy or null if empty + */ + serialize: function() { + if (this.length === 0) { + return null; + } - //Create the access policy node which will contain all the rules - var xml = "<accessPolicy>\n"; + // Create the access policy node which will contain all the rules + var accessPolicyElement = document.createElement('accesspolicy'); - //Serialize each AccessRule member model and add to the policy DOM - this.each(function(accessRule){ - xml += accessRule.serialize(); + // Serialize each AccessRule member model and add to the policy DOM + this.each(function(accessRule) { + var accessRuleNode = accessRule.serialize(); + if (accessRuleNode) { + accessPolicyElement.appendChild(accessRuleNode); + } }); - xml += "\n</accessPolicy>" - - //Convert the access policy DOM to a string and return it - return xml; - + return accessPolicyElement; }, /** diff --git a/docs/docs/src_js_models_AccessRule.js.html b/docs/docs/src_js_models_AccessRule.js.html index 3a08e29c8..e7c040418 100644 --- a/docs/docs/src_js_models_AccessRule.js.html +++ b/docs/docs/src_js_models_AccessRule.js.html @@ -74,71 +74,95 @@

Source: src/js/models/AccessRule.js

}, /** - * Translates the access rule XML DOM into a JSON object to be set on the model. - * @param {Element} accessRuleXML An <allow> DOM element that contains a single access rule - * @return {JSON} The Access Rule values to be set on this model - */ - parse: function( accessRuleXML ){ - //If there is no access policy, do not attempt to parse anything - if( typeof accessRuleXML == "undefined" || !accessRuleXML) - return {}; - - accessRuleXML = $(accessRuleXML); - - //Start an access rule object with the given subject - var parsedAccessRule = { - subject: accessRuleXML.find("subject").text() - } - - _.each( accessRuleXML.find("permission"), function( permissionNode ){ - parsedAccessRule[ $(permissionNode).text() ] = true; - }); + * Translates the access rule XML DOM into a JSON object to be set on the model. + * @param {Element} accessRuleXML An <allow> DOM element that contains a single access rule + * @return {JSON} The Access Rule values to be set on this model + */ + parse: function(accessRuleXML) { + // If there is no access policy, do not attempt to parse anything + if (typeof accessRuleXML === "undefined" || !accessRuleXML) { + return {}; + } - return parsedAccessRule; + var accessRuleXMLObj = $(accessRuleXML); - }, + // Start an access rule object with the given subject + var parsedAccessRule = { + subject: accessRuleXMLObj.find("subject").text() + }; - /** - * Takes the values set on this model's attributes and creates an XML string - * to be inserted into a DataONEObject's system metadata access policy. - * @return {string} The access rule XML string - */ - serialize: function(){ + _.each(accessRuleXMLObj.find("permission"), function(permissionNode, idx) { + let permissionText = $(permissionNode).text().trim(); - var xml = ""; + // Check if the permission text is not empty + if (permissionText.length) { + // Save the parsed permission + parsedAccessRule[permissionText] = true; + } else { + // This is added as a workaround for malformed permission XML + // introduced by Chromium 120.X + // See https://github.com/NCEAS/metacatui/issues/2235 - //Serialize the allow rules - if( this.get("read") || this.get("write") || this.get("changePermission") ){ + // Define the regular expression + let globalPermRegex = /<permission><\/permission>(.*)/g; + // Define the regular expression + let permRegex = /<permission><\/permission>(.*)/; - //Start the "allow" node - xml += '\t<allow>\n'; + let accessRoleStr = accessRuleXMLObj.html(); - //Add the subject - xml += '\t\t<subject>' + this.get("subject") + '</subject>\n'; + let matches = accessRoleStr.match(globalPermRegex); - //Add the read permission - if( this.get("read") ){ - xml += '\t\t<permission>read</permission>\n'; - } + // Check if matches exist and have a length + if (matches && matches.length && idx < matches.length) { + let permMatch = matches[idx].match(permRegex); - //Add the write permission - if( this.get("write") ){ - xml += '\t\t<permission>write</permission>\n'; - } + // Check if permMatch exists and has a length + if (permMatch && permMatch.length) { + parsedAccessRule[permMatch[1]] = true; + } + } + } + }); - //Add the changePermission permission - if( this.get("changePermission") ){ - xml += '\t\t<permission>changePermission</permission>\n'; - } + return parsedAccessRule; + }, - //Close the "allow" node - xml += '\t</allow>\n'; + /** + * Takes the values set on this model's attributes and creates an XML string + * to be inserted into a DataONEObject's system metadata access policy. + * @returns {object} The access rule XML object or null if not created + */ + serialize: function() { + // Serialize the allow rules + if (this.get("read") || this.get("write") || this.get("changePermission")) { + // Create the <allow> element + var allowElement = document.createElement('allow'); + + // Create the <subject> element and set its text content + var subjectElement = document.createElement('subject'); + subjectElement.textContent = this.get("subject"); + + // Append the <subject> and <permission> elements to <allow> + allowElement.appendChild(subjectElement); + + // Create the <permission> elements and set their text content + var permissions = ['read', 'write', 'changePermission']; + for (var i = 0; i < permissions.length; i++) { + if (this.get(permissions[i])) { + var permissionElement = document.createElement('permission'); + permissionElement.textContent = permissions[i]; + allowElement.appendChild(permissionElement); + } + } - } + // Return the <allow> element + return allowElement; + } - return xml; + // If no access rule is created, return null + return null; + }, - }, /** * Gets and sets the subject info for the subjects in this access policy. diff --git a/docs/index.md b/docs/index.md index cc3a44a34..8f99ba8c0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,7 +22,7 @@ MetacatUI is an open source, community project. We [welcome contributions](http Cite this software as: -> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix. 2022. MetacatUI: A client-side web interface for DataONE data repositories (version 2.24.0). Arctic Data Center. [doi:10.18739/A25M6282K](https://doi.org/10.18739/A25M6282K) +> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix. 2023. MetacatUI: A client-side web interface for DataONE data repositories (version 2.27.1). Arctic Data Center. [doi:10.18739/A25M6282K](https://doi.org/10.18739/A25M6282K) ## Related Projects diff --git a/package.json b/package.json index a48ee0062..59a498086 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metacatui", - "version": "2.27.0", + "version": "2.27.1", "description": "MetacatUI: A client-side web interface for DataONE data repositories", "main": "server.js", "dependencies": { diff --git a/src/index.html b/src/index.html index 1e01d7c0a..e28552077 100644 --- a/src/index.html +++ b/src/index.html @@ -44,7 +44,7 @@ //Create the MetacatUI object var MetacatUI = {}; - MetacatUI.metacatUIVersion = "2.27.0"; + MetacatUI.metacatUIVersion = "2.27.1"; //Catch errors when the config or loader file fails to load. // These are mainly helpful for developers/operators installing MetacatUI