From 4042b4da0fde3a1f0ac28c77c7771d11f9e8ed22 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Tue, 3 Jul 2018 15:34:23 +0200
Subject: [PATCH] adding of reference genomes implemented

---
 .../genome/ReferenceGenomeConnector.java      |   4 +-
 .../genome/UcscReferenceGenomeConnector.java  |   1 +
 frontend-js/src/main/js/ServerConnector.js    |  61 +++++++-
 .../src/main/js/gui/admin/EditGenomeDialog.js | 137 ++++++++++++++----
 .../js/gui/admin/EditGenomeDialog-test.js     | 105 +++++++++-----
 ...pe=UCSC&version=hg38&token=ADMIN_TOKEN_ID& |   1 +
 .../token=ADMIN_TOKEN_ID&                     |   1 +
 .../token=MOCK_TOKEN_ID&                      |   1 +
 .../genomics/ReferenceGenomeController.java   |  28 +++-
 .../api/genomics/ReferenceGenomeRestImpl.java |  52 ++++++-
 .../ReferenceGenomeControllerTest.java        |  12 ++
 11 files changed, 337 insertions(+), 66 deletions(-)
 create mode 100644 frontend-js/testFiles/apiCalls/genomics/POST_organismId=9606&sourceUrl=ftp%3A%2F%2Fhgdownload.cse.ucsc.edu%2FgoldenPath%2Fhg18%2FbigZips%2Fhg18.2bit&type=UCSC&version=hg38&token=ADMIN_TOKEN_ID&
 create mode 100644 frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=ADMIN_TOKEN_ID&
 create mode 100644 frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=MOCK_TOKEN_ID&

diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/ReferenceGenomeConnector.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/ReferenceGenomeConnector.java
index fbfb32622f..33d279d315 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/ReferenceGenomeConnector.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/ReferenceGenomeConnector.java
@@ -127,7 +127,7 @@ public interface ReferenceGenomeConnector {
 	 * @param version
 	 *          version of the reference genome
 	 * @throws IOException
-	 *           thrown when there is a problem with removeing file
+	 *           thrown when there is a problem with removing file
 	 */
 	void removeGenomeVersion(MiriamData organism, String version) throws IOException;
 
@@ -135,7 +135,7 @@ public interface ReferenceGenomeConnector {
 	 * Returns url to the file that describes reference genome.
 	 * 
 	 * @param organism
-	 *          organism of redference genome
+	 *          organism of reference genome
 	 * @param version
 	 *          version of the reference genome
 	 * @return url to the file that describes reference genome
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnector.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnector.java
index 9af8f7fdc3..d95d98b5c9 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnector.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnector.java
@@ -387,6 +387,7 @@ public class UcscReferenceGenomeConnector extends AbstractReferenceGenomeConnect
         String remotePath = getGenomePath(organism, version);
         FTPFile[] files = ftp.listFiles(remotePath);
         for (FTPFile ftpFile : files) {
+          logger.debug(ftpFile.getName());
           if (ftpFile.getName().endsWith(".2bit")) {
             if (filename != null) {
               logger.warn("More than one 2bit file found in a folder: " + remotePath + ". Using first: " + filename);
diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index be25fb33fd..e11954790e 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -448,6 +448,24 @@ ServerConnector.getReferenceGenomeUrl = function (queryParams, filterParams) {
   }
 };
 
+/**
+ *
+ * @param {Object} queryParams
+ * @param {string} queryParams.version
+ * @param {Annotation} queryParams.organism
+ * @param {string} queryParams.type
+ * @param {Object} filterParams
+ *
+ * @returns {string}
+ */
+ServerConnector.getAvailableGenomeUrlsUrl = function (queryParams, filterParams) {
+  return this.getApiUrl({
+    type: "genomics/taxonomies/" + queryParams.organism.getResource() + "/genomeTypes/" + queryParams.type + "/versions/" + queryParams.version
+    + ":getAvailableRemoteUrls",
+    params: filterParams
+  });
+};
+
 /**
  *
  * @param {Object} queryParams
@@ -792,8 +810,8 @@ ServerConnector.getUsersUrl = function (queryParams, filterParams) {
 
 /**
  *
- * @param {Object} queryParams
- * @param {Object} filterParams
+ * @param {Object} [queryParams]
+ * @param {Object} [filterParams]
  *
  * @returns {string}
  */
@@ -2077,6 +2095,45 @@ ServerConnector.getReferenceGenome = function (params) {
   }
 };
 
+/**
+ *
+ * @param {Object} params
+ * @param {string} params.version
+ * @param {Annotation} params.organism
+ * @param {string} params.type
+ *
+ * @returns {Promise<string[]>}
+ */
+ServerConnector.getAvailableGenomeUrls = function (params) {
+  var self = this;
+  var filterParams = {};
+  return self.sendGetRequest(self.getAvailableGenomeUrlsUrl(params, filterParams)).then(function (content) {
+    var result = [];
+    var raw = JSON.parse(content);
+    for (var i = 0; i < raw.length; i++) {
+      result.push(raw[i].url);
+    }
+    return result;
+  });
+};
+
+/**
+ *
+ * @param {ReferenceGenome} genome
+ * @returns {Promise<ReferenceGenome>}
+ */
+ServerConnector.addReferenceGenome = function (genome) {
+  var self = this;
+  var data = {
+    organismId: genome.getOrganism().getResource(),
+    type: genome.getType(),
+    version: genome.getVersion(),
+    sourceUrl: genome.getSourceUrl()
+  };
+  return self.sendPostRequest(self.getReferenceGenomesUrl(), data);
+};
+
+
 /**
  *
  * @param {Object} params
diff --git a/frontend-js/src/main/js/gui/admin/EditGenomeDialog.js b/frontend-js/src/main/js/gui/admin/EditGenomeDialog.js
index 3f0cf1646f..1987cc9ece 100644
--- a/frontend-js/src/main/js/gui/admin/EditGenomeDialog.js
+++ b/frontend-js/src/main/js/gui/admin/EditGenomeDialog.js
@@ -3,6 +3,7 @@
 var Promise = require("bluebird");
 
 var AbstractGuiElement = require('../AbstractGuiElement');
+var Annotation = require('../../map/data/Annotation');
 var GuiConnector = require('../../GuiConnector');
 
 var Functions = require('../../Functions');
@@ -175,6 +176,19 @@ EditGenomeDialog.prototype.createGeneralTabContent = function () {
   });
   result.appendChild(table);
 
+  $(table).on("change", "[name='genomeOrganismSelect']", function () {
+    return self._fillTypeSelect(self.getReferenceGenome(), self.getSelectedOrganism());
+  });
+
+  $(table).on("change", "[name='genomeTypeSelect']", function () {
+    return self._fillVersionSelect(self.getReferenceGenome(), self.getSelectedOrganism(), self.getSelectedType());
+  });
+
+  $(table).on("change", "[name='genomeVersionSelect']", function () {
+    return self._fillUrl(self.getReferenceGenome(), self.getSelectedOrganism(), self.getSelectedType(), self.getSelectedVersion());
+  });
+
+
   var menuRow = Functions.createElement({
     type: "div",
     className: "minerva-menu-row",
@@ -217,7 +231,12 @@ EditGenomeDialog.prototype.onSaveClicked = function () {
   if (!self.isNew()) {
     return self.callListeners("onSave");
   } else {
-    return self.getServerConnector().updateReferenceGenome(self.getReferenceGenome()).then(function () {
+    var genome = self.getReferenceGenome();
+    genome.setSourceUrl(self.getSourceUrl());
+    genome.setOrganism(self.getSelectedOrganism());
+    genome.setType(self.getSelectedType());
+    genome.setVersion(self.getSelectedVersion());
+    return self.getServerConnector().addReferenceGenome(genome).then(function () {
       return self.callListeners("onSave");
     });
   }
@@ -232,6 +251,7 @@ EditGenomeDialog.prototype._fillOrganismSelect = function (genome) {
   var self = this;
   return self.getServerConnector().getReferenceGenomeOrganisms().then(function (organisms) {
     var genomeOrganismSelect = $("[name=genomeOrganismSelect]", self.getElement());
+    genomeOrganismSelect.empty();
     var selectedOrganism;
     if (self.isNew()) {
       selectedOrganism = organisms[0];
@@ -255,7 +275,7 @@ EditGenomeDialog.prototype._fillOrganismSelect = function (genome) {
       }));
     });
     genomeOrganismSelect.val(selectedOrganism.getResource());
-    return selectedOrganism;
+    return self._fillTypeSelect(genome, selectedOrganism);
   });
 };
 
@@ -271,6 +291,8 @@ EditGenomeDialog.prototype._fillTypeSelect = function (genome, selectedOrganism)
   return self.getServerConnector().getReferenceGenomeTypes({organism: selectedOrganism}).then(function (types) {
 
     var genomeTypeSelect = $("[name=genomeTypeSelect]", self.getElement());
+    genomeTypeSelect.empty();
+
     var selectedType;
     if (self.isNew()) {
       selectedType = types[0].type;
@@ -289,7 +311,7 @@ EditGenomeDialog.prototype._fillTypeSelect = function (genome, selectedOrganism)
       }));
     });
     genomeTypeSelect.val(selectedType);
-    return selectedType;
+    return self._fillVersionSelect(genome, selectedOrganism, selectedType);
   })
 };
 
@@ -307,8 +329,9 @@ EditGenomeDialog.prototype._fillVersionSelect = function (genome, selectedOrgani
     organism: selectedOrganism,
     type: selectedType
   }).then(function (versions) {
-
     var genomeVersionSelect = $("[name=genomeVersionSelect]", self.getElement());
+    genomeVersionSelect.empty();
+
     var selectedVersion;
     if (self.isNew()) {
       selectedVersion = versions[0].version;
@@ -327,9 +350,52 @@ EditGenomeDialog.prototype._fillVersionSelect = function (genome, selectedOrgani
       }));
     });
     genomeVersionSelect.val(selectedVersion);
+    return self._fillUrl(genome, selectedOrganism, selectedType, selectedVersion);
   })
 };
 
+/**
+ *
+ * @param {ReferenceGenome} genome
+ * @param {Annotation} organism
+ * @param {string} type
+ * @param {string} version
+ * @returns {Promise}
+ * @private
+ */
+EditGenomeDialog.prototype._fillUrl = function (genome, organism, type, version) {
+  var self = this;
+  var genomeSourceUrlInput = $("[name=genomeSourceUrl]", self.getElement());
+  var genomeLocalUrlInput = $("[name=genomeLocalUrl]", self.getElement());
+  var genomeProgressInput = $("[name=genomeProgress]", self.getElement());
+  genomeLocalUrlInput.prop("disabled", true);
+  genomeProgressInput.val(genome.getDownloadProgressStatus());
+  genomeProgressInput.prop("disabled", true);
+  if (!self.isNew()) {
+    genomeSourceUrlInput.val(genome.getSourceUrl());
+    genomeSourceUrlInput.prop("disabled", true);
+
+    genomeLocalUrlInput.val(genome.getLocalUrl());
+  } else {
+    genomeSourceUrlInput.prop("disabled", false);
+
+    genomeLocalUrlInput.val("");
+    return self.getServerConnector().getAvailableGenomeUrls({
+      organism: organism,
+      type: type,
+      version: version
+    }).then(function (urls) {
+      if (urls.length > 0) {
+        genomeSourceUrlInput.val(urls[0]);
+      } else {
+        genomeSourceUrlInput.val("");
+      }
+    })
+  }
+  return Promise.resolve();
+}
+;
+
 
 /**
  *
@@ -364,27 +430,7 @@ EditGenomeDialog.prototype.init = function () {
 
   dataTable.clear().rows.add(data).draw();
 
-  var selectedOrganism, selectedType;
-  return self._fillOrganismSelect(genome).then(function (organism) {
-    selectedOrganism = organism;
-    return self._fillTypeSelect(genome, selectedOrganism);
-  }).then(function (type) {
-    selectedType = type;
-    return self._fillVersionSelect(genome, selectedOrganism, selectedType);
-  }).then(function (version) {
-    var genomeSourceUrlInput = $("[name=genomeSourceUrl]", self.getElement());
-    genomeSourceUrlInput.val(genome.getSourceUrl());
-    genomeSourceUrlInput.prop("disabled", true);
-
-    var genomeLocalUrlInput = $("[name=genomeLocalUrl]", self.getElement());
-    genomeLocalUrlInput.val(genome.getLocalUrl());
-    genomeLocalUrlInput.prop("disabled", true);
-
-    var genomeProgressInput = $("[name=genomeProgress]", self.getElement());
-    genomeProgressInput.val(genome.getDownloadProgressStatus());
-    genomeProgressInput.prop("disabled", true);
-
-  });
+  return self._fillOrganismSelect(genome);
 };
 
 EditGenomeDialog.prototype.destroy = function () {
@@ -427,4 +473,45 @@ EditGenomeDialog.prototype.close = function () {
   $(self.getElement()).dialog("close");
 };
 
+/**
+ *
+ * @returns {Annotation}
+ */
+EditGenomeDialog.prototype.getSelectedOrganism = function () {
+  var self = this;
+  return new Annotation({
+    resource: ($("[name='genomeOrganismSelect']", self.getElement()).val()).toString(),
+    link: '',
+    id: 0,
+    type: ''
+  })
+};
+
+/**
+ *
+ * @returns {string}
+ */
+EditGenomeDialog.prototype.getSelectedType = function () {
+  var self = this;
+  return ($("[name='genomeTypeSelect']", self.getElement()).val()).toString();
+};
+
+/**
+ *
+ * @returns {string}
+ */
+EditGenomeDialog.prototype.getSelectedVersion = function () {
+  var self = this;
+  return ($("[name='genomeVersionSelect']", self.getElement()).val()).toString();
+};
+
+/**
+ *
+ * @returns {string}
+ */
+EditGenomeDialog.prototype.getSourceUrl = function () {
+  var self = this;
+  return ($("[name='genomeSourceUrl']", self.getElement()).val()).toString();
+};
+
 module.exports = EditGenomeDialog;
diff --git a/frontend-js/src/test/js/gui/admin/EditGenomeDialog-test.js b/frontend-js/src/test/js/gui/admin/EditGenomeDialog-test.js
index 5eb04f7f35..c0f889d02d 100644
--- a/frontend-js/src/test/js/gui/admin/EditGenomeDialog-test.js
+++ b/frontend-js/src/test/js/gui/admin/EditGenomeDialog-test.js
@@ -13,45 +13,70 @@ var chai = require('chai');
 var assert = chai.assert;
 var expect = chai.expect;
 
+/**
+ *
+ * @param {ReferenceGenome} genome
+ * @returns {EditGenomeDialog}
+ */
+function createDialog(genome) {
+  return new EditGenomeDialog({
+    element: testDiv,
+    referenceGenome: genome,
+    customMap: null,
+    serverConnector: ServerConnector
+  });
+}
+
 describe('EditGenomeDialog', function () {
 
   describe('init', function () {
     it('new genome', function () {
-      var dialog;
-      var project;
       var genome = new ReferenceGenome();
-      return ServerConnector.getProject().then(function (result) {
-        project = result;
-        dialog = new EditGenomeDialog({
-          element: testDiv,
-          project: project,
-          referenceGenome: genome,
-          customMap: null,
-          serverConnector: ServerConnector
-        });
-        return dialog.init();
-      }).then(function () {
-        dialog.destroy();
+      var dialog = createDialog(genome);
+      return dialog.init().then(function () {
+        return dialog.destroy();
       });
     });
   });
 
+  it('on organism change', function () {
+    var genome = new ReferenceGenome();
+    var dialog = createDialog(genome);
+    return dialog.init().then(function () {
+      var element = $("[name='genomeOrganismSelect']")[0];
+      return helper.triggerJqueryEvent(element, "change");
+    }).then(function () {
+      return dialog.destroy();
+    });
+  });
+
+  it('on type change', function () {
+    var genome = new ReferenceGenome();
+    var dialog = createDialog(genome);
+    return dialog.init().then(function () {
+      var element = $("[name='genomeTypeSelect']")[0];
+      return helper.triggerJqueryEvent(element, "change");
+    }).then(function () {
+      return dialog.destroy();
+    });
+  });
+
+  it('on version change', function () {
+    var genome = new ReferenceGenome();
+    var dialog = createDialog(genome);
+    return dialog.init().then(function () {
+      var element = $("[name='genomeVersionSelect']")[0];
+      return helper.triggerJqueryEvent(element, "change");
+    }).then(function () {
+      return dialog.destroy();
+    });
+  });
+
   describe('click cancel', function () {
     it('new genome', function () {
-      var dialog;
-      var project;
       var genome = new ReferenceGenome();
-      return ServerConnector.getProject().then(function (result) {
-        project = result;
-        dialog = new EditGenomeDialog({
-          element: testDiv,
-          project: project,
-          referenceGenome: genome,
-          customMap: null,
-          serverConnector: ServerConnector
-        });
-        return dialog.init();
-      }).then(function () {
+      var dialog = createDialog(genome);
+      return dialog.init().then(function () {
         return dialog.open();
       }).then(function () {
         return $("[name=cancelGenome]", testDiv)[0].onclick();
@@ -64,13 +89,12 @@ describe('EditGenomeDialog', function () {
   describe('click save', function () {
     it('existing genome', function () {
       var dialog;
-      return ServerConnector.getReferenceGenome({organism:"9606", type:"UCSC",version:"hg38"}).then(function (genome) {
-        dialog = new EditGenomeDialog({
-          element: testDiv,
-          referenceGenome: genome,
-          customMap: null,
-          serverConnector: ServerConnector
-        });
+      return ServerConnector.getReferenceGenome({
+        organism: "9606",
+        type: "UCSC",
+        version: "hg38"
+      }).then(function (genome) {
+        dialog = createDialog(genome);
         return dialog.init();
       }).then(function () {
         return dialog.open();
@@ -80,6 +104,19 @@ describe('EditGenomeDialog', function () {
         dialog.destroy();
       });
     });
+
+    it('new genome', function () {
+      helper.loginAsAdmin();
+      var genome = new ReferenceGenome();
+      var dialog = createDialog(genome);
+      return dialog.init().then(function () {
+        return dialog.open();
+      }).then(function () {
+        return $("[name=saveGenome]", testDiv)[0].onclick();
+      }).then(function () {
+        dialog.destroy();
+      });
+    });
   });
 
 });
diff --git a/frontend-js/testFiles/apiCalls/genomics/POST_organismId=9606&sourceUrl=ftp%3A%2F%2Fhgdownload.cse.ucsc.edu%2FgoldenPath%2Fhg18%2FbigZips%2Fhg18.2bit&type=UCSC&version=hg38&token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/POST_organismId=9606&sourceUrl=ftp%3A%2F%2Fhgdownload.cse.ucsc.edu%2FgoldenPath%2Fhg18%2FbigZips%2Fhg18.2bit&type=UCSC&version=hg38&token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/POST_organismId=9606&sourceUrl=ftp%3A%2F%2Fhgdownload.cse.ucsc.edu%2FgoldenPath%2Fhg18%2FbigZips%2Fhg18.2bit&type=UCSC&version=hg38&token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000..c97ec2eab9
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+[{"url":"ftp://hgdownload.cse.ucsc.edu/goldenPath/hg18/bigZips/hg18.2bit"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000..c97ec2eab9
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=MOCK_TOKEN_ID&
@@ -0,0 +1 @@
+[{"url":"ftp://hgdownload.cse.ucsc.edu/goldenPath/hg18/bigZips/hg18.2bit"}]
\ No newline at end of file
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeController.java b/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeController.java
index b8c950515a..63b8088bd8 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeController.java
@@ -6,13 +6,16 @@ import java.util.Map;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
+import org.springframework.util.MultiValueMap;
 import org.springframework.web.bind.annotation.CookieValue;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
 import javassist.tools.rmi.ObjectNotFoundException;
+import lcsb.mapviewer.annotation.services.genome.ReferenceGenomeConnectorException;
 import lcsb.mapviewer.api.BaseController;
 import lcsb.mapviewer.api.QueryException;
 import lcsb.mapviewer.common.Configuration;
@@ -35,6 +38,17 @@ public class ReferenceGenomeController extends BaseController {
     return referenceGenomeController.getReferenceGenome(token, organism, type, version);
   }
 
+  @RequestMapping(value = "/genomics/taxonomies/{organismId}/genomeTypes/{type}/versions/{version}:getAvailableRemoteUrls", method = {
+      RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public List<Map<String, Object>> getRemoteUrls(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "organismId") String organism, //
+      @PathVariable(value = "type") String type, //
+      @PathVariable(value = "version") String version//
+  ) throws SecurityException, QueryException, ObjectNotFoundException {
+    return referenceGenomeController.getRemoteUrls(token, organism, type, version);
+  }
+
   @RequestMapping(value = "/genomics/taxonomies/", method = { RequestMethod.GET }, produces = {
       MediaType.APPLICATION_JSON_VALUE })
   public List<Map<String, Object>> getGenomeTaxonomies(//
@@ -43,6 +57,15 @@ public class ReferenceGenomeController extends BaseController {
     return referenceGenomeController.getReferenceGenomeTaxonomies(token);
   }
 
+  @RequestMapping(value = "/genomics/", method = { RequestMethod.POST }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object> addGenome(//
+      @RequestBody MultiValueMap<String, Object> formData, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, QueryException, IOException, ReferenceGenomeConnectorException  {
+    return referenceGenomeController.addReferenceGenome(formData, token);
+  }
+
   @RequestMapping(value = "/genomics/taxonomies/{organismId}/genomeTypes/", method = { RequestMethod.GET }, produces = {
       MediaType.APPLICATION_JSON_VALUE })
   public List<Map<String, Object>> getGenomeTaxonomyTypes(//
@@ -68,8 +91,9 @@ public class ReferenceGenomeController extends BaseController {
   ) throws SecurityException, QueryException, ObjectNotFoundException {
     return referenceGenomeController.getReferenceGenomes(token);
   }
-  
-  @RequestMapping(value = "/genomics/{genomeId}/", method = { RequestMethod.DELETE }, produces = { MediaType.APPLICATION_JSON_VALUE })
+
+  @RequestMapping(value = "/genomics/{genomeId}/", method = { RequestMethod.DELETE }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
   public Map<String, Object> removeGenome(//
       @PathVariable(value = "genomeId") String genomeId, //
       @CookieValue(value = Configuration.AUTH_TOKEN) String token //
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeRestImpl.java
index cedb3cc467..cd515a62d5 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeRestImpl.java
@@ -2,6 +2,7 @@ package lcsb.mapviewer.api.genomics;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -13,6 +14,7 @@ import java.util.TreeMap;
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.MultiValueMap;
 
 import lcsb.mapviewer.annotation.cache.BigFileCache;
 import lcsb.mapviewer.annotation.services.genome.ReferenceGenomeConnectorException;
@@ -25,7 +27,6 @@ import lcsb.mapviewer.model.map.layout.ReferenceGenome;
 import lcsb.mapviewer.model.map.layout.ReferenceGenomeGeneMapping;
 import lcsb.mapviewer.model.map.layout.ReferenceGenomeType;
 import lcsb.mapviewer.model.user.PrivilegeType;
-import lcsb.mapviewer.model.user.User;
 import lcsb.mapviewer.services.SecurityException;
 import lcsb.mapviewer.services.interfaces.IReferenceGenomeService;
 
@@ -69,6 +70,30 @@ public class ReferenceGenomeRestImpl extends BaseRestImpl {
     }
   }
 
+  public List<Map<String, Object>> getRemoteUrls(String token, String organismId, String type, String version)
+      throws SecurityException, QueryException, ObjectNotFoundException {
+    MiriamData organism = null;
+    if (organismId != null && !organismId.isEmpty()) {
+      organism = new MiriamData(MiriamType.TAXONOMY, organismId);
+    } else {
+      throw new QueryException("Unknown taxonomy organism: " + organismId);
+    }
+    try {
+      ReferenceGenomeType genomeType = ReferenceGenomeType.valueOf(type);
+      String url = referenceGenomeService.getUrlForGenomeVersion(genomeType, organism, version);
+
+      List<Map<String, Object>> result = new ArrayList<>();
+      if (url != null) {
+        Map<String, Object> row = new TreeMap<>();
+        row.put("url", url);
+        result.add(row);
+      }
+      return result;
+    } catch (IllegalArgumentException e) {
+      throw new QueryException("Cannot find type: " + type);
+    }
+  }
+
   private Map<String, Object> genomeToMap(ReferenceGenome genome) {
     Map<String, Object> result = new TreeMap<>();
     result.put("organism", super.createAnnotation(genome.getOrganism()));
@@ -190,4 +215,29 @@ public class ReferenceGenomeRestImpl extends BaseRestImpl {
     return okStatus();
   }
 
+  public Map<String, Object> addReferenceGenome(MultiValueMap<String, Object> formData, String token)
+      throws SecurityException, QueryException, IOException, ReferenceGenomeConnectorException {
+    if (!getUserService().userHasPrivilege(token, PrivilegeType.MANAGE_GENOMES)) {
+      throw new SecurityException("Access denied");
+    }
+
+    String organismId = getFirstValue(formData.get("organismId"));
+    String type = getFirstValue(formData.get("type"));
+    String version = getFirstValue(formData.get("version"));
+    String url = getFirstValue(formData.get("sourceUrl"));
+    MiriamData organism = null;
+    if (organismId != null && !organismId.isEmpty()) {
+      organism = new MiriamData(MiriamType.TAXONOMY, organismId);
+    } else {
+      throw new QueryException("Unknown taxonomy organism: " + organismId);
+    }
+    ReferenceGenomeType genomeType = ReferenceGenomeType.valueOf(type);
+    try {
+      referenceGenomeService.addReferenceGenome(genomeType, organism, version, url);
+      return okStatus();
+    } catch (URISyntaxException e) {
+      throw new QueryException("Problem wih given uri", e);
+    }
+  }
+
 }
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/genomics/ReferenceGenomeControllerTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/genomics/ReferenceGenomeControllerTest.java
index d1bb8e0b1f..35e85fa7db 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/genomics/ReferenceGenomeControllerTest.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/genomics/ReferenceGenomeControllerTest.java
@@ -98,6 +98,18 @@ public class ReferenceGenomeControllerTest extends RestTestFunctions {
     }
   }
 
+  @Test
+  public void testGetRemoteUrls() throws Exception {
+    try {
+      List<Map<String, Object>> result = referenceGenomeRestImpl.getRemoteUrls(adminToken, "9606", "UCSC", "hg18");
+      assertNotNull(result);
+      assertTrue(result.size() > 0);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
   @Test
   public void testGetAllDowloadedReferenceGenomes() throws Exception {
     try {
-- 
GitLab