From 63448d9dbdc36baca17e7b4acca08b1e87ecb81b Mon Sep 17 00:00:00 2001 From: Penghai Date: Wed, 23 Oct 2019 17:07:19 +1100 Subject: [PATCH 01/13] Update version to 2019.1.2 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index a8047c80b9..098461b0b0 100644 --- a/build.sbt +++ b/build.sbt @@ -113,7 +113,7 @@ name := "Equella" equellaMajor in ThisBuild := 2019 equellaMinor in ThisBuild := 1 -equellaPatch in ThisBuild := 1 +equellaPatch in ThisBuild := 2 equellaStream in ThisBuild := "Stable" equellaBuild in ThisBuild := buildConfig.value.getString("build.buildname") From 348e0a8a5693b23f99180859701ac4cde6b3c877 Mon Sep 17 00:00:00 2001 From: Aaron Holland Date: Fri, 4 Oct 2019 09:12:48 +1000 Subject: [PATCH 02/13] #1200 force 100% width (#1278) --- .../resources/web/css/controls.css | 342 ++++++++++-------- 1 file changed, 186 insertions(+), 156 deletions(-) diff --git a/Source/Plugins/Core/com.equella.core/resources/web/css/controls.css b/Source/Plugins/Core/com.equella.core/resources/web/css/controls.css index 3e425144fc..348c821d56 100644 --- a/Source/Plugins/Core/com.equella.core/resources/web/css/controls.css +++ b/Source/Plugins/Core/com.equella.core/resources/web/css/controls.css @@ -1,305 +1,335 @@ .wizard-controls { - margin: 4px 0; + margin: 4px 0; } .wizard-controls .control { - margin: 0 0 15px; + margin: 0 0 15px; } -.wizard-controls .indent1 .control:first-child,.wizard-controls .indent2 .control:first-child,.wizard-controls .indent3 .control:first-child - { - margin-top: 15px; +.wizard-controls .indent1 .control:first-child, +.wizard-controls .indent2 .control:first-child, +.wizard-controls .indent3 .control:first-child { + margin-top: 15px; } .wizard-controls .ctrlinvalidmessage { - display: none; + display: none; } -.wizard-controls .ctrlinvalid>.ctrlinvalidmessage { - background-color: #FDD; - padding: 5px; - display: block; +.wizard-controls .ctrlinvalid > .ctrlinvalidmessage { + background-color: #fdd; + padding: 5px; + display: block; } -.wizard-controls .ctrlmandatory,.wizard-controls .ctrlinvalidmessage { - color: red; - text-align: center; +.wizard-controls .ctrlmandatory, +.wizard-controls .ctrlinvalidmessage { + color: red; + text-align: center; } .wizard-controls .control p { - margin-top: 0; - margin-bottom: 10px; + margin-top: 0; + margin-bottom: 10px; } -.wizard-controls .indent1,.wizard-controls .indent2,.wizard-controls .indent3 - { - padding: 20px 0px 20px 40px; +.wizard-controls .indent1, +.wizard-controls .indent2, +.wizard-controls .indent3 { + padding: 20px 0px 20px 40px; } -.indent0 .indent1,.indent1 .indent2,.indent2 .indent3 { - padding-bottom: 0px; +.indent0 .indent1, +.indent1 .indent2, +.indent2 .indent3 { + padding-bottom: 0px; } -.option+.indent1,.option+.indent2,.option+.indent3 { - padding-top: 0px; +.option + .indent1, +.option + .indent2, +.option + .indent3 { + padding-top: 0px; } /************************/ .wizard-controls .indent1 { - width: 556px; + width: 556px; } .wizard-controls .indent2 { - width: 516px; + width: 516px; } .wizard-controls .indent3 { - width: 476px; + width: 476px; } /************************/ -.wizard-controls .input.text input[type="text"],.wizard-controls .input.text textarea,.wizard-controls select.listbox - { - box-sizing: border-box; - width: 100%; +.wizard-controls .input.text input[type="text"], +.wizard-controls .input.text textarea, +.wizard-controls select.listbox { + box-sizing: border-box; + width: 100%; +} + +.wizard-controls select.listbox + .newListSelected, +.wizard-controls select.listbox + .newListSelected .newList { + box-sizing: border-box; + width: 100% !important; } -.wizard-controls .indent1 .input.text input[type="text"],.wizard-controls .indent1 .input.text textarea,.wizard-controls .indent1 select.listbox - { - box-sizing: border-box; - width: 100%; +.wizard-controls .indent1 .input.text input[type="text"], +.wizard-controls .indent1 .input.text textarea, +.wizard-controls .indent1 select.listbox { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent2 .input.text input[type="text"],.wizard-controls .indent2 .input.text textarea,.wizard-controls .indent2 select.listbox - { - box-sizing: border-box; - width: 100%; +.wizard-controls .indent2 .input.text input[type="text"], +.wizard-controls .indent2 .input.text textarea, +.wizard-controls .indent2 select.listbox { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent3 .input.text input[type="text"],.wizard-controls .indent3 .input.text textarea,.wizard-controls .indent3 select.listbox - { - box-sizing: border-box; - width: 100%; +.wizard-controls .indent3 .input.text input[type="text"], +.wizard-controls .indent3 .input.text textarea, +.wizard-controls .indent3 select.listbox { + box-sizing: border-box; + width: 100%; } /************************/ -.wizard-controls .multieditbox input[type="text"],.wizard-controls .multieditbox select,.wizard-controls .multieditbox textarea - { - box-sizing: border-box; - width: 100%; +.wizard-controls .multieditbox input[type="text"], +.wizard-controls .multieditbox select, +.wizard-controls .multieditbox textarea { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent1 .multieditbox input[type="text"],.wizard-controls .indent1 .multieditbox select,.wizard-controls .indent1 .multieditbox textarea - { - box-sizing: border-box; - width: 100%; +.wizard-controls .indent1 .multieditbox input[type="text"], +.wizard-controls .indent1 .multieditbox select, +.wizard-controls .indent1 .multieditbox textarea { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent2 .multieditbox input[type="text"],.wizard-controls .indent2 .multieditbox select,.wizard-controls .indent2 .multieditbox textarea - { - box-sizing: border-box; - width: 100%; +.wizard-controls .indent2 .multieditbox input[type="text"], +.wizard-controls .indent2 .multieditbox select, +.wizard-controls .indent2 .multieditbox textarea { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent3 .multieditbox input[type="text"],.wizard-controls .indent3 .multieditbox select,.wizard-controls .indent3 .multieditbox textarea - { - box-sizing: border-box; - width: 100%; +.wizard-controls .indent3 .multieditbox input[type="text"], +.wizard-controls .indent3 .multieditbox select, +.wizard-controls .indent3 .multieditbox textarea { + box-sizing: border-box; + width: 100%; } -.wizard-controls .multieditbox DIV.singletranslation input[type="text"],.wizard-controls .multieditbox DIV.singletranslation textarea - { - box-sizing: border-box; - width: 100%; +.wizard-controls .multieditbox div.singletranslation input[type="text"], +.wizard-controls .multieditbox div.singletranslation textarea { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent1 .multieditbox DIV.singletranslation input[type="text"],.wizard-controls .indent1 .multieditbox DIV.singletranslation textarea - { - box-sizing: border-box; - width: 100%; +.wizard-controls + .indent1 + .multieditbox + div.singletranslation + input[type="text"], +.wizard-controls .indent1 .multieditbox div.singletranslation textarea { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent2 .multieditbox DIV.singletranslation input[type="text"],.wizard-controls .indent2 .multieditbox DIV.singletranslation textarea - { - box-sizing: border-box; - width: 100%; +.wizard-controls + .indent2 + .multieditbox + div.singletranslation + input[type="text"], +.wizard-controls .indent2 .multieditbox div.singletranslation textarea { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent3 .multieditbox DIV.singletranslation input[type="text"],.wizard-controls .indent3 .multieditbox DIV.singletranslation textarea - { - box-sizing: border-box; - width: 100%; +.wizard-controls + .indent3 + .multieditbox + div.singletranslation + input[type="text"], +.wizard-controls .indent3 .multieditbox div.singletranslation textarea { + box-sizing: border-box; + width: 100%; } /************************/ -.wizard-controls .shuffle input[type="text"],.wizard-controls .shuffle select - { - box-sizing: border-box; - width: 100%; +.wizard-controls .shuffle input[type="text"], +.wizard-controls .shuffle select { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent1 .shuffle input[type="text"],.wizard-controls .indent1 .shuffle select - { - box-sizing: border-box; - width: 100%; +.wizard-controls .indent1 .shuffle input[type="text"], +.wizard-controls .indent1 .shuffle select { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent2 .shuffle input[type="text"],.wizard-controls .indent2 .shuffle select - { - box-sizing: border-box; - width: 100%; +.wizard-controls .indent2 .shuffle input[type="text"], +.wizard-controls .indent2 .shuffle select { + box-sizing: border-box; + width: 100%; } -.wizard-controls .indent3 .shuffle input[type="text"],.wizard-controls .indent3 .shuffle select - { - box-sizing: border-box; - width: 100%; +.wizard-controls .indent3 .shuffle input[type="text"], +.wizard-controls .indent3 .shuffle select { + box-sizing: border-box; + width: 100%; } /************************/ .repeater { - border: 1px solid #8F8B7E; - margin: 0px 0px 10px; - padding: 15px 19px 9px !important; - position: relative; + border: 1px solid #8f8b7e; + margin: 0px 0px 10px; + padding: 15px 19px 9px !important; + position: relative; } .repeater-remove { - background: url(../images/repeater-remove.png) no-repeat 0px 0px; - margin-left: 3px; - cursor: pointer; - height: 17px; - float: right; - width: 17px; + background: url(../images/repeater-remove.png) no-repeat 0px 0px; + margin-left: 3px; + cursor: pointer; + height: 17px; + float: right; + width: 17px; } -.repeater-move{ - background: url(../images/repeater-button-bg.png) no-repeat 0px 0px; - height: 17px; - float: right; - width: 17px; - padding-left: 4px; - background-position: center; +.repeater-move { + background: url(../images/repeater-button-bg.png) no-repeat 0px 0px; + height: 17px; + float: right; + width: 17px; + padding-left: 4px; + background-position: center; } .repeater-move i { - margin-bottom: 2px; - position: relative; - + margin-bottom: 2px; + position: relative; } .options-control { - width: 100%; + width: 100%; } .options-control label { - margin: 0 5px; + margin: 0 5px; } /************************/ .calendar-control .calendar { - display: inline; - margin-right: 40px; + display: inline; + margin-right: 40px; } .calendar-control .calendar-clear { - display: inline; + display: inline; } /************************/ .wizard-layout .indent1 .shufflelist { - width: 556px; + width: 556px; } .wizard-layout .indent2 .shufflelist { - width: 516px; + width: 516px; } .wizard-layout .indent3 .shufflelist { - width: 476px; + width: 476px; } .wizard-layout .indent1 .shuffle-box-inner select { - width: 236px; + width: 236px; } .wizard-layout .indent2 .shuffle-box-inner select { - width: 216px; + width: 216px; } .wizard-layout .indent3 .shuffle-box-inner select { - width: 197px; + width: 197px; } .wizard-layout .indent0 .shuffle-box-inner label { - width: 253px; + width: 253px; } .wizard-layout .indent1 .shuffle-box-inner label { - width: 233px; + width: 233px; } .wizard-layout .indent2 .shuffle-box-inner label { - width: 213px; + width: 213px; } .wizard-layout .indent3 .shuffle-box-inner label { - width: 193px; + width: 193px; } /************************/ #searchform .wizard-controls div.input { - margin: 8px 0; - padding: 0px; + margin: 8px 0; + padding: 0px; } -#searchform .wizard-controls .input.text input[type="text"], #searchform .wizard-controls .input.text textarea, #searchform .wizard-controls select.listbox { - width: 465px; +#searchform .wizard-controls .input.text input[type="text"], +#searchform .wizard-controls .input.text textarea, +#searchform .wizard-controls select.listbox { + width: 465px; } #searchform .wizard-controls div.input.calendar { - margin: 8px 40px 8px 0; + margin: 8px 40px 8px 0; } #searchform .wizard-controls div.input.calendar input[type="text"] { - width: 140px; + width: 140px; } -#searchform .wizard-controls .shuffle input[type="text"], #searchform .wizard-controls .shuffle select { - width: 410px; +#searchform .wizard-controls .shuffle input[type="text"], +#searchform .wizard-controls .shuffle select { + width: 410px; } #searchform .wizard-controls .shuffle-box select { - width: 195px; + width: 195px; } #searchform .wizard-controls .autocompleteControl input[type="text"] { - width: 385px; + width: 385px; } -div.error-receipt -{ - background-color: #FDD; - padding: 5px; - display: block; - text-align: left; - color: red; - margin: 12px 0; +div.error-receipt { + background-color: #fdd; + padding: 5px; + display: block; + text-align: left; + color: red; + margin: 12px 0; } -html[class="accessibility"] div.error-receipt:focus -{ - outline: thin solid rgba(299, 151, 0, 255); - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; +html[class="accessibility"] div.error-receipt:focus { + outline: thin solid rgba(299, 151, 0, 255); + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; } -div.error-receipt p -{ - margin: 5px 0; -} -div.error-receipt ul li -{ - margin-left: 10px; - height: 18px; +div.error-receipt p { + margin: 5px 0; +} +div.error-receipt ul li { + margin-left: 10px; + height: 18px; } - From 5db23b4bd5ea1ae82a2c125cf23209bf6819c410 Mon Sep 17 00:00:00 2001 From: Jolse Maginnis Date: Fri, 26 Jul 2019 17:55:36 +1000 Subject: [PATCH 03/13] MAKE-PULL-REQUEST #1088 Fix advanced criteria button/page --- .../section/ItemAdminWhereSection.java | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/itemadmin/section/ItemAdminWhereSection.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/itemadmin/section/ItemAdminWhereSection.java index 55474194b0..fe735380ad 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/itemadmin/section/ItemAdminWhereSection.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/itemadmin/section/ItemAdminWhereSection.java @@ -34,7 +34,6 @@ import com.tle.web.sections.equella.annotation.PluginResourceHandler; import com.tle.web.sections.equella.layout.ContentLayout; import com.tle.web.sections.equella.utils.VoidKeyOption; -import com.tle.web.sections.events.BeforeEventsListener; import com.tle.web.sections.events.BookmarkEvent; import com.tle.web.sections.events.RenderEventContext; import com.tle.web.sections.events.js.EventGenerator; @@ -73,7 +72,7 @@ @SuppressWarnings("nls") public class ItemAdminWhereSection extends AbstractPrototypeSection - implements HtmlRenderer, BeforeEventsListener { + implements HtmlRenderer { static { PluginResourceHandler.init(ItemAdminWhereSection.class); } @@ -198,6 +197,7 @@ public void setupCriteria(SectionInfo info) { getModel(info).setEditQuery(false); List clauses = whereClauses.getValues(info); querySection.getModel(info).setCriteria(clauses); + info.forceRedirect(); } public void clearOptions(SectionInfo info) { @@ -225,13 +225,6 @@ private void setupWhereClause() { whereOperator.setListModel(new SimpleHtmlListModel(exprOps)); } - @Override - public void beforeEvents(SectionInfo info) { - if (getModel(info).isEditQuery()) { - rootItemAdmin.setModalSection(info, this); - } - } - public void setEditQuery(SectionInfo info, boolean edit, String collectionId) { ItemAdminWhereSectionModel model = getModel(info); model.setEditQuery(edit); @@ -240,21 +233,25 @@ public void setEditQuery(SectionInfo info, boolean edit, String collectionId) { @Override public Object instantiateModel(SectionInfo info) { - return new ItemAdminWhereSectionModel(); + return new ItemAdminWhereSectionModel(info); } - public static class ItemAdminWhereSectionModel { + public class ItemAdminWhereSectionModel { @Bookmarked(contexts = BookmarkEvent.CONTEXT_SESSION) private boolean editQuery; @Bookmarked private String collectionId; + private SectionInfo info; - public boolean isEditQuery() { - return editQuery; + public ItemAdminWhereSectionModel(SectionInfo info) { + this.info = info; } public void setEditQuery(boolean editQuery) { this.editQuery = editQuery; + if (editQuery) { + rootItemAdmin.setModalSection(info, ItemAdminWhereSection.this); + } } public String getCollectionId() { From 72a42e410576e94072bd77ae19aafc2dbd8e8248 Mon Sep 17 00:00:00 2001 From: PenghaiZhang <47203811+PenghaiZhang@users.noreply.github.com> Date: Wed, 30 Oct 2019 09:47:55 +1100 Subject: [PATCH 04/13] Change the functionality of version checking (#1314) * Make oEQ call Github api to retrieve new oEQ releases information instead of calling the Version Server * For major, minor and patch updates, the Health check page shows update information for each of them --- .../js/__mocks__/versioncheck_mock_data.js | 1089 +++++++++++++++++ .../js/__tests__/versioncheck.test.js | 43 + .../Core/com.equella.core/js/package.json | 9 +- .../lang/i18n-resource-centre.properties | 9 +- .../resources/view/tab/health.ftl | 52 +- .../resources/web/js/versioncheck.js | 165 ++- .../tle/web/institution/tab/HealthTab.java | 132 +- buildspec.yml | 1 + 8 files changed, 1450 insertions(+), 50 deletions(-) create mode 100644 Source/Plugins/Core/com.equella.core/js/__mocks__/versioncheck_mock_data.js create mode 100644 Source/Plugins/Core/com.equella.core/js/__tests__/versioncheck.test.js diff --git a/Source/Plugins/Core/com.equella.core/js/__mocks__/versioncheck_mock_data.js b/Source/Plugins/Core/com.equella.core/js/__mocks__/versioncheck_mock_data.js new file mode 100644 index 0000000000..8460acdb72 --- /dev/null +++ b/Source/Plugins/Core/com.equella.core/js/__mocks__/versioncheck_mock_data.js @@ -0,0 +1,1089 @@ +exports.mockReleases = [ + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/20197179", + assets_url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/20197179/assets", + upload_url: + "https://uploads.github.com/repos/openequella/openEQUELLA/releases/20197179/assets{?name,label}", + html_url: + "https://github.com/openequella/openEQUELLA/releases/tag/2019.1.1", + id: 20197199, + node_id: "MDc6UmVsZWFzZTIwMTk3MTc5", + tag_name: "2019.1.1", + target_commitish: "develop", + name: "2019.2.1", + draft: false, + author: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + prerelease: false, + created_at: "2019-09-20T06:05:01Z", + published_at: "2019-09-24T01:06:14Z", + assets: [ + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083635", + id: 15083635, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM1", + name: "equella-installer-2019.1.1.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 311597191, + download_count: 8, + created_at: "2019-09-24T01:07:56Z", + updated_at: "2019-09-24T01:09:28Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/equella-installer-2019.1.1.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083636", + id: 15083636, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM2", + name: "reference-language-pack.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 131816, + download_count: 12, + created_at: "2019-09-24T01:07:57Z", + updated_at: "2019-09-24T01:09:29Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/reference-language-pack.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083637", + id: 15083637, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM3", + name: "scriptingapi-javadoc-2019.1.1-Stable.OSE-g3a1c903.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 220033, + download_count: 2, + created_at: "2019-09-24T01:07:57Z", + updated_at: "2019-09-24T01:09:29Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/scriptingapi-javadoc-2019.1.1-Stable.OSE-g3a1c903.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083638", + id: 15083638, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM4", + name: "tle-upgrade-2019.1.r20190920.2019.1.1-Stable.OSE.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 295780946, + download_count: 4, + created_at: "2019-09-24T01:07:57Z", + updated_at: "2019-09-24T01:11:03Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/tle-upgrade-2019.1.r20190920.2019.1.1-Stable.OSE.zip" + } + ], + tarball_url: + "https://api.github.com/repos/openequella/openEQUELLA/tarball/2019.1.1", + zipball_url: + "https://api.github.com/repos/openequella/openEQUELLA/zipball/2019.1.1", + body: + "This is the first hotfix for 2019.1. It includes the following fixes:\r\n\r\n* [List of GitHub Issues](https://github.com/openequella/openEQUELLA/issues?q=is%3Aissue+label%3A2019.1.1+is%3Aclosed)\r\n\r\nOtherwise it also includes that found in [2019.1](https://github.com/openequella/openEQUELLA/releases/tag/2019.1-Stable)." + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/20197179", + assets_url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/20197179/assets", + upload_url: + "https://uploads.github.com/repos/openequella/openEQUELLA/releases/20197179/assets{?name,label}", + html_url: + "https://github.com/openequella/openEQUELLA/releases/tag/2019.1.1", + id: 20197189, + node_id: "MDc6UmVsZWFzZTIwMTk3MTc5", + tag_name: "2019.2.1", + target_commitish: "develop", + name: "2019.2.0", + draft: false, + author: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + prerelease: false, + created_at: "2019-09-20T06:05:01Z", + published_at: "2019-09-24T01:06:14Z", + assets: [ + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083635", + id: 15083635, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM1", + name: "equella-installer-2019.1.1.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 311597191, + download_count: 8, + created_at: "2019-09-24T01:07:56Z", + updated_at: "2019-09-24T01:09:28Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/equella-installer-2019.1.1.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083636", + id: 15083636, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM2", + name: "reference-language-pack.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 131816, + download_count: 12, + created_at: "2019-09-24T01:07:57Z", + updated_at: "2019-09-24T01:09:29Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/reference-language-pack.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083637", + id: 15083637, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM3", + name: "scriptingapi-javadoc-2019.1.1-Stable.OSE-g3a1c903.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 220033, + download_count: 2, + created_at: "2019-09-24T01:07:57Z", + updated_at: "2019-09-24T01:09:29Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/scriptingapi-javadoc-2019.1.1-Stable.OSE-g3a1c903.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083638", + id: 15083638, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM4", + name: "tle-upgrade-2019.1.r20190920.2019.1.1-Stable.OSE.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 295780946, + download_count: 4, + created_at: "2019-09-24T01:07:57Z", + updated_at: "2019-09-24T01:11:03Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/tle-upgrade-2019.1.r20190920.2019.1.1-Stable.OSE.zip" + } + ], + tarball_url: + "https://api.github.com/repos/openequella/openEQUELLA/tarball/2019.1.1", + zipball_url: + "https://api.github.com/repos/openequella/openEQUELLA/zipball/2019.1.1", + body: + "This is the first hotfix for 2019.1. It includes the following fixes:\r\n\r\n* [List of GitHub Issues](https://github.com/openequella/openEQUELLA/issues?q=is%3Aissue+label%3A2019.1.1+is%3Aclosed)\r\n\r\nOtherwise it also includes that found in [2019.1](https://github.com/openequella/openEQUELLA/releases/tag/2019.1-Stable)." + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/20197179", + assets_url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/20197179/assets", + upload_url: + "https://uploads.github.com/repos/openequella/openEQUELLA/releases/20197179/assets{?name,label}", + html_url: + "https://github.com/openequella/openEQUELLA/releases/tag/2019.1.1", + id: 20197179, + node_id: "MDc6UmVsZWFzZTIwMTk3MTc5", + tag_name: "2019.1.1", + target_commitish: "develop", + name: "2019.1.1", + draft: false, + author: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + prerelease: false, + created_at: "2019-09-20T06:05:01Z", + published_at: "2019-09-24T01:06:14Z", + assets: [ + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083635", + id: 15083635, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM1", + name: "equella-installer-2019.1.1.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 311597191, + download_count: 8, + created_at: "2019-09-24T01:07:56Z", + updated_at: "2019-09-24T01:09:28Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/equella-installer-2019.1.1.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083636", + id: 15083636, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM2", + name: "reference-language-pack.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 131816, + download_count: 12, + created_at: "2019-09-24T01:07:57Z", + updated_at: "2019-09-24T01:09:29Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/reference-language-pack.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083637", + id: 15083637, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM3", + name: "scriptingapi-javadoc-2019.1.1-Stable.OSE-g3a1c903.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 220033, + download_count: 2, + created_at: "2019-09-24T01:07:57Z", + updated_at: "2019-09-24T01:09:29Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/scriptingapi-javadoc-2019.1.1-Stable.OSE-g3a1c903.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/15083638", + id: 15083638, + node_id: "MDEyOlJlbGVhc2VBc3NldDE1MDgzNjM4", + name: "tle-upgrade-2019.1.r20190920.2019.1.1-Stable.OSE.zip", + label: null, + uploader: { + login: "PenghaiZhang", + id: 47203811, + node_id: "MDQ6VXNlcjQ3MjAzODEx", + avatar_url: "https://avatars0.githubusercontent.com/u/47203811?v=4", + gravatar_id: "", + url: "https://api.github.com/users/PenghaiZhang", + html_url: "https://github.com/PenghaiZhang", + followers_url: "https://api.github.com/users/PenghaiZhang/followers", + following_url: + "https://api.github.com/users/PenghaiZhang/following{/other_user}", + gists_url: + "https://api.github.com/users/PenghaiZhang/gists{/gist_id}", + starred_url: + "https://api.github.com/users/PenghaiZhang/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/PenghaiZhang/subscriptions", + organizations_url: "https://api.github.com/users/PenghaiZhang/orgs", + repos_url: "https://api.github.com/users/PenghaiZhang/repos", + events_url: + "https://api.github.com/users/PenghaiZhang/events{/privacy}", + received_events_url: + "https://api.github.com/users/PenghaiZhang/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 295780946, + download_count: 4, + created_at: "2019-09-24T01:07:57Z", + updated_at: "2019-09-24T01:11:03Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1.1/tle-upgrade-2019.1.r20190920.2019.1.1-Stable.OSE.zip" + } + ], + tarball_url: + "https://api.github.com/repos/openequella/openEQUELLA/tarball/2019.1.1", + zipball_url: + "https://api.github.com/repos/openequella/openEQUELLA/zipball/2019.1.1", + body: + "This is the first hotfix for 2019.1. It includes the following fixes:\r\n\r\n* [List of GitHub Issues](https://github.com/openequella/openEQUELLA/issues?q=is%3Aissue+label%3A2019.1.1+is%3Aclosed)\r\n\r\nOtherwise it also includes that found in [2019.1](https://github.com/openequella/openEQUELLA/releases/tag/2019.1-Stable)." + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/18976802", + assets_url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/18976802/assets", + upload_url: + "https://uploads.github.com/repos/openequella/openEQUELLA/releases/18976802/assets{?name,label}", + html_url: + "https://github.com/openequella/openEQUELLA/releases/tag/2019.1-Stable", + id: 18976802, + node_id: "MDc6UmVsZWFzZTE4OTc2ODAy", + tag_name: "2019.1-Stable", + target_commitish: "develop", + name: "2019.1", + draft: false, + author: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + prerelease: false, + created_at: "2019-07-31T00:48:12Z", + published_at: "2019-07-31T07:43:04Z", + assets: [ + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/14023727", + id: 14023727, + node_id: "MDEyOlJlbGVhc2VBc3NldDE0MDIzNzI3", + name: "equella-installer-2019.1.zip", + label: null, + uploader: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: + "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 311497140, + download_count: 43, + created_at: "2019-07-31T07:41:13Z", + updated_at: "2019-07-31T07:42:48Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1-Stable/equella-installer-2019.1.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/14023671", + id: 14023671, + node_id: "MDEyOlJlbGVhc2VBc3NldDE0MDIzNjcx", + name: "reference-language-pack.zip", + label: null, + uploader: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: + "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 131827, + download_count: 13, + created_at: "2019-07-31T07:38:08Z", + updated_at: "2019-07-31T07:38:11Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1-Stable/reference-language-pack.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/14023670", + id: 14023670, + node_id: "MDEyOlJlbGVhc2VBc3NldDE0MDIzNjcw", + name: "scriptingapi-javadoc-2019.1-Stable.OSE-r2-g8cf2a6c-SNAPSHOT.zip", + label: null, + uploader: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: + "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 220169, + download_count: 10, + created_at: "2019-07-31T07:38:08Z", + updated_at: "2019-07-31T07:38:10Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1-Stable/scriptingapi-javadoc-2019.1-Stable.OSE-r2-g8cf2a6c-SNAPSHOT.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/14023691", + id: 14023691, + node_id: "MDEyOlJlbGVhc2VBc3NldDE0MDIzNjkx", + name: "tle-upgrade-2019.1.r2.2019.1-Stable.OSE.zip", + label: null, + uploader: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: + "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 295682427, + download_count: 18, + created_at: "2019-07-31T07:39:15Z", + updated_at: "2019-07-31T07:40:54Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2019.1-Stable/tle-upgrade-2019.1.r2.2019.1-Stable.OSE.zip" + } + ], + tarball_url: + "https://api.github.com/repos/openequella/openEQUELLA/tarball/2019.1-Stable", + zipball_url: + "https://api.github.com/repos/openequella/openEQUELLA/zipball/2019.1-Stable", + body: + "**openEQUELLA 2019.1**\r\n\r\nPlease see https://version.openequella.net/ for future upgrades and changelogs.\r\n\r\nDocumentation can be found at the openEQUELLA [documentation site](https://openequella.github.io/).\r\n\r\n**Key features:**\r\n\r\n* **Administration Console Package** – this package bundles the Java Runtime Environment (JRE) with the Administration Console and allows users to access the Administration Console on local systems. This will remove the requirement to install Java locally and this package will be the access point to the Administration Console from openEQUELLA 2019.1 forward.\r\n\r\n* **Login Notice Editor** - openEQUELLA 2019.1 introduces the ability to create content using a rich text editor (TinyMCE 5.0.2) to display as a notice on the Login page.\r\n\r\n* **Support for Languages other than English** - expanded support for languages other than English in openEQUELLA’s search capabilities (such as recognising the specified language’s stop words, stemming, etc.).\r\n\r\n* **REST API Enhancements** – including search API documentation enhancements and the editing of attachments and metadata\r\n\r\n* **Cloud providers** – ability to register openEQUELLA with Cloud providers that deliver cloud services to openEQUELLA content.\r\n\r\n* **Enhanced Blackboard Integration** - a pure LTI / REST integration has started to be developed. This integration is available in this release as a 'beta' feature with a minimal set of functionality, and will be enhanced for 2019.2.\r\n\r\nFurther details can be found in the [openEQUELLA 2019.1 Features Guide](https://openequella.github.io/guides/featureGuides/featureGuide2019.1/openEQUELLA-2019.1-FeaturesGuide.html)." + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/14652766", + assets_url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/14652766/assets", + upload_url: + "https://uploads.github.com/repos/openequella/openEQUELLA/releases/14652766/assets{?name,label}", + html_url: + "https://github.com/openequella/openEQUELLA/releases/tag/2018.2-Stable", + id: 14652766, + node_id: "MDc6UmVsZWFzZTE0NjUyNzY2", + tag_name: "2018.2-Stable", + target_commitish: "master", + name: "2018.2", + draft: false, + author: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + prerelease: false, + created_at: "2018-12-21T00:20:22Z", + published_at: "2018-12-21T05:52:01Z", + assets: [ + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/10255967", + id: 10255967, + node_id: "MDEyOlJlbGVhc2VBc3NldDEwMjU1OTY3", + name: "equella-installer-2018.2.zip", + label: null, + uploader: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: + "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 295101809, + download_count: 76, + created_at: "2018-12-21T05:38:13Z", + updated_at: "2018-12-21T05:42:40Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2018.2-Stable/equella-installer-2018.2.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/10255969", + id: 10255969, + node_id: "MDEyOlJlbGVhc2VBc3NldDEwMjU1OTY5", + name: "reference-language-pack.zip", + label: null, + uploader: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: + "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 130400, + download_count: 16, + created_at: "2018-12-21T05:38:14Z", + updated_at: "2018-12-21T05:42:43Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2018.2-Stable/reference-language-pack.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/10255968", + id: 10255968, + node_id: "MDEyOlJlbGVhc2VBc3NldDEwMjU1OTY4", + name: "scriptingapi-javadoc-2018.2-Stable.OSE-r1-ga5e0b20.zip", + label: null, + uploader: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: + "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 220179, + download_count: 10, + created_at: "2018-12-21T05:38:14Z", + updated_at: "2018-12-21T05:42:42Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2018.2-Stable/scriptingapi-javadoc-2018.2-Stable.OSE-r1-ga5e0b20.zip" + }, + { + url: + "https://api.github.com/repos/openequella/openEQUELLA/releases/assets/10255966", + id: 10255966, + node_id: "MDEyOlJlbGVhc2VBc3NldDEwMjU1OTY2", + name: "tle-upgrade-2018.2.r1.2018.2-Stable.OSE.zip", + label: null, + uploader: { + login: "edalex-ian", + id: 43919233, + node_id: "MDQ6VXNlcjQzOTE5MjMz", + avatar_url: "https://avatars3.githubusercontent.com/u/43919233?v=4", + gravatar_id: "", + url: "https://api.github.com/users/edalex-ian", + html_url: "https://github.com/edalex-ian", + followers_url: "https://api.github.com/users/edalex-ian/followers", + following_url: + "https://api.github.com/users/edalex-ian/following{/other_user}", + gists_url: "https://api.github.com/users/edalex-ian/gists{/gist_id}", + starred_url: + "https://api.github.com/users/edalex-ian/starred{/owner}{/repo}", + subscriptions_url: + "https://api.github.com/users/edalex-ian/subscriptions", + organizations_url: "https://api.github.com/users/edalex-ian/orgs", + repos_url: "https://api.github.com/users/edalex-ian/repos", + events_url: + "https://api.github.com/users/edalex-ian/events{/privacy}", + received_events_url: + "https://api.github.com/users/edalex-ian/received_events", + type: "User", + site_admin: false + }, + content_type: "application/zip", + state: "uploaded", + size: 279379717, + download_count: 19, + created_at: "2018-12-21T05:38:13Z", + updated_at: "2018-12-21T05:40:16Z", + browser_download_url: + "https://github.com/openequella/openEQUELLA/releases/download/2018.2-Stable/tle-upgrade-2018.2.r1.2018.2-Stable.OSE.zip" + } + ], + tarball_url: + "https://api.github.com/repos/openequella/openEQUELLA/tarball/2018.2-Stable", + zipball_url: + "https://api.github.com/repos/openequella/openEQUELLA/zipball/2018.2-Stable", + body: + "**openEQUELLA 2018.2**\r\n\r\nPlease see https://version.openequella.net/ for future upgrades and changelogs.\r\n\r\nDocumentation can be found at the openEQUELLA [documentation site](https://openequella.github.io/).\r\n\r\nKey features:\r\n\r\n* **Views counts for summary pages and attachments** – Views counts can now be displayed for summary pages and attachments.\r\n* **Streamlined process for attaching EQUELLA resources during contribution** – an option to remove a number of dialogs during the selection of EQUELLA resources during contribution has been added.\r\n* **Course selector updated across EQUELLA** – the course selector has been updated to allow searching of Title, Code and Description with a scrollable list.\r\n* **HTTP Referrers added to log** – HTTP referrers are now recorded in the audit log to enable identification of an item’s LMS usage.\r\n* **Theme Editor (for New UI)** – a new Theme Editor is available to apply colour schemes to new UI components and upload logos.\r\n" + } +]; diff --git a/Source/Plugins/Core/com.equella.core/js/__tests__/versioncheck.test.js b/Source/Plugins/Core/com.equella.core/js/__tests__/versioncheck.test.js new file mode 100644 index 0000000000..40f60c42f0 --- /dev/null +++ b/Source/Plugins/Core/com.equella.core/js/__tests__/versioncheck.test.js @@ -0,0 +1,43 @@ +// versioncheck.js is not processed by Parcel and it only serves to the browser. +// So here need to read the file and then evaluate its content +const mockData = require("../__mocks__/versioncheck_mock_data"); +const fs = require("fs"); +const version_check_js_file = fs.readFileSync( + "../resources/web/js/versioncheck.js", + "utf8" +); +eval(version_check_js_file); + +test("Test major updates", () => { + const checkResult = createCheckResult("2018.1.0", mockData.mockReleases); + expect(checkResult.newer).toBe(true); + expect(checkResult.newerReleases.majorUpdate.major).toBe("2019"); +}); + +test("Test minor updates", () => { + const checkResult = createCheckResult("2019.1.1", mockData.mockReleases); + expect(checkResult.newer).toBe(true); + + const minorUpdateRelease = checkResult.newerReleases.minorUpdate; + expect(minorUpdateRelease.major).toBe("2019"); + expect(minorUpdateRelease.minor).toBe("2"); +}); + +test("Test patch updates", () => { + const checkResult = createCheckResult("2019.2.0", mockData.mockReleases); + expect(checkResult.newer).toBe(true); + + const patchUpdateRelease = checkResult.newerReleases.patchUpdate; + expect(patchUpdateRelease.major).toBe("2019"); + expect(patchUpdateRelease.minor).toBe("2"); + expect(patchUpdateRelease.patch).toBe("1"); +}); + +test("Test no updates", () => { + const checkResult = createCheckResult("2020.1.0", mockData.mockReleases); + expect(checkResult.newer).toBe(false); + + expect(checkResult.newerReleases.majorUpdate).toBe(null); + expect(checkResult.newerReleases.minorUpdate).toBe(null); + expect(checkResult.newerReleases.patchUpdate).toBe(null); +}); diff --git a/Source/Plugins/Core/com.equella.core/js/package.json b/Source/Plugins/Core/com.equella.core/js/package.json index 120a5dc798..57a84b5599 100644 --- a/Source/Plugins/Core/com.equella.core/js/package.json +++ b/Source/Plugins/Core/com.equella.core/js/package.json @@ -6,7 +6,10 @@ "devlang": "../target/scala-2.12/classes/lang", "devjs": "../target/scala-2.12/classes/web/reactjs", "psglob": "output/*/*.js", - "dist": "target/resources/web/reactjs" + "dist": "target/resources/web/reactjs", + "jest": { + "verbose": true + } }, "scripts": { "install": "cross-env-shell \"psc-package install && mkdirp ${npm_package_config_devlang} ${npm_package_config_buildlang}\"", @@ -21,7 +24,8 @@ "bundleps:main": "cross-env-shell \"purs bundle \"${npm_package_config_psglob}\" -m Bridge --main Bridge -o entrybuild/target/main.js\"", "bundleps:selection": "cross-env-shell \"purs bundle \"${npm_package_config_psglob}\" -m OEQ.SelectionUI.Main --main OEQ.SelectionUI.Main -o entrybuild/target/selection.js\"", "bundleps:uploadlist": "cross-env-shell \"purs bundle \"${npm_package_config_psglob}\" -m Uploads.UploadList --main Uploads.UploadList -o entrybuild/target/uploadlist.js\"", - "bundleps:langbundle": "cross-env-shell \"purs bundle \"${npm_package_config_psglob}\" -m Tools.GenLangStrings --main Tools.GenLangStrings -o target/genlang.js\"" + "bundleps:langbundle": "cross-env-shell \"purs bundle \"${npm_package_config_psglob}\" -m Tools.GenLangStrings --main Tools.GenLangStrings -o target/genlang.js\"", + "test": "jest test" }, "dependencies": { "@date-io/luxon": "1.3.7", @@ -88,6 +92,7 @@ "cross-spawn": "6.0.5", "css-vars-ponyfill": "1.17.2", "envify": "4.1.0", + "jest": "24.9.0", "mkdirp": "0.5.1", "npm-run-all": "4.1.5", "psc-package": "3.0.1", diff --git a/Source/Plugins/Core/com.equella.core/resources/lang/i18n-resource-centre.properties b/Source/Plugins/Core/com.equella.core/resources/lang/i18n-resource-centre.properties index 669b2ca42b..d34e55bf65 100644 --- a/Source/Plugins/Core/com.equella.core/resources/lang/i18n-resource-centre.properties +++ b/Source/Plugins/Core/com.equella.core/resources/lang/i18n-resource-centre.properties @@ -4328,8 +4328,13 @@ validation.script.empty=There is no script to save validation.uuidcannotchange=The UUID field cannot be changed version.checking=Checking to see if your version is up-to-date. version.checklatest=Version check -version.latest=You have the latest version. -version.new=A newer version is available. See here for details. +version.no.newer.version.found=You are on the latest version. +version.major.latest=You have the latest major version. +version.major.new=A newer major version is available. See here for details. +version.minor.latest=You have the latest minor version. +version.minor.new=A newer minor version is available. See here for details. +version.patch.latest=You have the latest patch version. +version.patch.new=A newer patch version is available. See here for details. versiondialog.title=Edit resource selections versionselection.checklist.label=Specify current or latest version selection versionselection.title=Version selection diff --git a/Source/Plugins/Core/com.equella.core/resources/view/tab/health.ftl b/Source/Plugins/Core/com.equella.core/resources/view/tab/health.ftl index 8ac73b88b5..177ecaf509 100644 --- a/Source/Plugins/Core/com.equella.core/resources/view/tab/health.ftl +++ b/Source/Plugins/Core/com.equella.core/resources/view/tab/health.ftl @@ -3,16 +3,46 @@

