diff --git a/src/main/html/webapp/components/core/job/detail/results/share-folder.stache b/src/main/html/webapp/components/core/job/detail/results/share-folder.stache
index 4786e40f..9ade7201 100644
--- a/src/main/html/webapp/components/core/job/detail/results/share-folder.stache
+++ b/src/main/html/webapp/components/core/job/detail/results/share-folder.stache
@@ -18,7 +18,7 @@
{{/files}}
Use the following command to download all results at once:
-
+
diff --git a/src/main/html/webapp/helpers/helpers.js b/src/main/html/webapp/helpers/helpers.js
index e8fbdf49..c7cf0ed7 100644
--- a/src/main/html/webapp/helpers/helpers.js
+++ b/src/main/html/webapp/helpers/helpers.js
@@ -40,7 +40,7 @@ function renderTreeItem(jobId, items, level) {
html += renderTreeItem(jobId, items[i].childs, level + 1);
} else {
html += ' '
- html += '' + items[i].name + '';
+ html += '' + items[i].name + '';
html += ' (' + items[i].size + ")";
}
html += "";
diff --git a/src/main/java/cloudgene/mapred/CommandLineInterface.java b/src/main/java/cloudgene/mapred/CommandLineInterface.java
index e2e87a11..0a63dc0c 100644
--- a/src/main/java/cloudgene/mapred/CommandLineInterface.java
+++ b/src/main/java/cloudgene/mapred/CommandLineInterface.java
@@ -23,7 +23,7 @@ private void printHeader() {
System.out.println();
System.out.println("Cloudgene " + Application.VERSION);
System.out.println("http://www.cloudgene.io");
- System.out.println("(c) 2009-2032 Lukas Forer and Sebastian Schoenherr");
+ System.out.println("(c) 2009-2024 Lukas Forer and Sebastian Schoenherr");
System.out.println();
}
diff --git a/src/main/java/cloudgene/mapred/database/DownloadDao.java b/src/main/java/cloudgene/mapred/database/DownloadDao.java
index c3256763..987cc62d 100644
--- a/src/main/java/cloudgene/mapred/database/DownloadDao.java
+++ b/src/main/java/cloudgene/mapred/database/DownloadDao.java
@@ -155,7 +155,35 @@ public Download findByJobAndPath(String job, String path) {
}
}
- class DownloadMapper implements IRowMapper {
+ public Download findByParameterAndName(CloudgeneParameterOutput param, String filename) {
+ StringBuilder sql = new StringBuilder();
+ sql.append("select * ");
+ sql.append("from downloads ");
+ sql.append("where name = ? and parameter_id = ? ");
+ sql.append("order by path ");
+
+ Object[] params = new Object[2];
+ params[0] = filename;
+ params[1] = param.getId();
+
+ Download result = null;
+
+ try {
+
+ result = (Download) queryForObject(sql.toString(), params,
+ new DownloadMapper());
+
+ log.debug("find download by param " + param.getId() + " and path " + filename
+ + " successful. results: " + result);
+
+ return result;
+ } catch (SQLException e) {
+ log.error("find download by job and path failed.", e);
+ return null;
+ }
+ }
+
+ class DownloadMapper implements IRowMapper {
@Override
public Object mapRow(ResultSet rs, int row) throws SQLException {
diff --git a/src/main/java/cloudgene/mapred/database/ParameterDao.java b/src/main/java/cloudgene/mapred/database/ParameterDao.java
index b33d7718..42e29eff 100644
--- a/src/main/java/cloudgene/mapred/database/ParameterDao.java
+++ b/src/main/java/cloudgene/mapred/database/ParameterDao.java
@@ -28,12 +28,12 @@ public ParameterDao(Database database) {
public boolean insert(CloudgeneParameterInput parameter) {
StringBuilder sql = new StringBuilder();
- sql.append("insert into parameter (name, `value`, input, job_id, type, variable, download, format, admin_only) ");
- sql.append("values (?,?,?,?,?,?,?,?,?)");
+ sql.append("insert into parameter (name, `value`, input, job_id, type, variable, download, format, admin_only, hash) ");
+ sql.append("values (?,?,?,?,?,?,?,?,?,?)");
try {
- Object[] params = new Object[9];
+ Object[] params = new Object[10];
if (parameter.getDescription() != null) {
params[0] = parameter.getDescription().substring(0, Math.min(parameter.getDescription().length(), 100));
} else {
@@ -47,6 +47,7 @@ public boolean insert(CloudgeneParameterInput parameter) {
params[6] = false;
params[7] = "";
params[8] = parameter.isAdminOnly();
+ params[9] = parameter.getHash();
int paramId = insert(sql.toString(), params);
parameter.setId(paramId);
@@ -63,12 +64,12 @@ public boolean insert(CloudgeneParameterInput parameter) {
public boolean insert(CloudgeneParameterOutput parameter) {
StringBuilder sql = new StringBuilder();
- sql.append("insert into parameter (name, `value`, input, job_id, type, variable, download, format, admin_only) ");
- sql.append("values (?,?,?,?,?,?,?,?,?)");
+ sql.append("insert into parameter (name, `value`, input, job_id, type, variable, download, format, admin_only, hash) ");
+ sql.append("values (?,?,?,?,?,?,?,?,?,?)");
try {
- Object[] params = new Object[9];
+ Object[] params = new Object[10];
params[0] = parameter.getDescription().substring(0, Math.min(parameter.getDescription().length(), 100));
params[1] = parameter.getValue();
params[2] = false;
@@ -78,6 +79,7 @@ public boolean insert(CloudgeneParameterOutput parameter) {
params[6] = parameter.isDownload();
params[7] = "";
params[8] = parameter.isAdminOnly();
+ params[9] = parameter.getHash();
int paramId = insert(sql.toString(), params);
parameter.setId(paramId);
@@ -180,6 +182,61 @@ public CloudgeneParameterOutput findById(int id) {
}
}
+ public CloudgeneParameterOutput findByHash(String hash) {
+ StringBuilder sql = new StringBuilder();
+ sql.append("select * ");
+ sql.append("from parameter ");
+ sql.append("where hash = ?");
+
+ Object[] params = new Object[1];
+ params[0] = hash;
+
+ CloudgeneParameterOutput result = null;
+
+ try {
+
+ result = (CloudgeneParameterOutput) queryForObject(sql.toString(), params, new ParameterOutputMapper());
+
+ DownloadDao downloadDao = new DownloadDao(database);
+ List downloads = downloadDao.findAllByParameter(result);
+ result.setFiles(downloads);
+
+ log.debug("find parameter by hash '" + hash + "' successful.");
+
+ return result;
+ } catch (SQLException e) {
+ log.error("find parameter by hash '" + hash + "' failed.", e);
+ return null;
+ }
+ }
+
+ public List findAllOutput() {
+ StringBuilder sql = new StringBuilder();
+ sql.append("select * ");
+ sql.append("from parameter ");
+ sql.append("where input = false");
+
+ List result = new Vector();
+
+ try {
+
+ result = query(sql.toString(), new ParameterOutputMapper());
+
+ DownloadDao downloadDao = new DownloadDao(database);
+ for (CloudgeneParameterOutput parameter : result) {
+ List downloads = downloadDao.findAllByParameter(parameter);
+ parameter.setFiles(downloads);
+ }
+
+ log.debug("find all output parameters successful. results: " + result.size());
+
+ return result;
+ } catch (SQLException e) {
+ log.error("find all output parameters failed.", e);
+ return null;
+ }
+ }
+
class ParameterInputMapper implements IRowMapper {
@Override
@@ -192,6 +249,7 @@ public Object mapRow(ResultSet rs, int row) throws SQLException {
parameter.setType(WdlParameterInputType.getEnum(rs.getString("type")));
parameter.setId(rs.getInt("id"));
parameter.setAdminOnly(rs.getBoolean("admin_only"));
+ parameter.setHash(rs.getString("hash"));
return parameter;
}
@@ -211,6 +269,7 @@ public Object mapRow(ResultSet rs, int row) throws SQLException {
parameter.setDownload(rs.getBoolean("download"));
parameter.setId(rs.getInt("id"));
parameter.setAdminOnly(rs.getBoolean("admin_only"));
+ parameter.setHash(rs.getString("hash"));
return parameter;
}
diff --git a/src/main/java/cloudgene/mapred/jobs/CloudgeneJob.java b/src/main/java/cloudgene/mapred/jobs/CloudgeneJob.java
index 96f14f4d..43f3e1fb 100644
--- a/src/main/java/cloudgene/mapred/jobs/CloudgeneJob.java
+++ b/src/main/java/cloudgene/mapred/jobs/CloudgeneJob.java
@@ -59,6 +59,7 @@ public CloudgeneJob(User user, String id, WdlApp app, Map params
outputParams = new Vector();
for (WdlParameterOutput output : app.getWorkflow().getOutputs()) {
CloudgeneParameterOutput newOutput = new CloudgeneParameterOutput(output);
+ newOutput.initHash();
newOutput.setJob(this);
outputParams.add(newOutput);
}
@@ -93,6 +94,7 @@ protected void initLogOutput() {
logOutput.setName(CLOUDGENE_LOGS_PARAM);
logOutput.setType(WdlParameterOutputType.LOCAL_FOLDER);
logOutput.setJob(this);
+ logOutput.initHash();
}
@Override
diff --git a/src/main/java/cloudgene/mapred/jobs/CloudgeneParameterInput.java b/src/main/java/cloudgene/mapred/jobs/CloudgeneParameterInput.java
index d06e458d..09bb16cd 100644
--- a/src/main/java/cloudgene/mapred/jobs/CloudgeneParameterInput.java
+++ b/src/main/java/cloudgene/mapred/jobs/CloudgeneParameterInput.java
@@ -21,6 +21,8 @@ public class CloudgeneParameterInput {
private boolean adminOnly = false;
+ private String hash = "";
+
public CloudgeneParameterInput() {
}
@@ -97,4 +99,11 @@ public boolean isAdminOnly() {
return adminOnly;
}
+ public void setHash(String hash) {
+ this.hash = hash;
+ }
+
+ public String getHash() {
+ return hash;
+ }
}
diff --git a/src/main/java/cloudgene/mapred/jobs/CloudgeneParameterOutput.java b/src/main/java/cloudgene/mapred/jobs/CloudgeneParameterOutput.java
index 6f150967..944ffbfe 100644
--- a/src/main/java/cloudgene/mapred/jobs/CloudgeneParameterOutput.java
+++ b/src/main/java/cloudgene/mapred/jobs/CloudgeneParameterOutput.java
@@ -1,11 +1,13 @@
package cloudgene.mapred.jobs;
import java.util.List;
+import java.util.Random;
import java.util.Vector;
import cloudgene.mapred.util.HashUtil;
import cloudgene.mapred.wdl.WdlParameterOutput;
import cloudgene.mapred.wdl.WdlParameterOutputType;
+import org.apache.commons.math3.random.RandomGenerator;
public class CloudgeneParameterOutput {
@@ -141,13 +143,17 @@ public void setHash(String hash) {
public String getHash() {
return hash;
}
-
- public String createHash() {
- String hash = "";
- for (Download download: files) {
- hash += download.getHash();
+
+ public void initHash() {
+ String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ hash = "";
+ Random random = new Random();
+ int length = 40;
+ for (int i = 0; i < length; i++) {
+ int index = random.nextInt(alphabet.length());
+ char randomChar = alphabet.charAt(index);
+ hash += randomChar;
}
- return HashUtil.getSha256(hash);
}
}
diff --git a/src/main/java/cloudgene/mapred/server/Application.java b/src/main/java/cloudgene/mapred/server/Application.java
index 93472179..ba18099c 100644
--- a/src/main/java/cloudgene/mapred/server/Application.java
+++ b/src/main/java/cloudgene/mapred/server/Application.java
@@ -27,7 +27,7 @@
@Context
public class Application {
- public static final String VERSION = "3.0.0-beta4";
+ public static final String VERSION = "3.0.0-beta5";
private Database database;
diff --git a/src/main/java/cloudgene/mapred/server/controller/DownloadController.java b/src/main/java/cloudgene/mapred/server/controller/DownloadController.java
index 8f8cfd1e..47fd8c20 100644
--- a/src/main/java/cloudgene/mapred/server/controller/DownloadController.java
+++ b/src/main/java/cloudgene/mapred/server/controller/DownloadController.java
@@ -82,26 +82,36 @@ public MutableHttpResponse downloadPublicLink(String hash, String f
}
- @Get("/get/{paramId}/{hash}")
+ @Get("/browse/{hash}/{filename:.+}")
@Secured(SecurityRule.IS_ANONYMOUS)
- public String downloadScript(String paramId, String hash) {
-
- int id = -1;
- try {
- id = Integer.parseInt(paramId);
- } catch (NumberFormatException e) {
- throw new JsonHttpStatusException(HttpStatus.BAD_REQUEST, "Parameter ID is not numeric.");
- }
+ public MutableHttpResponse downloadByParamHash(String hash, String filename)
+ throws URISyntaxException, IOException {
ParameterDao parameterDao = new ParameterDao(application.getDatabase());
- CloudgeneParameterOutput param = parameterDao.findById(id);
+ CloudgeneParameterOutput param = parameterDao.findByHash(hash);
if (param == null) {
- throw new JsonHttpStatusException(HttpStatus.NOT_FOUND, "Param " + param + " not found.");
+ throw new JsonHttpStatusException(HttpStatus.NOT_FOUND, "Param for hash " + hash + " not found.");
}
- if (!hash.equals(param.createHash())) {
- throw new JsonHttpStatusException(HttpStatus.FORBIDDEN, "Download forbidden.");
+ DownloadDao dao = new DownloadDao(application.getDatabase());
+ Download download = dao.findByParameterAndName(param, filename);
+
+ String message = String.format("Job: Anonymously downloading file '%s' (hash %s)", filename, hash);
+ log.info(message);
+ return downloadService.download(download);
+
+ }
+
+ @Get("/get/{hash}")
+ @Secured(SecurityRule.IS_ANONYMOUS)
+ public String downloadScript(String hash) {
+
+ ParameterDao parameterDao = new ParameterDao(application.getDatabase());
+ CloudgeneParameterOutput param = parameterDao.findByHash(hash);
+
+ if (param == null) {
+ throw new JsonHttpStatusException(HttpStatus.NOT_FOUND, "Param for hash " + hash + " not found.");
}
DownloadDao dao = new DownloadDao(application.getDatabase());
diff --git a/src/main/java/cloudgene/mapred/server/responses/JobResponse.java b/src/main/java/cloudgene/mapred/server/responses/JobResponse.java
index e53eb2f9..dfcdd94a 100644
--- a/src/main/java/cloudgene/mapred/server/responses/JobResponse.java
+++ b/src/main/java/cloudgene/mapred/server/responses/JobResponse.java
@@ -169,9 +169,7 @@ public static JobResponse build(AbstractJob job, User user) {
// create tree
for (CloudgeneParameterOutput param : job.getOutputParams()) {
- String hash = param.createHash();
- param.setHash(hash);
- param.setTree(JobResultsTreeUtil.createTree(param.getFiles()));
+ param.setTree(JobResultsTreeUtil.createTree(param));
}
// removes outputs that are for admin only
diff --git a/src/main/java/cloudgene/mapred/util/JobResultsTreeUtil.java b/src/main/java/cloudgene/mapred/util/JobResultsTreeUtil.java
index 09f240df..bd45da04 100644
--- a/src/main/java/cloudgene/mapred/util/JobResultsTreeUtil.java
+++ b/src/main/java/cloudgene/mapred/util/JobResultsTreeUtil.java
@@ -4,14 +4,15 @@
import java.util.List;
import java.util.Vector;
+import cloudgene.mapred.jobs.CloudgeneParameterOutput;
import cloudgene.mapred.jobs.Download;
import cloudgene.mapred.jobs.JobResultsTreeItem;
public class JobResultsTreeUtil {
- public static List createTree(List files) {
+ public static List createTree(CloudgeneParameterOutput param) {
List items = new Vector();
- for (Download file : files) {
+ for (Download file : param.getFiles()) {
String[] tiles = file.getName().split("/");
JobResultsTreeItem root = null;
for (int i = 0; i < tiles.length - 1; i++) {
@@ -32,7 +33,11 @@ public static List createTree(List files) {
}
JobResultsTreeItem item = new JobResultsTreeItem();
item.setName(tiles[tiles.length - 1]);
- item.setPath(file.getPath());
+ if (param.getHash() != null) {
+ item.setPath("/browse/" + param.getHash() + "/" + file.getName());
+ } else {
+ item.setPath("/share/results/" + file.getHash() + "/" + file.getName());
+ }
item.setHash(file.getHash());
item.setSize(file.getSize());
item.setFolder(false);
diff --git a/src/main/sql/updates.sql b/src/main/sql/updates.sql
index f4849220..44d54554 100644
--- a/src/main/sql/updates.sql
+++ b/src/main/sql/updates.sql
@@ -168,3 +168,6 @@ alter table job add column user_agent VARCHAR (400);
-- 3.0.0-beta1
alter table `user` add column api_token_expires_on timestamp null default null;
+
+-- 3.0.0-beta5
+alter table `parameter` add column hash varchar(300) null default null;