diff --git a/CHANGELOG.md b/CHANGELOG.md index 60242d138a183f92ba46b1be036839b3100ff354..fa2da0342f10310d282f32a75b28c47b95cb1255 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added (for new features, dependecies etc.) +* Change password functionality for users of the internal user source. * Visually highlighted drop zones for properties and parents in the edit_mode. * two new field types for the form_elements module, `file` and `select`. See the module documentation for more information. diff --git a/build.properties.d/00_default.properties b/build.properties.d/00_default.properties index cb0a89ce6d5cf991de67b9063caaf4349e34b59d..482913473a8d2620a4484b69424aab82e52e48f3 100644 --- a/build.properties.d/00_default.properties +++ b/build.properties.d/00_default.properties @@ -51,6 +51,9 @@ BUILD_MODULE_EXT_BOTTOM_LINE_TABLE_PREVIEW=DISABLED BUILD_MODULE_EXT_BOTTOM_LINE_TIFF_PREVIEW=DISABLED BUILD_MODULE_EXT_BOOKMARKS=ENABLED +BUILD_MODULE_USER_MANAGEMENT=ENABLED +BUILD_MODULE_USER_MANAGEMENT_CHANGE_OWN_PASSWORD_REALM=CaosDB + ############################################################################## # Navbar properties ############################################################################## diff --git a/src/core/js/webcaosdb.js b/src/core/js/webcaosdb.js index d6ae7825107fb0d39e1b46e925984c3b5da299eb..f5f65b93ca3722f58914ae4fee86f73ce5d83fc1 100644 --- a/src/core/js/webcaosdb.js +++ b/src/core/js/webcaosdb.js @@ -164,7 +164,7 @@ this.navbar = new function () { * hides again. When the user starts typing, the timeout is canceled. * * If the user leaves the input fields ("blur" event) the timeout is - * reestablished and the form hides after 10 seconds. + * reestablished and the form hides after 20 seconds. */ this.init_login_show_button = function () { const form = $("#caosdb-f-login-form"); @@ -173,32 +173,32 @@ this.navbar = new function () { // show form and hide the show_button const _in = () => { - // xs means viewport <= 768px - form.removeClass("visible-xs-inline-block"); - show_button.addClass("hidden"); + // xs means viewport <= 768px + form.removeClass("visible-xs-inline-block"); + show_button.addClass("hidden"); } // hide form and show the show_button const _out = () => { - // xs means viewport <= 768px - form.addClass("visible-xs-inline-block"); - show_button.removeClass("hidden"); + // xs means viewport <= 768px + form.addClass("visible-xs-inline-block"); + show_button.removeClass("hidden"); } show_button.on("click", () => { // show form... _in(); // and hide it after ten seconds if nothing happens - timeout = setTimeout(_out,10000) + timeout = setTimeout(_out, 10000) }); form.find("input,button").on("blur", () => { if (timeout) { // cancel existing timeout (e.g. from showing) clearTimeout(timeout); } - // hide after 10 seconds if nothing happens - timeout = setTimeout(_out,10000) + // hide after 20 seconds if nothing happens + timeout = setTimeout(_out, 20000) }); - form.find("input,button").on("change", () => { + form.find("input,button").on("input", () => { // something happens! if (timeout) { clearTimeout(timeout); @@ -344,8 +344,8 @@ this.caosdb_utils = new function () { * @param {string} [newline="%0A"] - the row separator. * @return {string} a tsv table as a string. */ - this.create_tsv_table = function(data, preamble, tab, newline) { - preamble = ((typeof preamble == 'undefined') ? "data:text/csv;charset=utf-8,": preamble); + this.create_tsv_table = function (data, preamble, tab, newline) { + preamble = ((typeof preamble == 'undefined') ? "data:text/csv;charset=utf-8," : preamble); tab = tab || "%09"; newline = newline || "%0A"; const rows = data.map(x => x.join(tab)) @@ -1002,7 +1002,7 @@ var version_history = new function () { * @param {string} entity - the entity id with or without version id. * @return {HTMLElement} A table with the version history. */ - this.retrieve_history = async function(entity) { + this.retrieve_history = async function (entity) { const xml = this._get(transaction .generateEntitiesUri([entity]) + "?H"); const html = (await transformation.transformEntities(xml))[0]; @@ -1059,8 +1059,8 @@ var version_history = new function () { this.get_history_tsv = function (history_table) { const rows = []; for (let row of $(history_table).find("tr")) { - const cells = $(row).find(".export-data").toArray().map(x => x.textContent); - rows.push(cells); + const cells = $(row).find(".export-data").toArray().map(x => x.textContent); + rows.push(cells); } return caosdb_utils.create_tsv_table(rows); } @@ -1079,7 +1079,7 @@ var version_history = new function () { this.init_export_history_buttons = function (entity) { entity = entity || $(".caosdb-entity-panel"); for (let version_info of $(entity) - .find(".caosdb-f-entity-version-info")) { + .find(".caosdb-f-entity-version-info")) { $(version_info).find(".caosdb-f-entity-version-export-history-btn") .click(async () => { const html_table = $(version_info).find("table")[0]; @@ -1089,7 +1089,7 @@ var version_history = new function () { } } - this._download_tsv = function(tsv_link) { + this._download_tsv = function (tsv_link) { window.location.href = tsv_link; } @@ -1339,7 +1339,7 @@ var queryForm = new function () { $("#caosdb-query-textarea").on("keydown", (e) => { // prevent submit on enter - if(e.originalEvent.which == 13) { + if (e.originalEvent.which == 13) { e.originalEvent.preventDefault(); } }) @@ -1717,6 +1717,142 @@ function insertParam(xsl, name, value = null) { xsl.firstElementChild.append(param); } + +this.user_management = function ($, connection, createWaitingNotification, createErrorNotification) { + + const set_new_password = function (realm, username, password) { + return $.ajax({ + type: "PUT", + url: connection.getBasePath() + `User/${realm}/${username}`, + dataType: "xml", + data: { + password: password, + }, + }); + } + + /** + * Get the modal with the password form, if present. + * + * @return {HTMLElement} + */ + const get_change_password_form = function () { + const modal = $("#caosdb-f-change-password-form"); + return modal[0]; + } + + const init_change_password_form = function () { + var modal = get_change_password_form(); + if (typeof modal == "undefined") { + return; + } + modal = $(modal); + + const form = modal.find("form"); + const password_input = form[0]["password"]; + const password_input2 = form[0]["password2"]; + const realm_input = form[0]["realm"]; + const username_input = form[0]["username"]; + const checkbox = form.find("[type='checkbox']"); + const reset_button = modal.find("[type='reset']"); + + reset_button.click(() => { + // hide form + modal.modal("hide"); + $(password_input).attr("type", "password"); + $(password_input2).attr("type", "password"); + checkbox.checked = false; + }); + + checkbox.change((e) => { + if (checkbox[0].checked) { + $(password_input).attr("type", "text"); + $(password_input2).attr("type", "text"); + } else { + $(password_input).attr("type", "password"); + $(password_input2).attr("type", "password"); + } + }) + + form[0].onsubmit = function (e) { + e.preventDefault(); + if (password_input.value == password_input2.value) { + const password = password_input.value; + const username = username_input.value; + const realm = realm_input.value; + form[0].reset(); + form.find(".modal-body > *, .modal-footer > *").hide() + const wait = createWaitingNotification("Please wait..."); + form.find(".modal-body").append(wait); + user_management.set_new_password(realm, username, password) + .then((result) => { + wait.remove(); + + const msg = $('<p>Success! The new password has been stored.</p>'); + form.find(".modal-body") + .append(msg); + + const ok_button = $('<button type="reset">Ok</button>'); + form.find(".modal-footer") + .append(ok_button); + + ok_button.click(() => { + ok_button.remove(); + msg.remove(); + form.find(".modal-body > *, .modal-footer > *").show(1000); + modal.modal("hide"); + }); + }) + .catch((err) => { + wait.remove(); + console.error(err); + + var msg_text; + if (err.status == 403) { + msg_text = "You are not allowed to do this."; + } else if (err.status == 422) { + msg_text = "Your password was too weak."; + } else { + msg_text = "An unknown error occurred."; + } + const msg = createErrorNotification(msg_text) + form.find(".modal-body").append(msg); + + const ok_button = $('<button type="reset">Ok</button>'); + form.find(".modal-footer") + .append(ok_button); + + ok_button.click(() => { + ok_button.remove(); + msg.remove(); + form.find(".modal-body > *, .modal-footer > *").show(1000); + modal.modal("hide"); + }); + }) + .catch(globalError); + + return false; + } else { + password_input2.setCustomValidity('The second password must match the first one.'); + password_input2.reportValidity(); + password_input2.setCustomValidity(''); + } + return false; + }; + + } + + var init = function () { + init_change_password_form(); + } + + return { + init: init, + set_new_password: set_new_password, + get_change_password_form: get_change_password_form, + }; +}($, connection, createWaitingNotification, createErrorNotification); + /** * When the page is scrolled down 100 pixels, the scroll-back button appears. * @@ -1753,6 +1889,9 @@ function initOnDocumentReady() { navbar.init(); version_history.init(); + if ("${BUILD_MODULE_USER_MANAGEMENT}" == "ENABLED") { + caosdb_modules.register(user_management); + } } @@ -1811,4 +1950,4 @@ class _CaosDBModules { var caosdb_modules = new _CaosDBModules() -$(document).ready(initOnDocumentReady); +$(document).ready(initOnDocumentReady); \ No newline at end of file diff --git a/src/core/xsl/navbar.xsl b/src/core/xsl/navbar.xsl index 6ce69e638efda10dbb95a066e8b59508854a4435..3c4ae26ae93a672acaa24bcbb3d70fb05a86640c 100644 --- a/src/core/xsl/navbar.xsl +++ b/src/core/xsl/navbar.xsl @@ -46,6 +46,12 @@ <xsl:if test="count(/Response/*)<2 and not(/Response/Error|/Response/Info|/Response/Warning)"> <xsl:attribute name="class">caosdb-welcome</xsl:attribute> </xsl:if> + <xsl:if test="/Response/@realm='${BUILD_MODULE_USER_MANAGEMENT_CHANGE_OWN_PASSWORD_REALM}'"> + <xsl:call-template name="change-password-modal"> + <xsl:with-param name="realm"><xsl:value-of select="/Response/@realm"/></xsl:with-param> + <xsl:with-param name="username"><xsl:value-of select="/Response/@username"/></xsl:with-param> + </xsl:call-template> + </xsl:if> <!-- Now the header follows. --> <nav class="navbar navbar-default navbar-fixed-top"> <div class="container-fluid"> @@ -185,6 +191,46 @@ <xsl:apply-templates select="Roles/Role"/> </div> </xsl:template> + <xsl:template name="change-password-modal"> + <xsl:param name="realm"/> + <xsl:param name="username"/> + <div id="caosdb-f-change-password-form" class="modal fade" role="dialog"> + <div class="modal-dialog"> + <form class="modal-content" method="PUT"> + <input type="hidden" name="realm"><xsl:attribute name="value"><xsl:value-of select="$realm"/></xsl:attribute></input> + <input type="hidden" name="username"><xsl:attribute name="value"><xsl:value-of select="$username"/></xsl:attribute></input> + <div class="modal-header"> + <h4 class="modal-title">Set a new password</h4> + </div> + <div class="modal-body"> + <div class="form-group"> + <label>New Password + <input class="form-control" type="password" name="password" required="required"> + <xsl:attribute name="pattern">(?=.*[_\W])(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}</xsl:attribute> + <xsl:attribute name="title">The new password must contain at least 8 characters, an uppercase letter (A-Z), a lowercase letter (a-z), a number (0-9), and a special character (!#$%'*+,-./:;?^_{|}~)</xsl:attribute> + </input> + </label> + </div> + <div class="form-group"> + <label>Repeat + <input class="form-control" type="password" name="password2" required="required"/> + </label> + </div> + <div class="checkbox"> + <label> + <input type="checkbox"/> + Show password + </label> + </div> + </div> + <div class="modal-footer"> + <button type="reset" class="btn btn-default" >Cancel</button> + <button type="submit" class="btn btn-default" >Submit</button> + </div> + </form> + </div> + </div> + </xsl:template> <xsl:template name="caosdb-user-menu"> <xsl:choose> <xsl:when test="/Response/@username"> @@ -195,6 +241,11 @@ <span class="caret"></span> </a> <ul class="dropdown-menu"> + <xsl:if test="/Response/@realm='${BUILD_MODULE_USER_MANAGEMENT_CHANGE_OWN_PASSWORD_REALM}'"> + <li> + <a title="Change your password." href="#" data-toggle="modal" data-target="#caosdb-f-change-password-form">Change Password</a> + </li> + </xsl:if> <li> <a title="Click to logout."> <xsl:attribute name="href"> diff --git a/test/core/js/modules/webcaosdb.js.js b/test/core/js/modules/webcaosdb.js.js index 58cbc2e71c6e558652a30caa9445a38a78fad651..aca6c61067d931a41bd56b731cd1998b4d71835d 100644 --- a/test/core/js/modules/webcaosdb.js.js +++ b/test/core/js/modules/webcaosdb.js.js @@ -27,17 +27,17 @@ /* SETUP general module */ QUnit.module("webcaosdb.js", { - before: function(assert) { + before: function (assert) { markdown.init(); connection._init(); }, - after: function(assert) { + after: function (assert) { connection._init(); }, }); /* TESTS */ -QUnit.test("xslt", function(assert) { +QUnit.test("xslt", function (assert) { let xml_str = '<root/>'; let xsl_str = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="html" /><xsl:template match="root"><newroot>content</newroot></xsl:template></xsl:stylesheet>'; xml = str2xml(xml_str); @@ -69,13 +69,13 @@ QUnit.test("xslt", function(assert) { }, "nu ll xsl throws exc."); }); -QUnit.test("markdown.textTohtml", function(assert) { +QUnit.test("markdown.textTohtml", function (assert) { const str = `\# header\n\#\# another header\nparagraph`; assert.equal(markdown.textToHtml(str), "<h1 id=\"header\">header</h1>\n<h2 id=\"anotherheader\">another header</h2>\n<p>paragraph</p>"); }); -QUnit.test("injectTemplate", async function(assert) { +QUnit.test("injectTemplate", async function (assert) { const xml_str = '<root/>'; const xsl_str = '<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"><xsl:output method="html" /></xsl:stylesheet>'; const xml = str2xml(xml_str); @@ -91,7 +91,7 @@ QUnit.test("injectTemplate", async function(assert) { assert.equal(xml2str(result_xml), "<newroot xmlns=\"http://www.w3.org/1999/xhtml\">content</newroot>"); }); -QUnit.test("getEntityId", function(assert) { +QUnit.test("getEntityId", function (assert) { assert.ok(getEntityId, "function available"); let okElem = $('<div><div class="caosdb-id">1234</div></div>')[0]; let notOkElem = $('<div><div class="caosdb-id">asdf</div></div>')[0]; @@ -113,7 +113,7 @@ QUnit.test("getEntityId", function(assert) { assert.equal("1234", getEntityId(okElem), "ID found"); }); -QUnit.test("asyncXslt", function(assert) { +QUnit.test("asyncXslt", function (assert) { let xml_str = '<root/>'; let xsl_str = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="html" /><xsl:template match="root"><newroot/></xsl:template></xsl:stylesheet>'; xml = str2xml(xml_str); @@ -137,12 +137,12 @@ QUnit.test("asyncXslt", function(assert) { }); }); -QUnit.test("xml2str", function(assert) { +QUnit.test("xml2str", function (assert) { xml = str2xml('<root/>'); assert.equal(xml2str(xml), '<root/>'); }); -QUnit.test("str2xml", function(assert) { +QUnit.test("str2xml", function (assert) { xml = str2xml('<root/>'); assert.ok(xml); @@ -155,11 +155,11 @@ QUnit.test("str2xml", function(assert) { // valid. }); -QUnit.test("postXml", function(assert) { +QUnit.test("postXml", function (assert) { assert.ok(postXml, "function exists."); }); -QUnit.test("createErrorNotification", function(assert) { +QUnit.test("createErrorNotification", function (assert) { assert.ok(createErrorNotification, "function available"); let err = createErrorNotification("test"); assert.ok($(err).hasClass(preview.classNameErrorNotification), "has class caosdb-preview-error-notification"); @@ -167,37 +167,37 @@ QUnit.test("createErrorNotification", function(assert) { /* MODULE connection */ QUnit.module("webcaosdb.js - connection", { - before: function(assert) { + before: function (assert) { assert.ok(connection, "connection module is defined"); } }); -QUnit.test("get", function(assert) { +QUnit.test("get", function (assert) { assert.expect(4); assert.ok(connection.get, "function available"); let done = assert.async(2); - connection.get("webinterface/${BUILD_NUMBER}/xsl/entity.xsl").then(function(resolve) { + connection.get("webinterface/${BUILD_NUMBER}/xsl/entity.xsl").then(function (resolve) { assert.equal(resolve.toString(), "[object XMLDocument]", "entity.xsl returned."); done(); }); - connection.get("webinterface/non-existent").then((resolve) => resolve, function(error) { - assert.equal(error.toString().split(" - ",1)[0], "Error: GET webinterface/non-existent returned with HTTP status 404", "404 error thrown"); + connection.get("webinterface/non-existent").then((resolve) => resolve, function (error) { + assert.equal(error.toString().split(" - ", 1)[0], "Error: GET webinterface/non-existent returned with HTTP status 404", "404 error thrown"); done(); }); }); /* MODULE transformation */ QUnit.module("webcaosdb.js - transformation", { - before: function(assert) { + before: function (assert) { assert.ok(transformation, "transformation module is defined"); } }); -QUnit.test("removePermissions", function(assert) { +QUnit.test("removePermissions", function (assert) { assert.ok(transformation.removePermissions, "function available"); }); -QUnit.test("retrieveXsltScript", function(assert) { +QUnit.test("retrieveXsltScript", function (assert) { assert.ok(transformation.retrieveXsltScript, "function available"); let done = assert.async(2); transformation.retrieveXsltScript("entity.xsl").then(xsl => { @@ -210,7 +210,7 @@ QUnit.test("retrieveXsltScript", function(assert) { }); }); -QUnit.test("retrieveEntityXsl", function(assert) { +QUnit.test("retrieveEntityXsl", function (assert) { assert.ok(transformation.retrieveEntityXsl, "function available"); let done = assert.async(); transformation.retrieveEntityXsl().then(xsl => { @@ -221,7 +221,7 @@ QUnit.test("retrieveEntityXsl", function(assert) { }); }); -QUnit.test("transformEntities", function(assert) { +QUnit.test("transformEntities", function (assert) { assert.ok(transformation.transformEntities, "function available"); let done = assert.async(); let xml = str2xml('<Response><Record id="142"><Warning description="asdf"/></Record></Response>'); @@ -234,7 +234,7 @@ QUnit.test("transformEntities", function(assert) { }); }); -QUnit.test("mergeXsltScripts", function(assert) { +QUnit.test("mergeXsltScripts", function (assert) { assert.ok(transformation.mergeXsltScripts, 'function available.'); let xslMainStr = '<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"/>'; assert.equal(xml2str(transformation.mergeXsltScripts(str2xml(xslMainStr), [])), xslMainStr, 'no includes returns same as xslMain.'); @@ -245,12 +245,12 @@ QUnit.test("mergeXsltScripts", function(assert) { /* MODULE transaction */ QUnit.module("webcaosdb.js - transaction", { - before: function(assert) { + before: function (assert) { assert.ok(transaction, "transaction module is defined"); }, }); -QUnit.test("generateEntitiesUri", function(assert) { +QUnit.test("generateEntitiesUri", function (assert) { assert.ok(transaction.generateEntitiesUri, "function available"); assert.throws(() => { @@ -262,10 +262,10 @@ QUnit.test("generateEntitiesUri", function(assert) { assert.equal(transaction.generateEntitiesUri(["asdf", "qwer"]), "Entity/asdf&qwer", "works"); }); -QUnit.test("updateEntitiesXml", function(assert) { +QUnit.test("updateEntitiesXml", function (assert) { assert.ok(transaction.updateEntitiesXml, "function available"); var done = assert.async(); - connection.put = function(uri, data) { + connection.put = function (uri, data) { assert.equal(uri, 'Entity/', "updateEntitiesXml calls connection.put"); assert.equal(xml2str(data), '<Update/>'); done(); @@ -273,20 +273,20 @@ QUnit.test("updateEntitiesXml", function(assert) { transaction.updateEntitiesXml(str2xml('<Update/>')); }); -QUnit.test("retrieveEntitiesById", function(assert) { +QUnit.test("retrieveEntitiesById", function (assert) { assert.ok(transaction.retrieveEntitiesById, "function available"); var done = assert.async(); - connection.get = function(uri) { + connection.get = function (uri) { assert.equal(uri, 'Entity/1234&2345', "retrieveEntitiesById calls connection.get"); done(); }; transaction.retrieveEntitiesById(["1234", "2345"]); }); -QUnit.test("retrieveEntityById", function(assert) { +QUnit.test("retrieveEntityById", function (assert) { assert.ok(transaction.retrieveEntityById, "function available"); var done = assert.async(); - connection.get = function(uri) { + connection.get = function (uri) { assert.equal(uri, 'Entity/1234', "retrieveEntityById calls connection.get"); return new Promise((ok, fail) => { setTimeout(() => ok(str2xml('<Response><Entity id="1234" name="new"/></Response>')), 200); @@ -299,29 +299,29 @@ QUnit.test("retrieveEntityById", function(assert) { /* MODULE transaction.update */ QUnit.module("webcaosdb.js - transaction.update", { - before: function(assert) { + before: function (assert) { assert.ok(transaction.update, "transaction.update module is defined"); } }); -QUnit.test("createWaitRetrieveNotification", function(assert) { +QUnit.test("createWaitRetrieveNotification", function (assert) { assert.ok(transaction.update.createWaitRetrieveNotification(), 'function available and returns non-null'); }); -QUnit.test("createWaitUpdateNotification", function(assert) { +QUnit.test("createWaitUpdateNotification", function (assert) { assert.ok(transaction.update.createWaitUpdateNotification(), 'function available and returns non-null'); }); -QUnit.test("createUpdateForm", function(assert) { +QUnit.test("createUpdateForm", function (assert) { let done = assert.async(); let cuf = transaction.update.createUpdateForm; assert.ok(cuf, "function available"); - assert.throws(() => cuf(null, function(xml) {}), "null entityXmlStr throws"); + assert.throws(() => cuf(null, function (xml) {}), "null entityXmlStr throws"); assert.throws(() => cuf("", null), "null putCallback throws"); assert.throws(() => cuf("", ""), "non-function putCallback throws"); - assert.throws(() => cuf("", function() {}), "putCallback function without parameters throws"); + assert.throws(() => cuf("", function () {}), "putCallback function without parameters throws"); - let form = cuf("<root/>", function(xml) { + let form = cuf("<root/>", function (xml) { assert.equal(xml, '<newroot/>', "modified xml is submitted."); done(); }); @@ -343,7 +343,7 @@ QUnit.test("createUpdateForm", function(assert) { //$(document.body).append(form); }); -QUnit.test("createUpdateEntityHeading", function(assert) { +QUnit.test("createUpdateEntityHeading", function (assert) { let cueh = transaction.update.createUpdateEntityHeading; assert.ok(cueh, "function available"); let eh = $('<div class="panel-heading"><div class="1strow"></div><div class="2ndrow"></div></div>')[0]; @@ -354,7 +354,7 @@ QUnit.test("createUpdateEntityHeading", function(assert) { assert.equal($(uh).children('.1strow').length, 1, "uh has 1st row"); }); -QUnit.test("createUpdateEntityPanel", function(assert) { +QUnit.test("createUpdateEntityPanel", function (assert) { let cued = transaction.update.createUpdateEntityPanel; assert.ok(cued, "function available"); let div = $(cued($('<div id="headingid">heading</div>'))); @@ -362,12 +362,12 @@ QUnit.test("createUpdateEntityPanel", function(assert) { assert.equal(div.children(":first-child")[0].id, "headingid", "heading is first child element"); }); -QUnit.test("updateSingleEntity - success", function(assert) { +QUnit.test("updateSingleEntity - success", function (assert) { let done = assert.async(); let use = transaction.update.updateSingleEntity; assert.ok(use, "function available"); let entityPanel = $('<div class="panel panel-default caosdb-entity-panel"><div class="panel-heading caosdb-entity-panel-heading"><div>heading<div class="caosdb-id">1234</div></div><div>other stuff in the heading</div></div>body</div>')[0]; - connection.get = function(uri) { + connection.get = function (uri) { assert.equal(uri, 'Entity/1234', 'get was called with correct uri'); return new Promise((ok, fail) => { setTimeout(() => { @@ -384,7 +384,7 @@ QUnit.test("updateSingleEntity - success", function(assert) { setTimeout(() => { connection._init(); - connection.put = function(uri, xml) { + connection.put = function (uri, xml) { assert.equal(xml2str(xml), '<Update><Entity id="1234" name="new"/></Update>', "put was called with correct xml"); return new Promise((ok, fail) => { setTimeout(() => ok(str2xml('<Response><Record id="1234" name="new"></Record></Response>')), 200); @@ -402,18 +402,18 @@ QUnit.test("updateSingleEntity - success", function(assert) { - app.onEnterFinal = function(e) { + app.onEnterFinal = function (e) { done(); $(entityPanel).remove(); }; }); -QUnit.test("updateSingleEntity - with errors in the server's response", function(assert) { +QUnit.test("updateSingleEntity - with errors in the server's response", function (assert) { let done = assert.async(); let use = transaction.update.updateSingleEntity; let entityPanel = $('<div class="panel panel-default caosdb-entity-panel"><div class="panel-heading caosdb-entity-panel-heading"><div>heading<div class="caosdb-id">1234</div></div><div>other stuff in the heading</div></div>body</div>')[0]; - connection.get = function(uri) { + connection.get = function (uri) { return new Promise((ok, fail) => { setTimeout(() => { ok(str2xml('<Response><Entity id="1234" name="old"/></Response>')); @@ -427,7 +427,7 @@ QUnit.test("updateSingleEntity - with errors in the server's response", function // submit form -> server response contains error tag. setTimeout(() => { connection._init(); - connection.put = function(uri, xml) { + connection.put = function (uri, xml) { return new Promise((ok, fail) => { setTimeout(() => ok(str2xml('<Response><Record id="1234" name="new"><Error description="This is an error."/></Record></Response>')), 200); }); @@ -435,7 +435,7 @@ QUnit.test("updateSingleEntity - with errors in the server's response", function $(document.body).find('form.' + transaction.classNameUpdateForm).submit(); }, 400); - app.onLeaveWaitPutEntity = function(e) { + app.onLeaveWaitPutEntity = function (e) { assert.equal(e.transition, "openForm", "app returns to form again due to errors."); assert.equal($(app.updatePanel).find('.panel-heading .' + preview.classNameErrorNotification).length, 0, "has no error notification before the response is processed."); @@ -449,17 +449,17 @@ QUnit.test("updateSingleEntity - with errors in the server's response", function }); -QUnit.test("createErrorInUpdatedEntityNotification", function(assert) { +QUnit.test("createErrorInUpdatedEntityNotification", function (assert) { assert.ok(transaction.update.createErrorInUpdatedEntityNotification, "function available."); }); -QUnit.test("addErrorNotification", function(assert) { +QUnit.test("addErrorNotification", function (assert) { assert.ok(transaction.update.addErrorNotification, "function available"); }); /* MODULE preview */ QUnit.module("webcaosdb.js - preview", { - before: function(assert) { + before: function (assert) { // load xmlTestCase var done = assert.async(2); var qunit_obj = this; @@ -467,13 +467,13 @@ QUnit.module("webcaosdb.js - preview", { cache: true, dataType: 'xml', url: "xml/test_case_preview_entities.xml", - }).done(function(data, textStatus, jdXHR) { + }).done(function (data, textStatus, jdXHR) { qunit_obj.testXml = data; - }).always(function() { + }).always(function () { done(); }); // load entity.xsl - preview.getEntityXsl("../").then(function(data) { + preview.getEntityXsl("../").then(function (data) { insertParam(data, "entitypath", "/entitypath/"); insertParam(data, "filesystempath", "/filesystempath/"); qunit_obj.entityXSL = injectTemplate(data, '<xsl:template match="/"><root><xsl:apply-templates select="/Response/*" mode="top-level-data"/></root></xsl:template>'); @@ -482,22 +482,31 @@ QUnit.module("webcaosdb.js - preview", { assert.ok(preview, "preview module is defined"); }, - afterEach: function(assert) { + afterEach: function (assert) { connection._init(); } }); -QUnit.test("halfArray", function(assert){ +QUnit.test("halfArray", function (assert) { assert.ok(preview.halfArray, "function available"); assert.throws(() => { preview.halfArray([1]); }, "length < 2 throws.") - assert.deepEqual(preview.halfArray([1,2]), [[1],[2]]); - assert.deepEqual(preview.halfArray([1,2,3]), [[1],[2,3]]); - assert.deepEqual(preview.halfArray([1,2,3,4]), [[1,2],[3,4]]); -}); - -QUnit.test("xslt file preview", function(assert) { + assert.deepEqual(preview.halfArray([1, 2]), [ + [1], + [2] + ]); + assert.deepEqual(preview.halfArray([1, 2, 3]), [ + [1], + [2, 3] + ]); + assert.deepEqual(preview.halfArray([1, 2, 3, 4]), [ + [1, 2], + [3, 4] + ]); +}); + +QUnit.test("xslt file preview", function (assert) { let done = assert.async(); let entityXSL = this.entityXSL; $.ajax({ @@ -515,7 +524,7 @@ QUnit.test("xslt file preview", function(assert) { }); }); -QUnit.test("createShowPreviewButton", function(assert) { +QUnit.test("createShowPreviewButton", function (assert) { assert.ok(preview.createShowPreviewButton, "function available"); let showPreviewButton = preview.createShowPreviewButton(); assert.ok(showPreviewButton, "not null"); @@ -523,7 +532,7 @@ QUnit.test("createShowPreviewButton", function(assert) { assert.ok($(showPreviewButton).hasClass("caosdb-show-preview-button"), "has class caosdb-show-preview-button"); }); -QUnit.test("createHidePreviewButton", function(assert) { +QUnit.test("createHidePreviewButton", function (assert) { assert.ok(preview.createHidePreviewButton, "function available"); let hidePreviewButton = preview.createHidePreviewButton(); assert.ok(hidePreviewButton, "not null"); @@ -531,7 +540,7 @@ QUnit.test("createHidePreviewButton", function(assert) { assert.ok($(hidePreviewButton).hasClass("caosdb-hide-preview-button"), "has class 'caosdb-hide-preview-button'"); }); -QUnit.test("addHidePreviewButton", function(assert) { +QUnit.test("addHidePreviewButton", function (assert) { assert.ok(preview.addHidePreviewButton, "function available"); let okTestElem = $('<div><div class="caosdb-f-property-value"></div></div>')[0] let notOkTestElem = $('<div></div>')[0] @@ -556,7 +565,7 @@ QUnit.test("addHidePreviewButton", function(assert) { assert.equal(okTestElem.firstChild.childNodes.length, 1, "after: test div has new child"); }); -QUnit.test("addShowPreviewButton", function(assert) { +QUnit.test("addShowPreviewButton", function (assert) { assert.ok(preview.addShowPreviewButton, "function available"); let okTestElem = $('<div><div class="caosdb-f-property-value"></div></div>')[0] let notOkTestElem = $('<div></div>')[0] @@ -581,7 +590,7 @@ QUnit.test("addShowPreviewButton", function(assert) { assert.equal(okTestElem.firstChild.childNodes.length, 1, "after: test div has new child"); }); -QUnit.test("addWaitingNotification", function(assert) { +QUnit.test("addWaitingNotification", function (assert) { assert.ok(preview.addWaitingNotification, "function available"); let testWaiting = $('<div>Waiting!</div>')[0]; let okTestElem = $('<div><div class="caosdb-preview-notification-area"></div></div>')[0]; @@ -608,7 +617,7 @@ QUnit.test("addWaitingNotification", function(assert) { assert.equal(okTestElem.firstChild.childNodes.length, 1, "after: test div has new child"); }); -QUnit.test("addErrorNotification", function(assert) { +QUnit.test("addErrorNotification", function (assert) { assert.ok(preview.addErrorNotification, "function available"); let testError = $('<div>Error!</div>')[0]; let okTestElem = $('<div><div class="caosdb-preview-notification-area"></div></div>')[0]; @@ -635,14 +644,14 @@ QUnit.test("addErrorNotification", function(assert) { assert.equal(okTestElem.firstChild.childNodes.length, 1, "after: test div has new child"); }); -QUnit.test("createWaitingNotification", function(assert) { +QUnit.test("createWaitingNotification", function (assert) { assert.ok(preview.createWaitingNotification, "function available"); let welem = preview.createWaitingNotification(); assert.ok(welem, "not null"); assert.ok($(welem).hasClass("caosdb-preview-waiting-notification"), "element has class 'caosdb-preview-waiting-notification'"); }), - QUnit.test("createNotificationArea", function(assert) { + QUnit.test("createNotificationArea", function (assert) { assert.ok(preview.createNotificationArea, "function available"); let narea = preview.createNotificationArea(); assert.ok(narea, "not null"); @@ -650,7 +659,7 @@ QUnit.test("createWaitingNotification", function(assert) { assert.ok($(narea).hasClass("caosdb-preview-notification-area"), "has class caosdb-preview-notification-area"); }); -QUnit.test("getHidePreviewButton", function(assert) { +QUnit.test("getHidePreviewButton", function (assert) { assert.ok(preview.getHidePreviewButton, "function available"); let okElem = $('<div><button class="caosdb-hide-preview-button">click</button></div>')[0]; let notOkElem = $('<div></div>')[0]; @@ -666,7 +675,7 @@ QUnit.test("getHidePreviewButton", function(assert) { assert.equal(preview.getHidePreviewButton(okElem), okElem.firstChild, "button found"); }); -QUnit.test("getRefLinksContainer", function(assert) { +QUnit.test("getRefLinksContainer", function (assert) { assert.ok(preview.getRefLinksContainer, "function available"); // TODO: references or lists of references should have a special class, not just // caosdb-value-list. -> entity.xsl @@ -686,7 +695,7 @@ QUnit.test("getRefLinksContainer", function(assert) { assert.equal(preview.getRefLinksContainer(okSingle), okSingle.firstChild.firstChild, "single link found"); }); -QUnit.test("getPreviewCarousel", function(assert) { +QUnit.test("getPreviewCarousel", function (assert) { assert.ok(preview.getPreviewCarousel, "function available"); let okElem = $('<div><div class="' + preview.classNamePreview + '"></div></div>')[0]; let notOkElem = $('<div></div>')[0]; @@ -702,7 +711,7 @@ QUnit.test("getPreviewCarousel", function(assert) { assert.equal(preview.getPreviewCarousel(okElem), okElem.firstChild, "carousel found"); }); -QUnit.test("getShowPreviewButton", function(assert) { +QUnit.test("getShowPreviewButton", function (assert) { assert.ok(preview.getShowPreviewButton, "function available"); let okElem = $('<div><button class="caosdb-show-preview-button">click</button></div>')[0]; let notOkElem = $('<div></div>')[0]; @@ -718,7 +727,7 @@ QUnit.test("getShowPreviewButton", function(assert) { assert.equal(preview.getShowPreviewButton(okElem), okElem.firstChild, "button found"); }); -QUnit.test("removeAllErrorNotifications", function(assert) { +QUnit.test("removeAllErrorNotifications", function (assert) { assert.ok(preview.removeAllErrorNotifications, "function available"); let okElem = $('<div><div class="caosdb-preview-error-notification">Error1</div>' + '<div class="caosdb-preview-error-notification">Error2</div>' + @@ -740,7 +749,7 @@ QUnit.test("removeAllErrorNotifications", function(assert) { assert.equal(emptyElem, preview.removeAllErrorNotifications(emptyElem), "empty elem works"); }); -QUnit.test("removeAllWaitingNotifications", function(assert) { +QUnit.test("removeAllWaitingNotifications", function (assert) { assert.ok(removeAllWaitingNotifications, "function available"); let okElem = $('<div><div class="caosdb-preview-waiting-notification">Waiting1</div>' + '<div class="caosdb-preview-waiting-notification">Waiting2</div>' + @@ -762,7 +771,7 @@ QUnit.test("removeAllWaitingNotifications", function(assert) { assert.equal(emptyElem, removeAllWaitingNotifications(emptyElem), "empty elem works"); }); -QUnit.test("getActiveSlideItemIndex", function(assert) { +QUnit.test("getActiveSlideItemIndex", function (assert) { assert.ok(preview.getActiveSlideItemIndex, "function available"); let okElem0 = $('<div><div class="carousel-inner">' + '<div class="item active"></div>' // index 0 @@ -803,7 +812,7 @@ QUnit.test("getActiveSlideItemIndex", function(assert) { assert.equal(2, preview.getActiveSlideItemIndex(okElem2)); }); -QUnit.test("getEntityByIdVersion", function(assert) { +QUnit.test("getEntityByIdVersion", function (assert) { assert.ok(preview.getEntityByIdVersion, "function available"); let e1 = $('<div><div class="caosdb-id">1</div></div>')[0]; let e2 = $('<div><div class="caosdb-id">2</div></div>')[0]; @@ -828,7 +837,7 @@ QUnit.test("getEntityByIdVersion", function(assert) { assert.equal(null, preview.getEntityByIdVersion(es, "3"), "find 3 -> null"); }); -QUnit.test("createEmptyInner", function(assert) { +QUnit.test("createEmptyInner", function (assert) { assert.ok(preview.createEmptyInner, "function available"); assert.throws(() => { @@ -851,7 +860,7 @@ QUnit.test("createEmptyInner", function(assert) { assert.equal(inner.children[2].className, "item", "third item is not active"); }); -QUnit.test("createCarouselNav", function(assert) { +QUnit.test("createCarouselNav", function (assert) { assert.ok(preview.createCarouselNav, "function available"); let refLinks = $('<div style="display: none;" class="caosdb-value-list"><a><span class="caosdb-id">1234</span></a><a><span class="caosdb-id">2345</span></a><a><span class="caosdb-id">3456</span></a><a><span class="caosdb-id">4567</span></a></div>')[0]; assert.throws(() => { @@ -894,7 +903,7 @@ QUnit.test("createCarouselNav", function(assert) { let preview3Links = preview.createPreview(entities, refLinks); let preview1Link = preview.createPreview([e1], refLinks.children[0]); - QUnit.test("createPreviewCarousel", function(assert) { + QUnit.test("createPreviewCarousel", function (assert) { assert.ok(preview.createPreviewCarousel, "function available"); @@ -921,12 +930,12 @@ QUnit.test("createCarouselNav", function(assert) { assert.equal($(carousel).attr("data-interval"), "false", "no auto-sliding"); }); - QUnit.test("getSelectorButtons", function(assert) { + QUnit.test("getSelectorButtons", function (assert) { assert.ok(preview.getSelectorButtons, "function available"); assert.equal(preview.getSelectorButtons($(carousel).find('.' + preview.classNamePreviewCarouselNav)[0])[0].getAttribute('data-slide-to'), "0", "found selector button"); }); - QUnit.test("setActiveSlideItemSelector", function(assert) { + QUnit.test("setActiveSlideItemSelector", function (assert) { assert.ok(preview.setActiveSlideItemSelector, "function available"); assert.throws(() => { @@ -956,7 +965,7 @@ QUnit.test("createCarouselNav", function(assert) { } }); - QUnit.test("triggerUpdateActiveSlideItemSelector", function(assert) { + QUnit.test("triggerUpdateActiveSlideItemSelector", function (assert) { assert.ok(preview.triggerUpdateActiveSlideItemSelector, "function available"); preview.setActiveSlideItemSelector(carousel, 1); @@ -968,7 +977,7 @@ QUnit.test("createCarouselNav", function(assert) { assert.equal($(carousel).find('.' + preview.classNamePreviewCarouselNav).find('.active')[0].getAttribute('data-slide-to'), 0, 'after: active selector is 0.'); }); - QUnit.test("createPreview", function(assert) { + QUnit.test("createPreview", function (assert) { assert.ok($(preview3Links).hasClass(preview.classNamePreview), "3 links class name."); assert.ok($(preview1Link).hasClass(preview.classNamePreview), "1 links class name."); assert.ok($(preview1Link).hasClass(preview.classNamePreview), "1 links returns entity element"); @@ -979,7 +988,7 @@ QUnit.test("createCarouselNav", function(assert) { let original_get = connection.get; ref_property_elem.find('div').append(refLinks); - QUnit.test("initProperty", async function(assert) { + QUnit.test("initProperty", async function (assert) { var done = assert.async(2); assert.ok(preview.initProperty, "function available"); @@ -990,7 +999,7 @@ QUnit.test("createCarouselNav", function(assert) { assert.equal(showPreviewButton.length, 1, 'one show preview button.'); // test case for error in get method - connection.get = async function(uri) { + connection.get = async function (uri) { assert.equal(uri, "Entity/1234&2345&3456&4567", "get called with correct uri"); await sleep(1000); done(); @@ -1007,7 +1016,7 @@ QUnit.test("createCarouselNav", function(assert) { assert.equal(app.state, 'showLinks', 'after reset in showLinks state'); // test case for mockup-preview data - connection.get = async function(uri) { + connection.get = async function (uri) { if (uri.match(/webinterface/g)) { return await original_get(uri); } @@ -1030,7 +1039,7 @@ QUnit.test("createCarouselNav", function(assert) { hidePreviewButton.click(); assert.equal(app.state, 'showLinks', 'again in showLinks state.'); - connection.get = function(uri) { + connection.get = function (uri) { assert.ok(null, 'get was called: ' + uri); } showPreviewButton.click(); @@ -1045,14 +1054,14 @@ QUnit.test("createCarouselNav", function(assert) { }; -QUnit.test("preparePreviewEntity", function(assert){ +QUnit.test("preparePreviewEntity", function (assert) { assert.ok(preview.preparePreviewEntity, "function available"); let e = $('<div><div class="label caosdb-id">1234</div></div>')[0]; let prepared = preview.preparePreviewEntity(e); assert.equal($(prepared).find('a.caosdb-id')[0].href, connection.getBasePath() + "Entity/1234", "link is correct."); }); -QUnit.test("getEntityRef", function(assert) { +QUnit.test("getEntityRef", function (assert) { assert.ok(preview.getEntityRef, 'function available'); var html = $('<div><div class="caosdb-id">sdfg</div></div>')[0]; @@ -1062,22 +1071,24 @@ QUnit.test("getEntityRef", function(assert) { assert.equal(preview.getEntityRef(html), "", "empty string extracted"); html = $('<div></div>')[0]; - assert.throws(()=>{preview.getEntityRef(html);}, "missing .caosdb-id throws"); + assert.throws(() => { + preview.getEntityRef(html); + }, "missing .caosdb-id throws"); }); -QUnit.test("getAllEntityRefs", function(assert) { +QUnit.test("getAllEntityRefs", function (assert) { assert.ok(preview.getAllEntityRefs, 'function available'); assert.throws(preview.getAllEntityRefs, "null param throws"); // overwrite called methods const oldGetReferenceLinks = preview.getReferenceLinks; - preview.getReferenceLinks = function(links) { + preview.getReferenceLinks = function (links) { assert.propEqual(links, ["bla"], "array is passed to getReferenceLinks"); return links; } const oldGetEntityRef = preview.getEntityRef; - preview.getEntityRef = function(link) { + preview.getEntityRef = function (link) { assert.equal(link, "bla", "array elements are passed to getEntityRef"); return "asdf"; } @@ -1089,10 +1100,10 @@ QUnit.test("getAllEntityRefs", function(assert) { preview.getReferenceLinks = oldGetReferenceLinks; }); -QUnit.test("retrievePreviewEntities", function(assert) { +QUnit.test("retrievePreviewEntities", function (assert) { let done = assert.async(3); - connection.get = function(url){ - if(url.length>15) { + connection.get = function (url) { + if (url.length > 15) { assert.equal(url, "Entity/1&2&3&4&5", "All five entities are to be retrieved."); done(); throw new Error("UriTooLongException") @@ -1103,19 +1114,22 @@ QUnit.test("retrievePreviewEntities", function(assert) { } } assert.ok(preview.retrievePreviewEntities, "function available"); - preview.retrievePreviewEntities([1,2,3,4,5]).catch(err=>{assert.equal(err.message, "Terminate this test!", "The url had been split up.");done();}); + preview.retrievePreviewEntities([1, 2, 3, 4, 5]).catch(err => { + assert.equal(err.message, "Terminate this test!", "The url had been split up."); + done(); + }); }); -QUnit.test("transformXmlToPreviews", function(assert) { +QUnit.test("transformXmlToPreviews", function (assert) { assert.ok(preview.transformXmlToPreviews, "function available"); assert.ok(this.entityXSL, "xsl there"); assert.ok(this.testXml, "xml there"); let done = assert.async(); - let asyncTestCase = function(resolve) { + let asyncTestCase = function (resolve) { done(); }; - let asyncErr = function(error) { + let asyncErr = function (error) { console.log(error); done(); done(); @@ -1123,22 +1137,22 @@ QUnit.test("transformXmlToPreviews", function(assert) { preview.transformXmlToPreviews(this.testXml, this.entityXSL).then(asyncTestCase).catch(asyncErr); }); -QUnit.test("init", function(assert) { +QUnit.test("init", function (assert) { assert.ok(preview.init, "function available"); }); -QUnit.test("initEntity", function(assert) { +QUnit.test("initEntity", function (assert) { assert.ok(preview.initEntity, "function available"); }); /* MODULE queryForm */ QUnit.module("webcaosdb.js - queryForm", { - before: function(assert) { + before: function (assert) { assert.ok(queryForm, "queryForm is defined"); } }); -QUnit.test("removePagingField", function(assert) { +QUnit.test("removePagingField", function (assert) { assert.ok(queryForm.removePagingField, "function available."); assert.throws(() => queryForm.removePagingField(), "null param throws."); let form = $('<form><input name="P"></form>')[0]; @@ -1148,7 +1162,7 @@ QUnit.test("removePagingField", function(assert) { }); -QUnit.test("isSelectQuery", function(assert) { +QUnit.test("isSelectQuery", function (assert) { assert.ok(queryForm.isSelectQuery, "function available."); assert.throws(() => queryForm.isSelectQuery(), "null param throws."); assert.equal(queryForm.isSelectQuery("SELECT asdf"), true); @@ -1159,11 +1173,11 @@ QUnit.test("isSelectQuery", function(assert) { assert.equal(queryForm.isSelectQuery("SEL ECT"), false); }); -QUnit.test("init", function(assert) { +QUnit.test("init", function (assert) { assert.ok(queryForm.init, "init available"); }); -QUnit.test("restoreLastQuery", function(assert) { +QUnit.test("restoreLastQuery", function (assert) { assert.ok(queryForm.restoreLastQuery, "available"); let form = document.createElement("form"); @@ -1182,10 +1196,12 @@ QUnit.test("restoreLastQuery", function(assert) { assert.equal(form.query.value, "this is the old query", "after2: field is not empty"); }); -QUnit.test("bindOnClick", function(assert) { +QUnit.test("bindOnClick", function (assert) { assert.ok(queryForm.bindOnClick, "available"); var done = assert.async(2); - queryForm.redirect = function(a, b) {done();}; + queryForm.redirect = function (a, b) { + done(); + }; let form = document.createElement("form"); let submitButton = $("<input type=\"submit\">"); @@ -1197,9 +1213,9 @@ QUnit.test("bindOnClick", function(assert) { assert.throws(() => queryForm.bindOnClick(null, (set) => undefined), "null form throws exc."); assert.throws(() => queryForm.bindOnClick("asdf", (set) => undefined), "string form throws exc."); - let storage = function() { + let storage = function () { let x = undefined; - return function(set) { + return function (set) { if (set) { x = set; } @@ -1231,10 +1247,10 @@ QUnit.test("bindOnClick", function(assert) { /* MODULE paging */ QUnit.module("webcaosdb.js - paging", { - before: function(assert) {} + before: function (assert) {} }); -QUnit.test("initPaging", function(assert) { +QUnit.test("initPaging", function (assert) { let initPaging = paging.initPaging; let getPageHref = paging.getPageHref; assert.ok(initPaging, "function exists."); @@ -1378,7 +1394,7 @@ QUnit.test("initPaging", function(assert) { }); -QUnit.test("getNextPage", function(assert) { +QUnit.test("getNextPage", function (assert) { let getNextPage = paging.getNextPage; assert.ok(getNextPage, "function exists."); assert.throws(() => { @@ -1410,7 +1426,7 @@ QUnit.test("getNextPage", function(assert) { }); -QUnit.test("getPrevPage", function(assert) { +QUnit.test("getPrevPage", function (assert) { let getPrevPage = paging.getPrevPage; assert.ok(getPrevPage, "function exists."); assert.throws(() => { @@ -1431,7 +1447,7 @@ QUnit.test("getPrevPage", function(assert) { assert.equal(getPrevPage("23L11"), "12L11", "Index 5 to index 0."); }); -QUnit.test("getPSegmentFromUri", function(assert) { +QUnit.test("getPSegmentFromUri", function (assert) { let getPSegmentFromUri = paging.getPSegmentFromUri; assert.ok(getPSegmentFromUri, "function exists."); assert.throws(() => { @@ -1449,7 +1465,7 @@ QUnit.test("getPSegmentFromUri", function(assert) { assert.equal(getPSegmentFromUri("https://example:1234/blabla?asdf&P=0L10&asdfasdf"), "0L10", "asdf?asdf&P=0L10&asdfasdf -> P=0L10"); }); -QUnit.test("getPageHref", function(assert) { +QUnit.test("getPageHref", function (assert) { let getPageHref = paging.getPageHref; assert.ok(getPageHref, "function exists."); assert.throws(() => { @@ -1465,20 +1481,20 @@ QUnit.test("getPageHref", function(assert) { /* MODULE annotation */ QUnit.module("webcaosdb.js - annotation", { - before: function(assert) { + before: function (assert) { markdown.init(); // overwrite (we don't actually want to send any post requests) - annotation.postCommentXml = function(xml) { + annotation.postCommentXml = function (xml) { return new Promise(resolve => setTimeout(resolve, 1000, str2xml("<Response/>"))); } } }); -QUnit.test("loadAnnotationXsl", function(assert) { +QUnit.test("loadAnnotationXsl", function (assert) { assert.ok(annotation.loadAnnotationXsl, "function exists"); }); -QUnit.test("getAnnotationsForEntity", function(assert) { +QUnit.test("getAnnotationsForEntity", function (assert) { let xsl_str = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="html" /><xsl:template match="annotation"><div><xsl:value-of select="@id"/></div></xsl:template><xsl:template match="Response"><root><xsl:apply-templates select="annotation"/></root></xsl:template></xsl:stylesheet>'; let xslPromise = str2xml(xsl_str); let xml_str = '<Response><annotation id="1"/><annotation id="2"/><annotation id="3"/></Response>'; @@ -1488,7 +1504,7 @@ QUnit.test("getAnnotationsForEntity", function(assert) { }; let done = assert.async(); - let asyncTestCase = function(result) { + let asyncTestCase = function (result) { assert.equal(result.length, 3, "3 divs"); assert.equal(result[0].tagName, "DIV", "is DIV"); assert.equal(result[0].childNodes[0].nodeValue, "1", "test is '1'"); @@ -1506,7 +1522,7 @@ QUnit.test("getAnnotationsForEntity", function(assert) { }); QUnit.test("async/await behavior", (assert) => { - let af = async function() { + let af = async function () { return await "returnval"; }; @@ -1520,7 +1536,7 @@ QUnit.test("async/await behavior", (assert) => { done(); }); - let er = async function() { + let er = async function () { throw "asyncerror"; }; @@ -1530,30 +1546,30 @@ QUnit.test("async/await behavior", (assert) => { }); }); -QUnit.test("convertNewCommentForm", function(assert) { +QUnit.test("convertNewCommentForm", function (assert) { assert.ok(annotation.convertNewCommentForm, "function exists."); assert.equal(xml2str(annotation.convertNewCommentForm(annotation.createNewCommentForm(2345))), "<Insert><Record><Parent name=\"CommentAnnotation\"/><Property name=\"comment\"/><Property name=\"annotationOf\">2345</Property></Record></Insert>", "conversion ok."); }); -QUnit.test("convertNewCommentResponse", function(assert) { +QUnit.test("convertNewCommentResponse", function (assert) { let convertNewAnnotationResponse = annotation.convertNewCommentResponse; assert.ok(convertNewAnnotationResponse, "function exists."); let done = assert.async(); let testResponse = '<Response><Record><Property name="annotationOf"/><History transaction="INSERT" datetime="2015-12-24T20:15:00" username="someuser"/><Property name="comment">This is a comment</Property></Record></Response>'; let expectedResult = "<li xmlns=\"http://www.w3.org/1999/xhtml\" class=\"list-group-item markdowned\"><div class=\"media\"><div class=\"media-left\"><h3>»</h3></div><div class=\"media-body\"><h4 class=\"media-heading\">someuser<small><i> posted on 2015-12-24T20:15:00</i></small></h4><p class=\"caosdb-comment-annotation-text\"><p>This is a comment</p></p></div></div></li>"; - convertNewAnnotationResponse(str2xml(testResponse), annotation.loadAnnotationXsl("../../")).then(function(result) { + convertNewAnnotationResponse(str2xml(testResponse), annotation.loadAnnotationXsl("../../")).then(function (result) { assert.equal(result.length, 1, "one element returned."); - assert.equal(xml2str(result[0]).replace(/\n/g,""), expectedResult, "result converted correctly"); + assert.equal(xml2str(result[0]).replace(/\n/g, ""), expectedResult, "result converted correctly"); done(); - }, function(error) { + }, function (error) { console.log(error); assert.ok(false, "see console.log"); done(); }); }); -QUnit.test("getEntityId", function(assert) { +QUnit.test("getEntityId", function (assert) { let annotationSection = $('<div data-entity-id="dfgh"/>')[0]; assert.ok(annotation.getEntityId, "function exists."); assert.equal(annotation.getEntityId($('<div/>')[0]), null, "no data-entity-id attribute returns null"); @@ -1561,7 +1577,7 @@ QUnit.test("getEntityId", function(assert) { assert.equal(annotation.getEntityId(), null, "no param returns null."); }); -QUnit.test("createNewCommentForm", function(assert) { +QUnit.test("createNewCommentForm", function (assert) { let createNewCommentForm = annotation.createNewCommentForm; assert.ok(createNewCommentForm, "function exists."); assert.equal(createNewCommentForm(1234).tagName, "FORM", "returns form"); @@ -1573,7 +1589,7 @@ QUnit.test("createNewCommentForm", function(assert) { assert.equal($(createNewCommentForm(1234)).find("button[type='asdf']")[0], null, "no asdf button"); }); -QUnit.test("getNewCommentButton", function(assert) { +QUnit.test("getNewCommentButton", function (assert) { assert.ok(annotation.getNewCommentButton, "function exists."); assert.equal(annotation.getNewCommentButton($('<div/>')[0]), null, "not present"); assert.equal(annotation.getNewCommentButton($('<div><button class="otherclass"/></div>')[0]), null, "not present"); @@ -1582,19 +1598,19 @@ QUnit.test("getNewCommentButton", function(assert) { assert.equal(annotation.getNewCommentButton(null), null, "null parameter"); }); -QUnit.test("createPleaseWaitNotification", function(assert) { +QUnit.test("createPleaseWaitNotification", function (assert) { assert.ok(annotation.createPleaseWaitNotification, "function exists."); assert.ok($(annotation.createPleaseWaitNotification()).hasClass("caosdb-please-wait-notification"), "has class caosdb-please-wait-notification"); }); -QUnit.test("getNewCommentForm", function(assert) { +QUnit.test("getNewCommentForm", function (assert) { let annotationSection = $('<div><form id="sdfg" class="caosdb-new-comment-form"></form></div>')[0]; assert.ok(annotation.getNewCommentForm, "function exists"); assert.equal(annotation.getNewCommentForm(annotationSection).id, "sdfg", "NewCommentForm found."); assert.equal(annotation.getNewCommentForm(), null, "no param returns null"); }); -QUnit.test("validateNewCommentForm", function(assert) { +QUnit.test("validateNewCommentForm", function (assert) { assert.ok(annotation.validateNewCommentForm, "function exists."); let entityId = "asdf"; let form = annotation.createNewCommentForm(entityId); @@ -1606,17 +1622,17 @@ QUnit.test("validateNewCommentForm", function(assert) { assert.equal(annotation.validateNewCommentForm(form), true, "long enough returns true"); }); -QUnit.test("getPleaseWaitNotification", function(assert) { +QUnit.test("getPleaseWaitNotification", function (assert) { assert.ok(annotation.getPleaseWaitNotification, "function exists"); assert.equal(annotation.getPleaseWaitNotification(), null, "no param returns null"); assert.equal(annotation.getPleaseWaitNotification($('<div><div class="blablabla" id="asdf"></div></div>')[0]), null, "does not exist"); assert.equal(annotation.getPleaseWaitNotification($('<div><div class="caosdb-please-wait-notification" id="asdf"></div></div>')[0]).id, "asdf", "found."); }); -QUnit.test("NewCommentApp exception", function(assert) { +QUnit.test("NewCommentApp exception", function (assert) { try { var original = annotation.createNewCommentForm; - annotation.createNewCommentForm = function() { + annotation.createNewCommentForm = function () { throw new TypeError("This is really bad!"); } @@ -1635,7 +1651,7 @@ QUnit.test("NewCommentApp exception", function(assert) { } }); -QUnit.test("convertNewCommentResponse error", function(assert) { +QUnit.test("convertNewCommentResponse error", function (assert) { let errorStr = '<Response username="tf" realm="PAM" srid="dc1df091045eca7bd6940b88aa6db5b6" timestamp="1499814014684" baseuri="https://baal:8444/mpidsserver" count="1">\ <Error code="12" description="One or more entities are not qualified. None of them have been inserted/updated/deleted." />\ <Record>\ @@ -1659,25 +1675,25 @@ QUnit.test("convertNewCommentResponse error", function(assert) { let done = assert.async(); let expectedResult = "<divxmlns=\"http://www.w3.org/1999/xhtml\"class=\"alertalert-dangercaosdb-new-comment-erroralert-dismissablemarkdowned\"><buttonclass=\"close\"data-dismiss=\"alert\"aria-label=\"close\">×</button><strong>Error!</strong>Thiscommenthasnotbeeninserted.<pclass=\"small\"><pre><code><record><errorcode=\"114\"description=\"Entityhasunqualifiedproperties.\"></error><warningcode=\"0\"description=\"Entityhasnoname.\"></warning><parentname=\"CommentAnnotation\"><errorcode=\"101\"description=\"Entitydoesnotexist.\"></error></parent><propertyname=\"comment\"importance=\"FIX\">sdfasdfasdf<errorcode=\"101\"description=\"Entitydoesnotexist.\"></error><errorcode=\"110\"description=\"Propertyhasnodatatype.\"></error></property><propertyname=\"annotationOf\"importance=\"FIX\">20<errorcode=\"101\"description=\"Entitydoesnotexist.\"></error><errorcode=\"110\"description=\"Propertyhasnodatatype.\"></error></property></record></code></pre></p></div>"; - annotation.convertNewCommentResponse(str2xml(errorStr), annotation.loadAnnotationXsl("../../")).then(function(result) { + annotation.convertNewCommentResponse(str2xml(errorStr), annotation.loadAnnotationXsl("../../")).then(function (result) { assert.equal(xml2str(result[0]).replace(/[\t\n\ ]/g, ""), expectedResult.replace(/[\t\n\ ]/g, ""), "transformed into an error div."); done(); - }, function(error) { + }, function (error) { console.log(error); assert.ok(false, "see console.log"); done(); }); }) -QUnit.test("NewCommentApp convertNewCommentResponse", function(assert) { +QUnit.test("NewCommentApp convertNewCommentResponse", function (assert) { var done = assert.async(2); var original = annotation.convertNewCommentResponse; - annotation.convertNewCommentResponse = function(xmlPromise, xslPromise) { + annotation.convertNewCommentResponse = function (xmlPromise, xslPromise) { done(1); // was called; return original(xmlPromise, xslPromise); } let originalPost = annotation.postCommentXml; - annotation.postCommentXml = function(xml) { + annotation.postCommentXml = function (xml) { let testResponse = '<Response><Record><Property name="annotationOf"/><History transaction="INSERT" datetime="2015-12-24T20:15:00" username="someuser"/><Property name="comment">This is a comment</Property></Record></Response>'; return new Promise(resolve => setTimeout(resolve, 1000, str2xml(testResponse))); } @@ -1709,13 +1725,13 @@ QUnit.test("NewCommentApp convertNewCommentResponse", function(assert) { annotation.postCommentXml = originalPost; }); -QUnit.test("NewCommentApp convertNewCommentForm/postCommentXml", function(assert) { +QUnit.test("NewCommentApp convertNewCommentForm/postCommentXml", function (assert) { let done = assert.async(2); // do not actually post the comment, just wait 1 second and return // something. let originalPost = annotation.postCommentXml; - annotation.postCommentXml = function(xml) { + annotation.postCommentXml = function (xml) { assert.equal(xml2str(xml), "<Insert><Record><Parent name=\"CommentAnnotation\"/><Property name=\"comment\">This is a new comment qwerasdf.</Property><Property name=\"annotationOf\">tzui</Property></Record></Insert>", "the conversion was sucessful"); done(2); // postCommentXml was called return new Promise(resolve => setTimeout(resolve, 1000, str2xml("<Response/>"))); @@ -1732,7 +1748,7 @@ QUnit.test("NewCommentApp convertNewCommentForm/postCommentXml", function(assert form.newComment.value = "This is a new comment qwerasdf."; let originalConvert = annotation.convertNewCommentForm; - annotation.convertNewCommentForm = function(sendform) { + annotation.convertNewCommentForm = function (sendform) { assert.ok(sendform == form, "form is still the same"); done(1); // convertNewCommentForm was called return originalConvert(sendform); @@ -1747,7 +1763,7 @@ QUnit.test("NewCommentApp convertNewCommentForm/postCommentXml", function(assert annotation.postCommentXml = originalPost; }); -QUnit.test("NewCommentApp waitingNotification", function(assert) { +QUnit.test("NewCommentApp waitingNotification", function (assert) { // prepare app let annotationSection = $('<div><button class="caosdb-new-comment-button"></button></div>')[0]; let app = annotation.initNewCommentApp(annotationSection); @@ -1764,7 +1780,7 @@ QUnit.test("NewCommentApp waitingNotification", function(assert) { }); -QUnit.test("NewCommentApp form.onsubmit", function(assert) { +QUnit.test("NewCommentApp form.onsubmit", function (assert) { let done = assert.async(2); let annotationSection = $('<div><button class="caosdb-new-comment-button"></button></div>')[0]; @@ -1779,7 +1795,7 @@ QUnit.test("NewCommentApp form.onsubmit", function(assert) { let submitButton = annotation.getSubmitNewCommentButton(annotationSection); // test with empty form -> rejected - app.observe("onBeforeTransition", function(e) { + app.observe("onBeforeTransition", function (e) { done("1&2"); }); @@ -1796,14 +1812,14 @@ QUnit.test("NewCommentApp form.onsubmit", function(assert) { $(annotationSection).remove(); }); -QUnit.test("NewCommentApp form.onreset", function(assert) { +QUnit.test("NewCommentApp form.onreset", function (assert) { let annotationSection = $('<div><button class="caosdb-new-comment-button"></button></div>')[0]; let app = annotation.initNewCommentApp(annotationSection); app.openForm(); let done = assert.async(); assert.equal(annotation.getNewCommentForm(annotationSection).className, "caosdb-new-comment-form", "form is there"); - app.observe("onBeforeCancelForm", function(e) { + app.observe("onBeforeCancelForm", function (e) { assert.equal(e.from, "write", "leaving write state"); done(); }); @@ -1821,7 +1837,7 @@ QUnit.test("NewCommentApp form.onreset", function(assert) { $(annotationSection).remove(); }); -QUnit.test("getCancelNewCommentButton", function(assert) { +QUnit.test("getCancelNewCommentButton", function (assert) { let annotationSection = $('<div><form class="caosdb-new-comment-form"><button id="fghj" type="reset"/></form></div>')[0]; assert.ok(annotation.getCancelNewCommentButton, "function exists."); assert.equal(annotation.getCancelNewCommentButton(), null, "no param returns null"); @@ -1830,7 +1846,7 @@ QUnit.test("getCancelNewCommentButton", function(assert) { assert.equal(annotation.getCancelNewCommentButton($('<div><form class="caosdb-new-comment-form"><button type="submit"/></form></div>')[0]), null, "button does not exist"); }); -QUnit.test("getSubmitNewCommentButton", function(assert) { +QUnit.test("getSubmitNewCommentButton", function (assert) { let annotationSection = $('<div><form class="caosdb-new-comment-form"><button id="fghj" type="submit"/></form></div>')[0]; assert.ok(annotation.getSubmitNewCommentButton, "function exists."); assert.equal(annotation.getSubmitNewCommentButton(), null, "no param returns null"); @@ -1839,7 +1855,7 @@ QUnit.test("getSubmitNewCommentButton", function(assert) { assert.equal(annotation.getSubmitNewCommentButton($('<div><form class="caosdb-new-comment-form"><button type="reset"/></form></div>')[0]), null, "button does not exist"); }); -QUnit.test("NewCommentApp newCommentButton.onclick", function(assert) { +QUnit.test("NewCommentApp newCommentButton.onclick", function (assert) { let annotationSection = $('<div><button class="caosdb-new-comment-button"></button></div>')[0]; let app = annotation.initNewCommentApp(annotationSection); let button = annotation.getNewCommentButton(annotationSection); @@ -1857,7 +1873,7 @@ QUnit.test("NewCommentApp newCommentButton.onclick", function(assert) { assert.equal(annotation.getNewCommentForm(annotationSection).parentNode.className, "list-group-item", "form is wrapped into list-group-item"); }); -QUnit.test("NewCommentApp transitions", function(assert) { +QUnit.test("NewCommentApp transitions", function (assert) { assert.throws(annotation.initNewCommentApp, "null parameter throws exc."); let annotationSection = $('<div><button class="caosdb-new-comment-button"></button></div>')[0]; @@ -1883,7 +1899,7 @@ QUnit.test("NewCommentApp transitions", function(assert) { assert.equal(app.state, "read", "reset -> state read"); }); -QUnit.test("annotation module", function(assert) { +QUnit.test("annotation module", function (assert) { assert.ok(annotation, "module exists."); assert.ok(annotation.createNewCommentForm, "createNewCommentForm exists."); assert.ok(annotation.initNewCommentApp, "initNewCommentApp exists."); @@ -1903,17 +1919,25 @@ QUnit.module("webcaosdb.js - navbar", { }, }); -QUnit.test("get_navbar", function(assert) { +QUnit.test("get_navbar", function (assert) { assert.equal(navbar.get_navbar().className, "caosdb-navbar"); }); -QUnit.test("add_button wrong parameters", function(assert) { - assert.throws(()=>{navbar.add_button(undefined)}, /button is expected/, "undefined throws"); - assert.throws(()=>{navbar.add_button({"test": "an object"})}, "object throws"); - assert.throws(()=>{navbar.add_button(["array of strings"])}, "array of string throws"); +QUnit.test("add_button wrong parameters", function (assert) { + assert.throws(() => { + navbar.add_button(undefined) + }, /button is expected/, "undefined throws"); + assert.throws(() => { + navbar.add_button({ + "test": "an object" + }) + }, "object throws"); + assert.throws(() => { + navbar.add_button(["array of strings"]) + }, "array of string throws"); }); -QUnit.test("test button classes", function(assert) { +QUnit.test("test button classes", function (assert) { var result = $(navbar.add_button("TestButton")).children().first() assert.ok(result.hasClass("navbar-btn"), "has class navbar-btn"); assert.ok(result.hasClass("btn"), "has class btn"); @@ -1921,7 +1945,7 @@ QUnit.test("test button classes", function(assert) { assert.equal(result.text(), "TestButton", "text is correct"); }); -QUnit.test("add_tool", function(assert) { +QUnit.test("add_tool", function (assert) { assert.equal($(".caosdb-f-navbar-toolbox").length, 0, "no toolbox"); navbar.add_tool("TestButton", "TestMenu"); @@ -1939,7 +1963,7 @@ QUnit.test("add_tool", function(assert) { assert.notOk(toolbox.siblings("a.dropdown-toggle").hasClass("navbar-btn")); }); -QUnit.test("toolbox example", function(assert) { +QUnit.test("toolbox example", function (assert) { // this is a kind of integration test and it uses the toolbox_example // module from toolbox_example.js. That example is also usefull for manual // testing. @@ -1959,10 +1983,10 @@ QUnit.test("toolbox example", function(assert) { }); QUnit.module("webcaosdb.js - version_history", { - before: function(assert) { + before: function (assert) { connection._init(); }, - after: function(assert) { + after: function (assert) { connection._init(); }, }); @@ -2030,3 +2054,55 @@ QUnit.test("init_load_history_buttons and init_load_history_buttons", async func $(html).remove(); }); + + +/* SETUP tests for user_management */ +QUnit.module("webcaosdb.js - user_management", { + afterEach: function (assert) { + $(user_management.get_change_password_form()).remove(); + }, +}); + + +QUnit.test("get_change_password_form", async function (assert) { + assert.equal(typeof user_management.get_change_password_form(), "undefined", "no password form"); + + const modal = callTemplate( + (await transformation.retrieveXsltScript("navbar.xsl")), + "change-password-modal", { + "username": "testuser", + "realm": "testrealm" + }); + + $("body").append(modal); + + assert.ok(user_management.get_change_password_form(), "found password form"); +}); + +QUnit.test("submit new password", async function (assert) { + const modal = $(callTemplate( + (await transformation.retrieveXsltScript("navbar.xsl")), + "change-password-modal", { + "username": "testuser", + "realm": "testrealm" + }).firstElementChild); + + $("body").append(modal); + + user_management.init(); + var done = assert.async(); + user_management.set_new_password = async (realm, user, password) => { + assert.equal(realm, "testrealm", "realm correct"); + assert.equal(user, "testuser", "user correct"); + assert.equal(password, "newtestpassword1A!", "password correct"); + done(); + } + + const form = modal.find("form"); + assert.ok(form, "form there"); + + form[0]["password"].value = "newtestpassword1A!"; + form[0]["password2"].value = "newtestpassword1A!"; + + form.find(":submit").click(); +}); \ No newline at end of file