${b.key("version.checklatest")}

- <@a.div id="latestVersion"> - <#if m.onLatestVersion> - ${b.key("version.latest")} - <#elseif m.versionInfoUrl??> - ${b.key("version.new", [m.versionInfoUrl])} - <#else> - ${b.key("version.checking")} - - -
+ <@a.div id="latestVersion"> + <#if m.newerVersionFound> +
+ + <#if m.onLatestMajorVersion> + ${b.key("version.major.latest")} + <#elseif m.majorUpdateUrl??> + ${b.key("version.major.new", [m.majorUpdateUrl])} + <#else> + ${b.key("version.checking")} + + +
+ + <#if m.onLatestMinorVersion> + ${b.key("version.minor.latest")} + <#elseif m.minorUpdateUrl??> + ${b.key("version.minor.new", [m.minorUpdateUrl])} + <#else> + ${b.key("version.checking")} + + +
+ + <#if m.onLatestPacthVersion> + ${b.key("version.patch.latest")} + <#elseif m.patchUpdateUrl??> + ${b.key("version.patch.new", [m.patchUpdateUrl])} + <#else> + ${b.key("version.checking")} + +
+ <#else > + ${b.key("version.no.newer.version.found")} +
+ + + + +

${b.key("clusternodes.health")}

<#if m.cluster>

