From 2cacbdf04709d987a717029832d8da264f2e3a10 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Tue, 29 Oct 2019 08:49:55 +0100
Subject: [PATCH] notification about new releases of minerva added in admin
 panel

---
 CHANGELOG                               |  2 +
 frontend-js/package-lock.json           | 11 ++++
 frontend-js/package.json                |  2 +
 frontend-js/src/main/js/Admin.js        | 69 ++++++++++++++++++++++++-
 frontend-js/src/test/js/Admin-test.js   | 12 +++++
 frontend-js/src/test/js/mocha-config.js |  3 ++
 6 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index ddbe19ff37..de6c94e395 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,8 @@ minerva (15.0.0~alpha.0) stable; urgency=medium
   * Small improvement: CellDesigner text area object can have "BorderColor" 
     property defined (#806)
   * Small improvement: list of submaps is sorted alphabetically (#962) 
+  * Small improvement: notification about new releases of minerva added in
+    admin panel (#961)
   * Bug fix: position of structural state is preserved on upload CellDesigner 
     file (#671)
   * Bug fix: problematic notes doesn't crash CellDesigner upload (#968)
diff --git a/frontend-js/package-lock.json b/frontend-js/package-lock.json
index 4da1376269..2bdf791df5 100644
--- a/frontend-js/package-lock.json
+++ b/frontend-js/package-lock.json
@@ -3624,6 +3624,12 @@
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
       "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
     },
+    "node-fetch": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
+      "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==",
+      "dev": true
+    },
     "nomnom": {
       "version": "1.8.1",
       "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz",
@@ -4589,6 +4595,11 @@
       "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
       "dev": true
     },
+    "semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+    },
     "send": {
       "version": "0.16.1",
       "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz",
diff --git a/frontend-js/package.json b/frontend-js/package.json
index 7370e19452..89764b4635 100644
--- a/frontend-js/package.json
+++ b/frontend-js/package.json
@@ -32,6 +32,7 @@
     "mocha": "^3.5.3",
     "mock-local-storage": "^1.1.8",
     "molart": "1.4.0",
+    "node-fetch": "^2.6.0",
     "stream-to-blob": "^1.0.1",
     "uglifyjs": "^2.4.10"
   },
@@ -57,6 +58,7 @@
     "pileup": "^0.6.12",
     "popper.js": "^1.15.0",
     "request": "^2.88.0",
+    "semver": "^6.3.0",
     "spectrum-colorpicker": "^1.8.0",
     "text-encoding": "^0.7.0",
     "xss": "^1.0.6"
diff --git a/frontend-js/src/main/js/Admin.js b/frontend-js/src/main/js/Admin.js
index 1adf7bdc59..e7f4dcde07 100644
--- a/frontend-js/src/main/js/Admin.js
+++ b/frontend-js/src/main/js/Admin.js
@@ -16,7 +16,11 @@ var UsersAdminPanel = require('./gui/admin/UsersAdminPanel');
 
 // noinspection JSUnusedLocalSymbols
 var logger = require('./logger');
+var request = require('request');
+var semver = require('semver');
 var GuiUtils = require('./gui/leftPanel/GuiUtils');
+var NetworkError = require('./NetworkError');
+var GuiConnector = require('./GuiConnector');
 
 /**
  * Default constructor.
@@ -110,12 +114,15 @@ Admin.prototype.getElement = function () {
  * @returns {Promise}
  */
 Admin.prototype.init = function () {
+  var self = this;
   var promises = [];
-  for (var i = 0; i < this._panels.length; i++) {
-    promises.push(this._panels[i].init());
+  for (var i = 0; i < self._panels.length; i++) {
+    promises.push(self._panels[i].init());
   }
   return Promise.all(promises).then(function () {
     $(window).trigger('resize');
+  }).then(function () {
+    return self.checkAvailableVersion();
   });
 };
 
@@ -148,6 +155,64 @@ Admin.prototype.destroy = function () {
   return Promise.all(promises);
 };
 
+/**
+ *
+ * @return {Promise<T>}
+ */
+Admin.prototype.checkAvailableVersion = function () {
+  var self = this;
+
+  var localVersion = semver.coerce(self.getConfiguration().getVersion());
+  return self.getLatestPublishedVersion().then(function (publishedVersion) {
+    if (semver.gt(publishedVersion, localVersion) > 0) {
+      GuiConnector.warn("New minerva version (" + publishedVersion + ") was released. Please upgrade your minerva instance or contact system administrator to do so.");
+    }
+  });
+};
+
+/**
+ *
+ * @return {Promise}
+ */
+Admin.prototype.getLatestPublishedVersion = function () {
+  return new Promise(function (resolve, reject) {
+    var url = "https://minerva-net.lcsb.uni.lu/proxy/?url=https://webdav-r3lab.uni.lu/public/minerva/";
+    request(url, function (error, response, body) {
+      if (error) {
+        reject(new NetworkError(error.message, {
+          content: body,
+          url: url
+        }));
+      } else if (response.statusCode !== 200) {
+        reject(new NetworkError(url + " rejected with status code: " + response.statusCode, {
+          content: body,
+          url: url,
+          statusCode: response.statusCode
+        }));
+      } else {
+        var content;
+        // for some reason sometimes result is an object not a string
+        if (typeof body === 'string' || body instanceof String) {
+          content = body;
+        } else {
+          content = JSON.stringify(body);
+        }
+        var re = /href="[\w.]+/g;
+        var result = content.match(re);
+        for (var i = result.length - 1; i >= 0; i--) {
+          result[i] = result[i].replace("href=\"", "");
+          if (!semver.valid(result[i])) {
+            logger.warn("Invalid version: " + result[i]);
+            result.splice(i, 1);
+          }
+        }
+        result.sort(semver.compare);
+        resolve(result[result.length - 1]);
+      }
+    });
+  });
+};
+
 /**
  *
  * @param {ServerConnector} serverConnector
diff --git a/frontend-js/src/test/js/Admin-test.js b/frontend-js/src/test/js/Admin-test.js
index 36e91d7fac..b355633348 100644
--- a/frontend-js/src/test/js/Admin-test.js
+++ b/frontend-js/src/test/js/Admin-test.js
@@ -6,6 +6,7 @@ var $ = require('jquery');
 var Admin = require('../../main/js/Admin');
 var ServerConnector = require('./ServerConnector-mock');
 var logger = require('./logger');
+var semver = require('semver');
 
 var chai = require('chai');
 var assert = chai.assert;
@@ -37,5 +38,16 @@ describe('Admin', function () {
       })
     });
   });
+  describe('getLatestPublishedVersion', function () {
+    it('default', function () {
+      helper.loginAsAdmin();
+      var admin = new Admin(helper.createCustomMapOptions(null));
+      return admin.getLatestPublishedVersion().then(function (version) {
+        var oldVersion  = "1.0.0";
+        assert.ok(semver.gt(version, oldVersion));
+        admin.destroy();
+      })
+    });
+  });
 
 });
diff --git a/frontend-js/src/test/js/mocha-config.js b/frontend-js/src/test/js/mocha-config.js
index be50e7e969..dc0c56494c 100644
--- a/frontend-js/src/test/js/mocha-config.js
+++ b/frontend-js/src/test/js/mocha-config.js
@@ -186,6 +186,9 @@ function mockEnvironment() {
   global.ServerConnector = require('./ServerConnector-mock');
 
   Promise.longStackTraces();
+
+  global.fetch = require("node-fetch");
+
 }
 
 
-- 
GitLab