${b.key("clusternodes.ids")}

@@ -38,4 +68,4 @@ <@render s.institutionUsageTable /> -
\ No newline at end of file + diff --git a/Source/Plugins/Core/com.equella.core/resources/web/js/versioncheck.js b/Source/Plugins/Core/com.equella.core/resources/web/js/versioncheck.js index d9f2bf3af9..2d4535b28b 100644 --- a/Source/Plugins/Core/com.equella.core/resources/web/js/versioncheck.js +++ b/Source/Plugins/Core/com.equella.core/resources/web/js/versioncheck.js @@ -1,8 +1,161 @@ -function checkVersion(mmr, commit, display, versionUrl, aurl, cb) -{ - $.ajax(versionUrl + "?mmr=" + encodeURIComponent(mmr) + "&commit=" + encodeURIComponent(commit) - + "&display=" + encodeURIComponent(display) +"&aurl=" + encodeURIComponent(aurl)).done(function (data){ - cb(data.newer, data.url); +function checkVersion(currentVersion, callback) { + const releaseCheckUrl = + "https://api.github.com/repos/openequella/openEQUELLA/releases"; + $.ajax(releaseCheckUrl).done(function(data) { + const checkResult = createCheckResult(currentVersion, data); + callback(checkResult.newer, JSON.stringify(checkResult.newerReleases)); + }); +} + +function createCheckResult(currentVersion, data) { + let newerReleaseFound = false; + let newerReleases = null; + const parsedVersion = parseVersion(currentVersion); + + if (parsedVersion != null) { + const releaseList = getReleaseList(data); + + const latestMajorRelease = getLatestMajorRelease( + releaseList, + parsedVersion + ); + const latestMinorRelease = getLatestMinorRelease( + releaseList, + parsedVersion + ); + const latestPatchRelease = getLatestPatchRelease( + releaseList, + parsedVersion + ); + + newerReleaseFound = + latestMajorRelease != null || + latestMinorRelease != null || + latestPatchRelease != null; + newerReleases = { + majorUpdate: latestMajorRelease, + minorUpdate: latestMinorRelease, + patchUpdate: latestPatchRelease + }; + } else { + console.log( + `Current version ${currentVersion} does not match the semantic version rule` + ); + } + return { newer: newerReleaseFound, newerReleases: newerReleases }; +} + +function getReleaseList(data) { + const releaseList = []; + data.forEach(function(value) { + const releaseVersion = value.name; + const releaseUrl = value.html_url; + const parsedVersion = parseVersion(releaseVersion); + // We only want releases which support the semantic version + if (parsedVersion != null) { + releaseList.push({ + major: parsedVersion.major, + minor: parsedVersion.minor, + patch: parsedVersion.patch, + url: releaseUrl + }); + } + }); + return releaseList; +} + +function getLatestMajorRelease(releaseList, parsedVersion) { + // Find out all major releases published after current version + const majorReleaseList = releaseList.filter(function(release) { + return release.major > parsedVersion.major; + }); + + if (majorReleaseList.length > 0) { + // Find out the latest major release + const latestMajorRelease = majorReleaseList.reduce((release1, release2) => { + const newerMajorFound = release1.major < release2.major; + const newerMinorFound = + release1.major === release2.major && release1.minor < release2.minor; + const newerPatchFound = + release1.major === release2.major && + release1.minor === release2.minor && + release1.patch < release2.patch; + + if (newerMajorFound || newerMinorFound || newerPatchFound) { + return release2; + } + return release1; + }); + + return latestMajorRelease; + } + return null; +} + +function getLatestMinorRelease(releaseList, parsedVersion) { + // Find out all minor releases published after current version + const minorReleaseList = releaseList.filter(function(release) { + return ( + release.major === parsedVersion.major && + release.minor > parsedVersion.minor + ); + }); + + if (minorReleaseList.length > 0) { + // Find out the latest minor release + const latestMinorRelease = minorReleaseList.reduce((release1, release2) => { + const newerMinorFound = release1.minor < release2.minor; + const newerPatchFound = + release1.minor === release2.minor && release1.patch < release2.patch; + + if (newerMinorFound || newerPatchFound) { + return release2; + } + return release1; }); + return latestMinorRelease; + } + return null; +} + +function getLatestPatchRelease(releaseList, parsedVersion) { + // Find out all patch releases published after current version + const patchReleaseList = releaseList.filter(function(release) { + return ( + release.major === parsedVersion.major && + release.minor === parsedVersion.minor && + release.patch > parsedVersion.patch + ); + }); + + if (patchReleaseList.length > 0) { + // Find out the latest patch release + const latestPatchRelease = patchReleaseList.reduce((release1, release2) => { + if (release1.patch < release2.patch) { + return release2; + } + return release1; + }); + + return latestPatchRelease; + } + return null; +} + +function parseVersion(version) { + // This regex checks if a version number matches the rule of semantic version. + // For example, an expected input is '2019.1.1' (not including single quotes). + // And the expected output is an array: [ '2019.1.1', '2019', '1', '1']. + const semanticVersionPattern = new RegExp(/^(\d+)\.(\d+)\.(\d+)$/); -} \ No newline at end of file + const parsedVersion = version.match(semanticVersionPattern); + let result = null; + if (parsedVersion) { + result = { + major: parsedVersion[1], + minor: parsedVersion[2], + patch: parsedVersion[3] + }; + } + return result; +} diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/institution/tab/HealthTab.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/institution/tab/HealthTab.java index 0e204b47e0..83476620f7 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/institution/tab/HealthTab.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/institution/tab/HealthTab.java @@ -164,6 +164,10 @@ public class HealthTab extends AbstractInstitutionTab { @PlugKey("institutionusage.name") private static Label INST_NAME; + private final String MAJOR_UPDATE = "majorUpdate"; + private final String MINOR_UPDATE = "minorUpdate"; + private final String PATCH_UPDATE = "patchUpdate"; + private static IncludeFile SERVICES_INCLUDE = new IncludeFile(SERVICES_JS_URL, JQueryTimer.PRERENDER); private static JSCallAndReference REFRESH_FUNC = @@ -271,14 +275,7 @@ public SectionResult renderHtml(RenderEventContext context) throws Exception { context.getBody().addReadyStatements(refreshHandler, usageRefreshHandler); context .getBody() - .addReadyStatements( - CHECK_VERSION, - version.getSemanticVersion(), - version.getCommit(), - version.getDisplay(), - VERSION_SERVER_URL, - urlService.getAdminUrl().toString(), - updateVersionCheck); + .addReadyStatements(CHECK_VERSION, version.getSemanticVersion(), updateVersionCheck); return viewFactory.createResult("tab/health.ftl", context); } @@ -356,12 +353,31 @@ private TableState buildServicesTable(String nodeId) { } @EventHandlerMethod - public void versionResponse(SectionInfo info, boolean newer, String infoUrl) { + public void versionResponse( + SectionInfo info, boolean newer, Map newReleases) { ClusterModel model = getModel(info); if (newer) { - model.setVersionInfoUrl(infoUrl); - } else { - model.setOnLatestVersion(true); + model.setNewerVersionFound(true); + NewerRelease newerMajorRelease = newReleases.get(MAJOR_UPDATE); + if (newerMajorRelease != null) { + model.setMajorUpdateUrl(newerMajorRelease.url); + } else { + model.setOnLatestMajorVersion(true); + } + + NewerRelease newerMinorRelease = newReleases.get(MINOR_UPDATE); + if (newerMinorRelease != null) { + model.setMinorUpdateUrl(newerMinorRelease.url); + } else { + model.setOnLatestMinorVersion(true); + } + + NewerRelease newerPatchRelease = newReleases.get(PATCH_UPDATE); + if (newerPatchRelease != null) { + model.setPatchUpdateUrl(newerPatchRelease.url); + } else { + model.setOnLatestPatchVersion(true); + } } } @@ -422,12 +438,72 @@ public Table getInstitutionUsageTable() { public static class ClusterModel { private boolean isCluster; - private String versionInfoUrl; - private boolean onLatestVersion; - + private boolean newerVersionFound; + private String majorUpdateUrl; + private boolean onLatestMajorVersion; + private String minorUpdateUrl; + private boolean onLatestMinorVersion; + private String patchUpdateUrl; + private boolean onLatestPatchVersion; private Map quotas = Maps.newHashMap(); private boolean displayQuotas; + public String getMajorUpdateUrl() { + return majorUpdateUrl; + } + + public void setMajorUpdateUrl(String majorUpdateUrl) { + this.majorUpdateUrl = majorUpdateUrl; + } + + public boolean isOnLatestMajorVersion() { + return onLatestMajorVersion; + } + + public void setOnLatestMajorVersion(boolean onLatestMajorVersion) { + this.onLatestMajorVersion = onLatestMajorVersion; + } + + public String getMinorUpdateUrl() { + return minorUpdateUrl; + } + + public void setMinorUpdateUrl(String minorUpdateUrl) { + this.minorUpdateUrl = minorUpdateUrl; + } + + public boolean isOnLatestMinorVersion() { + return onLatestMinorVersion; + } + + public void setOnLatestMinorVersion(boolean onLatestMinorVersion) { + this.onLatestMinorVersion = onLatestMinorVersion; + } + + public String getPatchUpdateUrl() { + return patchUpdateUrl; + } + + public void setPatchUpdateUrl(String patchUpdateUrl) { + this.patchUpdateUrl = patchUpdateUrl; + } + + public boolean isOnLatestPacthVersion() { + return onLatestPatchVersion; + } + + public void setOnLatestPatchVersion(boolean onLatestPatchVersion) { + this.onLatestPatchVersion = onLatestPatchVersion; + } + + public boolean isNewerVersionFound() { + return newerVersionFound; + } + + public void setNewerVersionFound(boolean newerVersionFound) { + this.newerVersionFound = newerVersionFound; + } + public Map getQuotas() { return quotas; } @@ -451,21 +527,19 @@ public boolean isDisplayQuotas() { public void setDisplayQuotas(boolean displayQuotas) { this.displayQuotas = displayQuotas; } + } - public String getVersionInfoUrl() { - return versionInfoUrl; - } - - public void setVersionInfoUrl(String versionInfoUrl) { - this.versionInfoUrl = versionInfoUrl; - } - - public boolean isOnLatestVersion() { - return onLatestVersion; - } - - public void setOnLatestVersion(boolean onLatestVersion) { - this.onLatestVersion = onLatestVersion; + class NewerRelease { + private String major; + private String minor; + private String patch; + private String url; + + public NewerRelease(String major, String minor, String patch, String url) { + this.major = major; + this.minor = minor; + this.patch = patch; + this.url = url; } } } diff --git a/buildspec.yml b/buildspec.yml index a2f84104fa..55d2f72ccd 100644 --- a/buildspec.yml +++ b/buildspec.yml @@ -17,6 +17,7 @@ phases: - service postgresql start build: commands: + - cd Source/Plugins/Core/com.equella.core/js && npm install && npm test; cd - - sbt -no-colors -Dconfig.file=${HOME}/build.conf test installerZip writeLanguagePack writeScriptingJavadoc - sbt -mem 2048 -no-colors "project autotest" installEquella startEquella configureInstall setupForTests Tests/test Tests/Serial/test OldTests/test coverageReport - (cd import-export-tool && ./gradlew build); cd - From 10e1308af826c29ebdcb9e242f70de8c1383f211 Mon Sep 17 00:00:00 2001 From: PenghaiZhang <47203811+PenghaiZhang@users.noreply.github.com> Date: Thu, 31 Oct 2019 14:34:21 +1100 Subject: [PATCH 05/13] Run the npm test in a subshell so it does not change the directory (#1331) --- buildspec.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildspec.yml b/buildspec.yml index 55d2f72ccd..14f4f41913 100644 --- a/buildspec.yml +++ b/buildspec.yml @@ -17,7 +17,7 @@ phases: - service postgresql start build: commands: - - cd Source/Plugins/Core/com.equella.core/js && npm install && npm test; cd - + - (cd Source/Plugins/Core/com.equella.core/js && npm install && npm test) - sbt -no-colors -Dconfig.file=${HOME}/build.conf test installerZip writeLanguagePack writeScriptingJavadoc - sbt -mem 2048 -no-colors "project autotest" installEquella startEquella configureInstall setupForTests Tests/test Tests/Serial/test OldTests/test coverageReport - (cd import-export-tool && ./gradlew build); cd - From 500341ad15642155315f5918364cf5bcf5f79041 Mon Sep 17 00:00:00 2001 From: PenghaiZhang <47203811+PenghaiZhang@users.noreply.github.com> Date: Tue, 5 Nov 2019 14:23:03 +1100 Subject: [PATCH 06/13] Disable the browser's cache for attachments (#1338) * enforce the browse to send a request to oEQ server to check if an attachment is on its latest version --- .../tle/web/viewitem/ItemFilestoreServlet.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ItemFilestoreServlet.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ItemFilestoreServlet.java index 1adcda7fad..00d2b065ec 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ItemFilestoreServlet.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ItemFilestoreServlet.java @@ -185,17 +185,10 @@ public InitialFilestoreStream( @SuppressWarnings("nls") @Override public String getCacheControl() { - // Before changing anything, read http://www.mnot.net/cache_docs/ - // - // The following settings mean that all caches will be able to keep - // a copy of the resource - the age values only specify how long - // before the cache must *revalidate* their copy. With these - // settings, browser caches can serve their copy for a whole day - // without needing to talk to the server. Shared caches (eg, a Squid - // proxy cache) must always revalidate before releasing their copy - // to ensure we're not returning a resource to a user who doesn't - // have access. - return "max-age=86400, s-maxage=0, must-revalidate"; + // Set 'max-age' to 0 so that the content of cache is always stale. + // Hence, the browser sends every request to the the Equella server which will then + // re-validate the content. + return "max-age=0, s-maxage=0, must-revalidate"; } @Override From 0d4739de05a5266aa26bdcd5fd7ff9bbfbefc5da Mon Sep 17 00:00:00 2001 From: Aaron Holland Date: Tue, 29 Oct 2019 14:08:23 +1100 Subject: [PATCH 07/13] Don't register a HEAD or OPTIONS request as a viewing * Don't register a HEAD or OPTIONS request as a viewing for the purposes of 'smart' auditing --- .../web/cloud/view/CloudViewItemAuditor.java | 3 +- .../section/RootCloudViewItemSection.java | 5 ++-- .../web/viewitem/ItemFilestoreServlet.java | 2 +- .../com/tle/web/viewitem/ViewItemAuditor.java | 25 ++++++++++++---- .../viewitem/section/RootItemFileSection.java | 30 +++++++++++++++---- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/cloud/view/CloudViewItemAuditor.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/cloud/view/CloudViewItemAuditor.java index 29288d7276..0c72c2ac6e 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/cloud/view/CloudViewItemAuditor.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/cloud/view/CloudViewItemAuditor.java @@ -27,6 +27,7 @@ import com.tle.web.viewurl.ViewAuditEntry; import javax.inject.Inject; import javax.inject.Singleton; +import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -55,7 +56,7 @@ public void setAuditLevelString(@Named("audit.level") String auditLevelString) { } } - public void audit(ViewAuditEntry auditEntry, ItemKey itemId) { + public void audit(HttpServletRequest request, ViewAuditEntry auditEntry, ItemKey itemId) { if (auditLevel != AuditLevel.NONE && auditEntry != null) { try { if (auditLevel == AuditLevel.NORMAL) { diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/cloud/view/section/RootCloudViewItemSection.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/cloud/view/section/RootCloudViewItemSection.java index 12db200d80..8d05fa0434 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/cloud/view/section/RootCloudViewItemSection.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/cloud/view/section/RootCloudViewItemSection.java @@ -88,14 +88,15 @@ public SectionResult renderHtml(RenderEventContext context) { if (viewer == null) { ViewAuditEntry vae = resource.getViewAuditEntry(); if (viewableItem.isItemForReal() && vae != null) { - auditor.audit(vae, viewableItem.getItemId()); + auditor.audit(context.getRequest(), vae, viewableItem.getItemId()); } context.forwardToUrl(resource.createCanonicalURL().getHref(), resource.getForwardCode()); return null; } if (viewableItem.isItemForReal()) { - auditor.audit(viewer.getAuditEntry(context, resource), viewableItem.getItemId()); + auditor.audit( + context.getRequest(), viewer.getAuditEntry(context, resource), viewableItem.getItemId()); } try { return viewer.view(context, resource); diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ItemFilestoreServlet.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ItemFilestoreServlet.java index 00d2b065ec..3c92731c85 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ItemFilestoreServlet.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ItemFilestoreServlet.java @@ -139,7 +139,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) } } if (itemId != null) { - auditor.audit(new ViewAuditEntry("file:" + mimeType, path), itemId, attachment); + auditor.audit(request, new ViewAuditEntry("file:" + mimeType, path), itemId, attachment); } contentStreamWriter.outputStream(request, response, filteredStream); } catch (AccessDeniedException ade) { diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ViewItemAuditor.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ViewItemAuditor.java index f4f9b63504..40a24656cf 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ViewItemAuditor.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/ViewItemAuditor.java @@ -31,6 +31,7 @@ import com.tle.web.viewurl.ViewAuditEntry; import javax.inject.Inject; import javax.inject.Singleton; +import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -59,15 +60,21 @@ public void setAuditLevelString(@Named("audit.level") String auditLevelString) { } } - public void audit(ViewAuditEntry auditEntry, ItemKey itemId, Attachment attachment) { - audit(auditEntry, itemId, () -> logViewed(itemId, attachment, auditEntry)); + public void audit( + HttpServletRequest request, + ViewAuditEntry auditEntry, + ItemKey itemId, + Attachment attachment) { + audit(request, auditEntry, itemId, () -> logViewed(itemId, attachment, auditEntry)); } - public void audit(ViewAuditEntry auditEntry, ViewableItem vitem) { - audit(auditEntry, vitem.getItemId(), () -> logViewed(vitem, auditEntry)); + public void audit( + HttpServletRequest request, ViewAuditEntry auditEntry, ViewableItem vitem) { + audit(request, auditEntry, vitem.getItemId(), () -> logViewed(vitem, auditEntry)); } - public void audit(ViewAuditEntry auditEntry, ItemKey itemId, AuditCall doAudit) { + public void audit( + HttpServletRequest request, ViewAuditEntry auditEntry, ItemKey itemId, AuditCall doAudit) { if (auditLevel != AuditLevel.NONE && auditEntry != null) { try { if (auditLevel == AuditLevel.NORMAL) { @@ -76,7 +83,13 @@ public void audit(ViewAuditEntry auditEntry, ItemKey itemId, AuditCall doAudit) // log it if it hasn't been already if (!isAlreadyViewed(itemId, auditEntry)) { doAudit.call(); - registerViewed(itemId, auditEntry); + // For HEAD and OPTION requests, don't record that we have already viewed. + // That way, if a follow up GET request is issued, we will record that too, along with + // the referrer header. + final String method = request.getMethod(); + if (!"OPTIONS".equals(method) && !"HEAD".equals(method)) { + registerViewed(itemId, auditEntry); + } } } } catch (Exception e) { diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/section/RootItemFileSection.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/section/RootItemFileSection.java index 7aa677bbb7..ad75796ef2 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/section/RootItemFileSection.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/viewitem/section/RootItemFileSection.java @@ -22,13 +22,14 @@ import com.tle.annotation.NonNullByDefault; import com.tle.annotation.Nullable; import com.tle.beans.item.Item; -import com.tle.beans.item.attachments.Attachment; import com.tle.beans.item.attachments.IAttachment; import com.tle.common.Check; +import com.tle.common.URLUtils; import com.tle.common.usermanagement.user.CurrentUser; import com.tle.core.institution.InstitutionService; import com.tle.core.mimetypes.MimeTypeService; import com.tle.core.services.FileSystemService; +import com.tle.core.services.UrlService; import com.tle.exceptions.AccessDeniedException; import com.tle.web.integration.Integration; import com.tle.web.integration.IntegrationSessionData; @@ -43,6 +44,7 @@ import com.tle.web.sections.annotations.Bookmarked; import com.tle.web.sections.annotations.DirectEvent; import com.tle.web.sections.events.BeforeEventsListener; +import com.tle.web.sections.events.BookmarkEvent; import com.tle.web.sections.events.ForwardEventListener; import com.tle.web.sections.events.RenderEventContext; import com.tle.web.sections.events.SectionEvent; @@ -100,6 +102,7 @@ public class RootItemFileSection @Inject private FileSystemService fileSystemService; @Inject private InstitutionService institutionService; @Inject private Provider itemInfoProvider; + @Inject private UrlService urlService; private final PathMapper pathMappedViewers = new PathMapper(); private final List filterViewers = new ArrayList(); @@ -145,7 +148,7 @@ public ViewItemResource getViewItemResource(SectionInfo info) { mimeType = mimeService.getMimeTypeForFilename(filename); } resource = - new BaseViewItemResource(getViewableItem(info), filename, mimeType, model.getViewer()); + getBaseViewItemResource(getViewableItem(info), filename, mimeType, model.getViewer()); for (ViewItemFilter filter : filterViewers) { resource = filter.filter(info, resource); @@ -235,17 +238,18 @@ public SectionResult renderHtml(RenderEventContext info) throws IOException { if (viewableItem.isItemForReal() && vae != null && viewableItem.getItemExtensionType() == null) { - auditor.audit(vae, ((ViewableItem) viewableItem)); + auditor.audit(info.getRequest(), vae, ((ViewableItem) viewableItem)); } - info.forwardToUrl(resource.createCanonicalURL().getHref(), resource.getForwardCode()); + info.forwardToUrl( + modifyHref(info, resource.createCanonicalURL().getHref()), resource.getForwardCode()); return null; } ensureOnePrivilege(resource.getPrivileges(), viewer.ensureOnePrivilege()); if (viewableItem.isItemForReal() && viewableItem.getItemExtensionType() == null) { auditor.audit( + info.getRequest(), viewer.getAuditEntry(info, resource), - viewableItem.getItemId(), - (Attachment) viewableItem.getAttachmentByUuid(viewableItem.getItemId().getUuid())); + (ViewableItem) viewableItem); } return viewer.view(info, resource); } catch (AccessDeniedException ade) { @@ -260,6 +264,20 @@ public SectionResult renderHtml(RenderEventContext info) throws IOException { } } + // Appalling hack to hide navigation when an error screen shows up... + private String modifyHref(SectionInfo info, String href) { + if (urlService.isRelativeUrl(href)) { + BookmarkEvent ev = new BookmarkEvent(info.lookupSection(RenderTemplate.class), false, info); + info.processEvent(ev); + String paramString = + SectionUtils.getParameterString( + SectionUtils.getParameterNameValues(ev.getBookmarkState(), true)); + + return URLUtils.appendQueryString(href, paramString); + } + return href; + } + private void checkRestrictedResource( SectionInfo info, ViewItemResource resource, @Nullable ViewItemViewer viewer) { boolean checkRestricted = false; From edef40230ccc184bf7150c256d7dfcd7434ebc81 Mon Sep 17 00:00:00 2001 From: edalex-ian <43919233+edalex-ian@users.noreply.github.com> Date: Wed, 16 Oct 2019 16:39:54 +1100 Subject: [PATCH 08/13] Merge pull request #1279 from abidingotter/bugfix/1198-error-screen-in-package-viewer Dirtiness to prevent navigation bars on error screen --- .../com.tle.platform.common/src/com/tle/common/URLUtils.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Platform/Plugins/com.tle.platform.common/src/com/tle/common/URLUtils.java b/Platform/Plugins/com.tle.platform.common/src/com/tle/common/URLUtils.java index 962eb62d1c..93bb254696 100644 --- a/Platform/Plugins/com.tle.platform.common/src/com/tle/common/URLUtils.java +++ b/Platform/Plugins/com.tle.platform.common/src/com/tle/common/URLUtils.java @@ -170,6 +170,9 @@ public static Map parseQueryString(String queryString, boolean s } public static String appendQueryString(String url, String qs) { + if (qs == null || qs.length() == 0) { + return url; + } if (url.indexOf('?') > 0) { return url + '&' + qs; } From 727cbf7996f2aafb4e143c586f65ebb926011cd2 Mon Sep 17 00:00:00 2001 From: Aaron Holland Date: Fri, 1 Nov 2019 15:10:11 +1100 Subject: [PATCH 09/13] Ensure advanced search controls added to tree when editing params --- .../searching/section/SearchQuerySection.java | 6 +++--- .../com/tle/web/sections/standard/Tree.java | 20 ++----------------- .../standard/model/HtmlTreeServer.java | 3 --- .../com/tle/web/wizard/page/WizardPage.java | 4 ++-- 4 files changed, 7 insertions(+), 26 deletions(-) diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/searching/section/SearchQuerySection.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/searching/section/SearchQuerySection.java index b48e1c093f..5ccdcce9f0 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/searching/section/SearchQuerySection.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/searching/section/SearchQuerySection.java @@ -759,7 +759,7 @@ public void loadPowerPage() { } catch (Exception e) { Throwables.propagate(e); } - powerPage.ensureTreeAdded(info, isSubmitWizard()); + powerPage.ensureTreeAdded(info, isEditQuery() || isSubmitWizard()); if (isSubmitWizard()) { info.queueEvent( @@ -886,8 +886,8 @@ public TextField getCurrentHidden() { @DirectEvent(priority = SectionEvent.PRIORITY_AFTER_EVENTS) public void ensurePowerPage(SectionInfo info) { SearchQueryModel model = getModel(info); - if (model.isSubmitWizard()) { - model.loadPowerPage(); + if (model.isSubmitWizard() || model.isEditQuery()) { + model.ensurePowerPage(); } } diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/sections/standard/Tree.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/sections/standard/Tree.java index 717bb882a4..fa01416715 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/sections/standard/Tree.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/sections/standard/Tree.java @@ -23,14 +23,12 @@ import com.tle.web.sections.Bookmark; import com.tle.web.sections.SectionId; import com.tle.web.sections.SectionInfo; -import com.tle.web.sections.SectionTree; import com.tle.web.sections.ajax.AjaxGenerator; import com.tle.web.sections.ajax.AjaxRenderContext; import com.tle.web.sections.ajax.JSONResponseCallback; import com.tle.web.sections.ajax.handler.AjaxFactory; import com.tle.web.sections.ajax.handler.AjaxMethod; import com.tle.web.sections.events.RenderContext; -import com.tle.web.sections.js.JSCallable; import com.tle.web.sections.render.SectionRenderable; import com.tle.web.sections.standard.model.HtmlComponentState; import com.tle.web.sections.standard.model.HtmlTreeModel; @@ -47,32 +45,18 @@ public class Tree extends AbstractDisablerComponent implements H private boolean allowMultipleOpenBranches; @AjaxFactory private AjaxGenerator ajaxMethods; - private JSCallable ajaxFunction; public Tree() { super(RendererConstants.TREE); } - @Override - public void registered(String id, SectionTree tree) { - super.registered(id, tree); - if (lazyLoad) { - ajaxFunction = ajaxMethods.getAjaxFunction("getTreeNodes"); // $NON-NLS-1$ - } - } - - @Override - public JSCallable getAjaxFunctionForNode(SectionInfo info, String nodeId) { - return ajaxFunction; - } - @Override public Bookmark getAjaxUrlForNode(SectionInfo info, String nodeId) { - return ajaxMethods.getAjaxUrl(info, "getTreeNodes", nodeId); // $NON-NLS-1$ + return ajaxMethods.getAjaxUrl(info, "getTreeNodes"); } @AjaxMethod - public JSONResponseCallback getTreeNodes(AjaxRenderContext context, String nodeId) { + public JSONResponseCallback getTreeNodes(AjaxRenderContext context) { context.setModalId(displayTree.getSectionId()); return getTreeRenderer(context).getJSONResponse(); } diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/sections/standard/model/HtmlTreeServer.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/sections/standard/model/HtmlTreeServer.java index f8f7928050..5f68c8d6a8 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/sections/standard/model/HtmlTreeServer.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/sections/standard/model/HtmlTreeServer.java @@ -21,11 +21,8 @@ import com.tle.annotation.NonNullByDefault; import com.tle.web.sections.Bookmark; import com.tle.web.sections.SectionInfo; -import com.tle.web.sections.js.JSCallable; @NonNullByDefault public interface HtmlTreeServer { Bookmark getAjaxUrlForNode(SectionInfo info, String nodeId); - - JSCallable getAjaxFunctionForNode(SectionInfo info, String nodeId); } diff --git a/Source/Plugins/Core/com.equella.core/src/com/tle/web/wizard/page/WizardPage.java b/Source/Plugins/Core/com.equella.core/src/com/tle/web/wizard/page/WizardPage.java index 3a8dd336fe..2e01986601 100644 --- a/Source/Plugins/Core/com.equella.core/src/com/tle/web/wizard/page/WizardPage.java +++ b/Source/Plugins/Core/com.equella.core/src/com/tle/web/wizard/page/WizardPage.java @@ -37,8 +37,6 @@ public interface WizardPage { void createPage() throws WizardPageException; - void ensureTreeAdded(SectionInfo info, boolean submitWizard); - void loadFromDocument(SectionInfo info); void saveToDocument(SectionInfo info) throws Exception; @@ -64,6 +62,8 @@ Map> renderPage( void ensureTreeAdded(SectionInfo info); + void ensureTreeAdded(SectionInfo info, boolean processParams); + void setSubmitted(boolean submitted); void setShowMandatory(boolean showMandatory); From 2c466e86d9af120593a3572aa632193fa9c48c90 Mon Sep 17 00:00:00 2001 From: Penghai Date: Thu, 14 Nov 2019 17:41:57 +1100 Subject: [PATCH 10/13] Enforce single attachment when appropriate (#1297) * An attachment control with no maximum attachments selected should only allow one attachment * Make sure the maximum attachment warning message use correct plural words --- .../js/src/Uploads/UploadList.purs | 13 +- .../lang/i18n-resource-centre.properties | 173 +++++++++--------- .../universal/UniversalWebControlNew.scala | 20 +- .../sections/result/util/PluralKeyLabel.java | 16 +- .../controls/MaxAttachmentsTest.java | 2 +- 5 files changed, 126 insertions(+), 98 deletions(-) diff --git a/Source/Plugins/Core/com.equella.core/js/src/Uploads/UploadList.purs b/Source/Plugins/Core/com.equella.core/js/src/Uploads/UploadList.purs index d764b822d0..bb2162919f 100644 --- a/Source/Plugins/Core/com.equella.core/js/src/Uploads/UploadList.purs +++ b/Source/Plugins/Core/com.equella.core/js/src/Uploads/UploadList.purs @@ -33,7 +33,7 @@ import Web.HTML.Window (confirm) type ControlStrings = { edit :: String, replace :: String, delete :: String, deleteConfirm :: String, cancel :: String, add :: String, drop :: String, - none :: String, preview :: String, toomany :: String} + none :: String, preview :: String, toomany :: String, toomany_1 :: String} type DialogStrings = { scrapbook :: String, @@ -79,8 +79,15 @@ inlineUploadClass = component "InlineUpload" $ \this -> do newError = ctrlError entries if oldError /= newError then runEffectFn2 updateCtrlErrorText ctrlId newError else pure unit - ctrlError entries = if compareMax (>) entries - then maybe "" (\ma -> simpleFormat strings.toomany [show ma, show (length entries - ma)]) maxAttach + ctrlError entries = if compareMax (>) entries + then + case maxAttach of + Just maxAttachAmount | maxAttachAmount > 1 -> + maybe "" (\ma -> simpleFormat strings.toomany [show ma, show (length entries - ma)]) maxAttach + | maxAttachAmount == 1 -> + maybe "" (\ma -> simpleFormat strings.toomany_1 [show (length entries - ma)]) maxAttach + | otherwise -> "" --in theory maxAttach could be 0 + _ -> "" --when maxAttach is Nothing else "" compareMax f entries = maybe false (f $ length entries) maxAttach diff --git a/Source/Plugins/Core/com.equella.core/resources/lang/i18n-resource-centre.properties b/Source/Plugins/Core/com.equella.core/resources/lang/i18n-resource-centre.properties index d34e55bf65..090ede29cb 100644 --- a/Source/Plugins/Core/com.equella.core/resources/lang/i18n-resource-centre.properties +++ b/Source/Plugins/Core/com.equella.core/resources/lang/i18n-resource-centre.properties @@ -203,7 +203,8 @@ /wizard.controls.file.select=Select zip file /wizard.controls.file.selecttitle=Please select files /wizard.controls.file.title=Filename of Attachment -/wizard.controls.file.toomanyattachments=This attachment control is restricted to a max. of {0} attachments. Please remove {1} attachment(s). +/wizard.controls.file.toomanyattachments=This control is restricted to a maximum of {0} attachments. Please remove {1} attachment(s). +/wizard.controls.file.toomanyattachments.1=This control is restricted to a maximum of 1 attachment. Please remove {0} attachment(s). /wizard.controls.file.unabletoupload=Unable to upload file /wizard.controls.file.url=Use the following URL in your favourite WebDAV client\:
{0} /wizard.controls.file.zipcurrent=Zip files uploaded @@ -316,7 +317,7 @@ activate.citatenone=None activate.citation=Citation\: activate.course=Course\: activate.error.accessdenied=You do not have the required privilege to view this page. -activate.error.emptycourse=You must select a course. +activate.error.emptycourse=You must select a course. activate.error.invalidfrom=Invalid 'from' date format activate.error.invalidrange='From' date must come before 'until'. activate.error.invalidtoday='Until' date must be after today. @@ -480,7 +481,7 @@ bannedext.remove=Remove bannedext.remove.confirm=Are you sure you want to remove this banned extension? bb.editor.error.testwebservice.mandatory=You must successfully test the openEQUELLA Blackboard web service bb.editor.help.installmodule=You must install the latest openEQUELLA Blackboard Building Block within Blackboard before you can use this feature. -bb.editor.label.testwebservice=Blackboard system user +bb.editor.label.testwebservice=Blackboard system user bb.editor.label.testwebservice.fail=Failed to connect to the openEQUELLA Blackboard web service bb.editor.label.testwebservice.ok=openEQUELLA Blackboard web service contacted successfully breadcrumb=Settings @@ -535,7 +536,7 @@ bulkop.executescript=Execute script... bulkop.executescript.title=Executing script bulkop.move=Move... bulkop.movetask=Reset to workflow task... -bulkop.movetask.error.nostep=Target workflow step does not exist in this workflow. +bulkop.movetask.error.nostep=Target workflow step does not exist in this workflow. bulkop.movetask.optional=Enter an optional message\: bulkop.movetask.select=Select the workflow task to which the selected items are to be reset to. bulkop.movetask.title=Resetting to another workflow task @@ -685,7 +686,7 @@ checkout.table.name=Selection checkout.table.remove=Are you sure you wish to remove this selection? checkout.table.version=Version checkout.title=My selections -checkout.version.latest=Latest available +checkout.version.latest=Latest available checkout.version.specific=Fixed to v{0} checktask=Checking for migrations citation.summary.title=Citation @@ -713,7 +714,7 @@ client.editor.error.user.mandatory=You must select a user to use this flow client.editor.flow.acg.desc=To use this flow your client application needs to be a web application with a URL that can be redirected to. client.editor.flow.acg.name=Authorisation code grant client.editor.flow.ccg.desc=Use this flow if your client application is not web based in any way, e.g. it is a Python script. When using this flow your client must act as a pre-configured user. This flow should also be used for LTI authentication. -client.editor.flow.ccg.name=Client credentials grant +client.editor.flow.ccg.name=Client credentials grant client.editor.flow.choosetype=Select a flow client.editor.flow.help=The OAuth flow to use for this client client.editor.flow.ig.desc=Use this flow if your client is Javascript in a web browser that needs to make secure APIcalls, or your client application supports an embeddable browser (such as a C\# Winforms application) where you can extract the location URL. @@ -896,7 +897,7 @@ connector.selectionsbox.count.1=You have selected 1 external resource connector.selectionsbox.pleaseselect=You must first select the external resources you want to perform the action on. connector.selectionsbox.selectall=Select all external resources connector.selectionsbox.unselect=Unselect all external resources -connector.selectionsbox.viewselected=View selected external resources +connector.selectionsbox.viewselected=View selected external resources connector.setting.description=Configure external system connectors to enable content to be published directly to an LMS connector.setting.title=External system connectors connector.test.error.emptyresponse=Empty response from Moodle, make sure web service and REST protocol are enabled @@ -933,7 +934,7 @@ contribute.pleaseselect=Please select a resource type to contribute contribute.title=Contribute contributebutton=Contribute contributenew=Contribute a new item -contributetitle=Upload new content +contributetitle=Upload new content conversion.htmlviewername=HTML Conversion conversion.imageconvertername=View as JPEG Image convert.layout.description=Set default wizard layouts @@ -954,7 +955,7 @@ coursedefaults.settings.save.receipt=Course settings saved successfully coursedefaults.settings.title=Course defaults coursedefaults.startdate=Start date coursedefaults.title=Copyright -courselist.button.cancel=Cancel +courselist.button.cancel=Cancel courselist.button.save=Save courselist.link.review=Review all selections courselist.warning.notargets=There are no areas available to add content to. @@ -983,7 +984,7 @@ databases.cell.name=Name databases.cell.status=Status databases.delete=Remove this database databases.delete.confirm=Are you sure you want to remove this database? Any institutions residing on this database will become unavailable. -databases.delete.receipt=Database successfully removed +databases.delete.receipt=Database successfully removed databases.dialog.add=Add databases.dialog.addonline=Add and bring online databases.dialog.addonline.confirm=If you are adding an existing openEQUELLA database please confirm that you have backed it up. @@ -995,7 +996,7 @@ databases.dialog.main.description.sqlserver=Microsoft SQL Server databases.dialog.main.heading=Main connection databases.dialog.otherdetails=Other details databases.dialog.password=Password -databases.dialog.reporting.description=These setting are used when executing reports. It is highly recommended that credentials with lower privileges are used to avoid report designers from performing queries against data you wish to remain secret or perform data manipulation. Any fields that are left blank will use the respective value from the main connection above. +databases.dialog.reporting.description=These setting are used when executing reports. It is highly recommended that credentials with lower privileges are used to avoid report designers from performing queries against data you wish to remain secret or perform data manipulation. Any fields that are left blank will use the respective value from the main connection above. databases.dialog.reporting.heading=Reporting connection databases.dialog.save=Save databases.dialog.title.add=Add database @@ -1009,7 +1010,7 @@ databases.dialog.username.oracle=openEQUELLA will use the default schema for thi databases.dialog.username.postgresql=openEQUELLA will use the default schema for this user, which will be a schema with the same name as the username, or the public schema if that doesn't exist. This can be changed permanently for the user using ALTER USER username SET search_path TO myschema databases.dialog.username.sqlserver=openEQUELLA will use the default schema for this login. This can be changed by modifying the default schema for the user associated with this login. databases.dialog.usesystem=Use system schema -databases.dialog.usesystem.help=Check this if you want this database connection to use the system schema as specified in the hibernate.properties file +databases.dialog.usesystem.help=Check this if you want this database connection to use the system schema as specified in the hibernate.properties file databases.dialog.validate.password.mandatory=You must enter a password for the main connection databases.dialog.validate.url.duplicate=You already have a database connection with the same URL, username and password databases.dialog.validate.url.mandatory=You must enter a JDBC URL for the main connection @@ -1036,7 +1037,7 @@ databases.progress.runningmigration=Running migration {0} of {1} - {2} databases.progress.runningstep=Running step {0} of {1} databases.progress.title=Migration progress databases.progress.warnings=Warnings -databases.refresh=Reload database state +databases.refresh=Reload database state databases.review=Review log databases.select.title=Select a database databases.showduplicate=More information @@ -1056,7 +1057,7 @@ databases.takeoffline.confirm=Are you sure you want to take this database off-li databases.takeoffline.receipt=Database successfully taken off-line databases.title=Databases datefavourited=Date favourited -dateformat.description=Select a display date format +dateformat.description=Select a display date format dateformat.exact=Exact date - e.g June 19, 2014 3\:13 PM dateformat.relative=Relative date - e.g about an hour ago dateformat.title=Display date format @@ -1085,11 +1086,11 @@ deletereceipt=Successfully deleted from scrapbook description.label=Description description.untitled=Untitled detachbutton=Detach -details.echocenter.link=EchoCenter +details.echocenter.link=EchoCenter details.echoplayer.link=EchoPlayer details.echopodcast.link=Podcast details.echovodcast.link=Vodcast -details.error.noserver=There is no Echo360 EchoSystem server configured for this attachment. Please contact your system administrator +details.error.noserver=There is no Echo360 EchoSystem server configured for this attachment. Please contact your system administrator details.mimetype=IMS Package details.name=Name\: details.scormversion=SCORM Version\: @@ -1280,7 +1281,7 @@ editactivation.changecourse=Change course editactivation.course=Course\: editactivation.error.fromafterbefore=Start date must be be before end date editactivation.error.pendingpast=This activation is pending, the start date must be after today -editactivation.error.untilpast=End date must be after today +editactivation.error.untilpast=End date must be after today editactivation.name=User\: editactivation.save=Save editactivation.title=Edit activation @@ -1323,7 +1324,7 @@ editor.error.custom.norole=You must enter an LTI/LIS role to map to an openEQUEL editor.error.duplicate.key=An LTI consumer with this key already exists editor.error.duplicate.secret=An LTI consumer with this secret already exists editor.error.nokey=You must supply an LTI consumer key -editor.error.nosecret=You must supply an LTI consumer secret +editor.error.nosecret=You must supply an LTI consumer secret editor.error.register.mandatory=You must register the openEQUELLA Blackboard proxy tool. editor.error.testwebservice.enteruser=Please enter a Blackboard user's username for running the Blackboard Synchronisation task and to test the openEQUELLA Blackboard web service. editor.error.testwebservice.mandatory=You must successfully test the openEQUELLA Moodle web service @@ -1333,7 +1334,7 @@ editor.error.url.musttest=You must successfully test the {0} URL before you can editor.error.url.unreachable=Could not contact the given {0} URL editor.error.webservicetoken.mandatory=You must enter a web service token editor.expressionselector.button.change=Change -editor.expressionselector.title=Select users +editor.expressionselector.title=Select users editor.freemarker.label.client.description=Client-side JavaScript to run when the portlet is loaded. editor.freemarker.label.client.title=Client-side script editor.freemarker.label.format=Format script @@ -1357,10 +1358,10 @@ editor.freemarker.tab.server.name=Server-side script editor.help.adminsignin=Certain functions require openEQUELLA act under an account with elevated privileges. This account must have "Manage External Learning Tool Links" and "Create Quicklinks from available External Learning Tools links" privileges for all course offerings in Brightspace. editor.help.appid=Application ID editor.help.appkey=Application Key -editor.help.appsetup=You must register an application in Brightspace if you have not already done so. Login to Brightspace with an adminstrative account and visit this link {0}/d2l/lp/extensibility/home and click Register an App. When registering the app, the Trusted URL must be {1} . Once the app is registered, copy the Application ID and Application Key values into the form below. +editor.help.appsetup=You must register an application in Brightspace if you have not already done so. Login to Brightspace with an adminstrative account and visit this link {0}/d2l/lp/extensibility/home and click Register an App. When registering the app, the Trusted URL must be {1} . Once the app is registered, copy the Application ID and Application Key values into the form below. editor.help.baseurl=The base URL is used to match the tool launch URL entered during contribution to the correct tool provider configuration editor.help.consumerkey=The consumer key as supplied by the tool provider -editor.help.customparams=Custom parameters to send to the tool provider. Consult the tool's documentation for possible parameters. Multiple parameters should be entered as a comma separated list e.g. review_chaper\=1.2.57,book_isbn\=0-962303208 or on separate lines for each name\=value pair +editor.help.customparams=Custom parameters to send to the tool provider. Consult the tool's documentation for possible parameters. Multiple parameters should be entered as a comma separated list e.g. review_chaper\=1.2.57,book_isbn\=0-962303208 or on separate lines for each name\=value pair editor.help.email=If enabled the email address of the user launching the tool will be shared with the tool provider editor.help.enablewebservices=You must ensure that web services and the REST protocol are enabled in Moodle and you need to create a web service token. editor.help.iconurl=If set, will override the icon which applies to the openEQUELLA attachment-lti MIME type @@ -1368,14 +1369,14 @@ editor.help.installmodule=You must install the latest openEQUELLA Moodle Module editor.help.link.createtoken=Follow this link to create a web service token editor.help.link.enablerest=Follow this link to enable the REST protocol editor.help.link.enablewebservices=Follow this link to enable web services -editor.help.lti=You are now ready to push content from openEQUELLA into Brightspace. +editor.help.lti=You are now ready to push content from openEQUELLA into Brightspace. editor.help.manualtoken=Access tokens can be manually generated in Canvas on the desired user's profile page. editor.help.mustbeadmin=To use the links below you must login as a Moodle administrator if prompted. editor.help.name=If enabled the full name of the user launching the tool will be shared with the tool provider -editor.help.nextsteps=You are now ready to push content from openEQUELLA into Brightspace. +editor.help.nextsteps=You are now ready to push content from openEQUELLA into Brightspace. editor.help.proxypass=A password is only required if your Blackboard Proxy Tool Global Properties specify a Proxy Tool Registration Password editor.help.proxysecret=You will only need to manually enter a proxy tool shared password if the proxy tool has been previously registered for this server and the shared password has been changed in Blackboard. If you believe this has happened, edit the existing proxy tool in Blackboard and copy the value of the shared password field into this field before using the test web service function below. -editor.help.register=You need only register one proxy tool per Blackboard server and you must make the proxy tool available in Blackboard once successfully registered. Follow this link to make the proxy tool available +editor.help.register=You need only register one proxy tool per Blackboard server and you must make the proxy tool available in Blackboard once successfully registered. Follow this link to make the proxy tool available editor.help.testservice=Use this button to verify that the openEQUELLA Moodle web service is setup correctly. editor.help.testurl=You must test that this {0} URL is a valid and reachable URL before you can proceed. editor.help.testwebservice=Use this button to verify that the openEQUELLA Blackboard web service is setup correctly. @@ -1473,7 +1474,7 @@ editor.rss.label.results=Default number of results to show (maximum 30) editor.rss.label.titledesc=Show the title and description editor.rss.label.titleonly=Show only the title editor.rss.label.url=URL -editor.save.receipt=EchoSystem server saved successfully +editor.save.receipt=EchoSystem server saved successfully editor.script=Script editor.scripttype=Script type editor.scripttypes.display=Display script (FreeMarker) @@ -1494,10 +1495,10 @@ editor.unknown.groups.label=Groups editor.unknown.help=Choose how to handle logon attempts with a username that doesn't exist editor.unknown.ignore=Treat user as a guest editor.unknown.label=Unknown user handling -editor.username.help=Automatically modify usernames to disambiguate from other LTI consumers +editor.username.help=Automatically modify usernames to disambiguate from other LTI consumers editor.validation.appid=You must enter an Application ID editor.validation.appkey=You must enter an Application Key -editor.validation.applicationurl.invalid=The Application URL is invalid +editor.validation.applicationurl.invalid=The Application URL is invalid editor.validation.applicationurl.mandatory=You must enter an Application URL editor.validation.consumerkey.mandatory=You must enter a Consumer key editor.validation.consumersecret.mandatory=You must enter a Consumer secret @@ -1514,7 +1515,7 @@ editpage=Edit Page editpage.label=Edit page editpagesbutton=Open HTML editor editpagestitle=Edit pages -edittitle=Editing ''{0}'' +edittitle=Editing ''{0}'' edituser.breadcrumb.title=Return to Dashboard email.accepttask=Previous task email.autoaccept=accepted @@ -1626,7 +1627,7 @@ error.invalidemail=Invalid email address error.invalidpassword=An invalid proxy tool shared password was sent to the openEQUELLA Blackboard web service error.invalidsession=Invalid Blackboard session error.label.reason=Reason\: -error.line=line {0}\: {1} (column {2}) +error.line=line {0}\: {1} (column {2}) error.login=Failed to login to Blackboard error.lorax.download=Problem downloading package {0} error.message.help=You use the browser's back button rather than the wizard navigation controls or your browser's session has been timed out @@ -1635,7 +1636,7 @@ error.mimetype.exists=This MIME type already exists. Please change the type or error.musthavemessage=You must enter a message when uploading a file error.name=The display name cannot be blank error.noaccess=Insufficient privileges -error.noadmin=No administrator user has been configured for this Brightspace connector. Please edit this connector and configure an administrator user. +error.noadmin=No administrator user has been configured for this Brightspace connector. Please edit this connector and configure an administrator user. error.nocookies=The session id supplied does not match the current user session id {0}. This most likely because you do not have cookies over SOAP enabled. Cookies MUST be used to enable sessions. error.noinstitutionid=No iTunes U institution ID has been configured for this control. Please contact your administrator. error.noitemforresource=Cannot find item for selected resource {0}/{1} @@ -1644,19 +1645,19 @@ error.nostaging=There is no staging object available at this point. Please make error.notabs=No tabs on ItemNavigationNode error.notenabled=The proxy tool has not been made available yet error.notmoderating=You can no longer moderate that task. -error.notool=There is no matching openEQUELLA External App configured for this Canvas course. Contact the administrator for this Canvas course. +error.notool=There is no matching openEQUELLA External App configured for this Canvas course. Contact the administrator for this Canvas course. error.noworkflow=No workflow associated with this item -error.oldid=Please ensure that the latest Building Block and Web Service are installed in Blackboardand re-run the Blackboard Connector Synchronisation task +error.oldid=Please ensure that the latest Building Block and Web Service are installed in Blackboardand re-run the Blackboard Connector Synchronisation task error.personal=This operation cannot be performed on personal items error.preamble=A problem occurred running user script ''{0}''. error.prelim=An error occurred in Canvas\: error.protectedresource=Protected resource -error.receipt=This item has fields that need to be completed before it can be submitted\: +error.receipt=This item has fields that need to be completed before it can be submitted\: error.receipt.cause={0} - {1} error.requiresselectionsession=Selection session required to display this page -error.script=Script error in +error.script=Script error in error.search=Error getting results from MERLOT\: {0} -error.selectionsession.accessdenied=User does not have required privilege INTEGRATION_SELECTION_SESSION +error.selectionsession.accessdenied=User does not have required privilege INTEGRATION_SELECTION_SESSION error.title=An error occurred in the wizard error.title.help=Wizard Errors can occur if\: error.type.other=Error during wizard @@ -1724,8 +1725,8 @@ export.label.selectlocations=Select the locations to add to export.label.selectpackage=Add content package export.label.selectresources=Select the resources to add export.label.selectsummary=Add resource summary -export.link.itemaction=Add to external system -export.nocourses=There are no courses that you can add resources to +export.link.itemaction=Add to external system +export.nocourses=There are no courses that you can add resources to export.original=Download original IMS package export.record=METS record export.selectconnector=