Commit 9cbe83f7 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

every map has optional default center coordinates where map should be focused...

every map has optional default center coordinates where map should be focused after first open during session
parent 29b9b684
Pipeline #2639 passed with stage
in 44 seconds
......@@ -408,6 +408,12 @@ ServerConnector.updateOverlayUrl = function (queryParams) {
});
};
ServerConnector.updateModelUrl = function (queryParams) {
return this.getApiUrl({
url: this.getModelsUrl(queryParams)
});
};
ServerConnector.deleteOverlayUrl = function (queryParams) {
return this.getApiUrl({
url: this.getOverlayByIdUrl(queryParams)
......@@ -1638,6 +1644,25 @@ ServerConnector.updateOverlay = function (overlay) {
return self.sendPatchRequest(self.updateOverlayUrl(queryParams), filterParams);
};
ServerConnector.updateModel = function (params) {
var self = this;
var model = params.model;
var queryParams = {
projectId: params.projectId,
modelId: model.getId()
};
var filterParams = {
model: {
id: model.getId(),
defaultCenterX: model.getDefaultCenterX(),
defaultCenterY: model.getDefaultCenterY(),
defaultZoomLevel: model.getDefaultZoomLevel()
}
};
return self.sendPatchRequest(self.updateModelUrl(queryParams), filterParams);
};
ServerConnector.removeOverlay = function (params) {
var self = this;
var queryParams = {
......
......@@ -441,7 +441,14 @@ CustomMap.prototype.customizeGoogleMapView = function (div) {
// center map and zoom in to fit into browser window if there is no
// information about coordinates in the session
if (ServerConnector.getSessionData(this.getProject()).getCenter(this.getModel()) === undefined) {
if (ServerConnector.getSessionData(this.getProject()).getCenter(this.getModel()) === undefined &&
(this.getModel().getDefaultCenterX() === undefined ||
this.getModel().getDefaultCenterY() === undefined ||
this.getModel().getDefaultZoomLevel() === undefined ||
this.getModel().getDefaultCenterX() === null ||
this.getModel().getDefaultCenterY() === null ||
this.getModel().getDefaultZoomLevel() === null
)) {
var bounds = new google.maps.LatLngBounds();
bounds.extend(this.getTopLeftLatLng());
bounds.extend(this.getBottomRightLatLng());
......@@ -459,15 +466,6 @@ CustomMap.prototype.createMapChangedCallbacks = function () {
var self = this;
var sessionData = ServerConnector.getSessionData(self.getProject());
// if we have zoom level data stored in session then restore it
var level = sessionData.getZoomLevel(self.getModel());
if (parseInt(level) > 0) {
level = parseInt(level);
this.getGoogleMap().setZoom(level);
} else {
sessionData.setZoomLevel(self.getModel(), self.getGoogleMap().getZoom());
}
// listener for changing type of layout
google.maps.event.addListener(self.getGoogleMap(), 'maptypeid_changed', function () {
sessionData.setSelectedBackgroundOverlay(self.getGoogleMap().getMapTypeId());
......
"use strict";
require("../../mocha-config");
var EditProjectDialog = require('../../../../main/js/gui/admin/EditProjectDialog');
var ServerConnector = require('../../ServerConnector-mock');
var logger = require('../../logger');
var assert = require('assert');
describe('EditProjectDialog', function () {
it('open', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.open();
}).then(function () {
assert.equal(0, logger.getWarnings().length);
dialog.destroy();
});
});
it('init', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.init();
}).then(function () {
dialog.destroy();
});
});
it('saveOverlay', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.init();
}).then(function () {
return dialog.saveOverlay(14081);
}).then(function () {
dialog.destroy();
});
});
it('saveUser', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.init();
}).then(function () {
return dialog.saveUser("anonymous");
}).then(function () {
dialog.destroy();
});
});
it('onSaveClicked', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
project.setVersion("2.01");
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.onSaveClicked();
}).then(function (result) {
assert.ok(project === result);
dialog.destroy();
});
});
it('openAddOverlayDialog', function () {
var dialog;
return ServerConnector.getProject().then(function (project) {
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.openAddOverlayDialog();
}).then(function () {
dialog.destroy();
});
});
});
"use strict";
require("../../mocha-config");
var EditProjectDialog = require('../../../../main/js/gui/admin/EditProjectDialog');
var ServerConnector = require('../../ServerConnector-mock');
var logger = require('../../logger');
var assert = require('assert');
describe('EditProjectDialog', function () {
it('open', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.open();
}).then(function () {
assert.equal(0, logger.getWarnings().length);
dialog.destroy();
});
});
it('init', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.init();
}).then(function () {
dialog.destroy();
});
});
it('saveOverlay', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.init();
}).then(function () {
return dialog.saveOverlay(14081);
}).then(function () {
dialog.destroy();
});
});
it('saveMap', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.init();
}).then(function () {
return dialog.saveMap(15781);
}).then(function () {
dialog.destroy();
});
});
it('saveUser', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.init();
}).then(function () {
return dialog.saveUser("anonymous");
}).then(function () {
dialog.destroy();
});
});
it('onSaveClicked', function () {
var dialog;
var project;
return ServerConnector.getProject().then(function (result) {
project = result;
project.setVersion("2.01");
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.onSaveClicked();
}).then(function (result) {
assert.ok(project === result);
dialog.destroy();
});
});
it('openAddOverlayDialog', function () {
var dialog;
return ServerConnector.getProject().then(function (project) {
dialog = new EditProjectDialog({
element: testDiv,
project: project,
customMap: null
});
return dialog.openAddOverlayDialog();
}).then(function () {
dialog.destroy();
});
});
});
{"version":null,"name":"UNKNOWN DISEASE MAP","idObject":15781,"tileSize":256,"width":1305,"height":473,"defaultCenterX":3.0,"defaultCenterY":4.0,"defaultZoomLevel":null,"minZoom":2,"maxZoom":5,"layouts":[{"idObject":14081,"modelId":15781,"name":"Pathways and compartments","description":"","status":"Not available","publicOverlay":true,"defaultOverlay":false,"progress":"0.00","directory":"5e8ff9bf55ba3508199d22e984129be6/_nested0","creator":"","inputDataAvailable":"false"},{"idObject":14082,"modelId":15781,"name":"Network","description":"","status":"Not available","publicOverlay":true,"defaultOverlay":false,"progress":"0.00","directory":"5e8ff9bf55ba3508199d22e984129be6/_normal0","creator":"","inputDataAvailable":"false"},{"idObject":14083,"modelId":15781,"name":"Empty","description":"","status":"Not available","publicOverlay":true,"defaultOverlay":true,"progress":"0.00","directory":"5e8ff9bf55ba3508199d22e984129be6/_empty0","creator":"","inputDataAvailable":"false"},{"idObject":18076,"modelId":15781,"name":"C:\\fakepath\\test.txt","description":"xxx","status":"OK","publicOverlay":true,"defaultOverlay":false,"progress":"0.00","directory":"5e8ff9bf55ba3508199d22e984129be6/.18076","creator":"","inputDataAvailable":"true"},{"idObject":18077,"modelId":15781,"name":"xxx","description":"yyy","status":"OK","publicOverlay":true,"defaultOverlay":false,"progress":"0.00","directory":"5e8ff9bf55ba3508199d22e984129be6/.18077","creator":"","inputDataAvailable":"true"},{"idObject":22750,"modelId":15781,"name":"new-global","description":"","status":"OK","publicOverlay":true,"defaultOverlay":false,"progress":"0.00","directory":"5e8ff9bf55ba3508199d22e984129be6/.22750","creator":"","inputDataAvailable":"true"}],"submodels":[],"centerLatLng":{"lat":79.18277721779353,"lng":-135.06093781915757},"topLeftLatLng":{"lat":85.05112877980659,"lng":-180.0},"bottomRightLatLng":{"lat":81.26928406550978,"lng":-90.0},"submodelType":"UNKNOWN"}
\ No newline at end of file
-- column which indicates that this overlay should be shown on startup
alter table layout add column defaultoverlay boolean default false;
-- default positioning of map when session data is not available
alter table model_table add column defaultzoomlevel integer default null;
alter table model_table add column defaultcenterx double precision default null;
alter table model_table add column defaultcentery double precision default null;
package lcsb.mapviewer.api.projects.models;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import lcsb.mapviewer.api.BaseController;
import lcsb.mapviewer.api.ObjectNotFoundException;
import lcsb.mapviewer.common.Configuration;
import lcsb.mapviewer.services.SecurityException;
@RestController
public class ModelController extends BaseController {
@Autowired
private ModelRestImpl modelController;
@RequestMapping(value = "/projects/{projectId:.+}/models/", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
public List<ModelMetaData> getModels(//
@PathVariable(value = "projectId") String projectId, //
@CookieValue(value = Configuration.AUTH_TOKEN) String token //
) throws SecurityException, ObjectNotFoundException {
return modelController.getModels(projectId, token);
}
@RequestMapping(value = "/projects/{projectId:.+}/models/{modelId:.+}", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
public Object getModel(//
@PathVariable(value = "modelId") String modelId, //
@PathVariable(value = "projectId") String projectId, //
@CookieValue(value = Configuration.AUTH_TOKEN) String token //
) throws SecurityException, ObjectNotFoundException {
if (modelId.equals("*")) {
return modelController.getModels(projectId, token);
} else {
return modelController.getModel(projectId, modelId, token);
}
}
package lcsb.mapviewer.api.projects.models;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
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 com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import lcsb.mapviewer.api.BaseController;
import lcsb.mapviewer.api.ObjectNotFoundException;
import lcsb.mapviewer.api.QueryException;
import lcsb.mapviewer.common.Configuration;
import lcsb.mapviewer.services.SecurityException;
@RestController
public class ModelController extends BaseController {
@Autowired
private ModelRestImpl modelController;
@RequestMapping(value = "/projects/{projectId:.+}/models/", method = { RequestMethod.GET }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public List<ModelMetaData> getModels(//
@PathVariable(value = "projectId") String projectId, //
@CookieValue(value = Configuration.AUTH_TOKEN) String token //
) throws SecurityException, ObjectNotFoundException {
return modelController.getModels(projectId, token);
}
@RequestMapping(value = "/projects/{projectId:.+}/models/{modelId:.+}", method = { RequestMethod.GET }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public Object getModel(//
@PathVariable(value = "modelId") String modelId, //
@PathVariable(value = "projectId") String projectId, //
@CookieValue(value = Configuration.AUTH_TOKEN) String token //
) throws SecurityException, ObjectNotFoundException {
if (modelId.equals("*")) {
return modelController.getModels(projectId, token);
} else {
return modelController.getModel(projectId, modelId, token);
}
}
@RequestMapping(value = "/projects/{projectId:.+}/models/{modelId:.+}", method = { RequestMethod.PATCH }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public Object updateModel(//
@PathVariable(value = "modelId") String modelId, //
@PathVariable(value = "projectId") String projectId, //
@RequestBody String body, //
@CookieValue(value = Configuration.AUTH_TOKEN) String token //
) throws SecurityException, JsonParseException, JsonMappingException, IOException, QueryException {
Map<String, Object> node = parseBody(body);
Map<String, Object> data = getData(node, "model");
return modelController.updateModel(projectId, modelId, data, token);
}
}
\ No newline at end of file
......@@ -46,6 +46,12 @@ public class ModelMetaData implements Serializable {
private Integer height;
private Double defaultCenterX;
private Double defaultCenterY;
private Integer defaultZoomLevel;
/**
* Minimum zoom level that should be allowed by the Google Maps API.
*/
......@@ -104,6 +110,9 @@ public class ModelMetaData implements Serializable {
this.setCenterLatLng(cConverter.toLatLng(new Point2D.Double(size / 2, size / 2)));
this.setBottomRightLatLng(cConverter.toLatLng(new Point2D.Double(model.getWidth(), model.getHeight())));
this.setTopLeftLatLng(cConverter.toLatLng(new Point2D.Double(0, 0)));
this.setDefaultCenterX(model.getDefaultCenterX());
this.setDefaultCenterY(model.getDefaultCenterY());
this.setDefaultZoomLevel(model.getDefaultZoomLevel());
List<ModelMetaData> submodels = new ArrayList<>();
for (ModelSubmodelConnection connection : model.getSubmodels()) {
......@@ -362,4 +371,28 @@ public class ModelMetaData implements Serializable {
this.submodelType = submodelType;
}
public Integer getDefaultZoomLevel() {
return defaultZoomLevel;
}
public void setDefaultZoomLevel(Integer defaultZoomLevel) {
this.defaultZoomLevel = defaultZoomLevel;
}
public Double getDefaultCenterX() {
return defaultCenterX;
}
public void setDefaultCenterX(Double defaultCenterX) {
this.defaultCenterX = defaultCenterX;
}
public Double getDefaultCenterY() {
return defaultCenterY;
}
public void setDefaultCenterY(Double defaultCenterY) {
this.defaultCenterY = defaultCenterY;
}
}
......@@ -2,6 +2,8 @@ package lcsb.mapviewer.api.projects.models;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -9,8 +11,12 @@ import org.springframework.transaction.annotation.Transactional;
import lcsb.mapviewer.api.BaseRestImpl;
import lcsb.mapviewer.api.ObjectNotFoundException;
import lcsb.mapviewer.api.QueryException;
import lcsb.mapviewer.common.exception.InvalidArgumentException;
import lcsb.mapviewer.model.Project;
import lcsb.mapviewer.model.map.model.Model;
import lcsb.mapviewer.model.map.model.ModelData;
import lcsb.mapviewer.model.user.PrivilegeType;
import lcsb.mapviewer.services.SecurityException;
import lcsb.mapviewer.services.interfaces.ILayoutService;
import lcsb.mapviewer.services.view.AuthenticationToken;
......@@ -72,4 +78,86 @@ public class ModelRestImpl extends BaseRestImpl {
}
return result;
}
public ModelMetaData updateModel(String projectId, String modelId, Map<String, Object> data, String token)
throws SecurityException, QueryException {
AuthenticationToken authenticationToken = getUserService().getToken(token);
Project project = getProjectService().getProjectByProjectId(projectId, authenticationToken);
if (project == null) {
throw new ObjectNotFoundException("Project with given id doesn't exist");
}
boolean canModify = getUserService().userHasPrivilege(authenticationToken, PrivilegeType.ADD_MAP);
if (!canModify) {
throw new SecurityException("You cannot update projects");
}
ModelData model = null;
Integer id = Integer.valueOf(modelId);
for (ModelData m : project.getModels()) {
if (m.getId().equals(id)) {
model = m;
}
}
if (model == null) {
throw new ObjectNotFoundException("Model with given id doesn't exist");
}
Set<String> fields = data.keySet();
for (String fieldName : fields) {
Object value = data.get(fieldName);
if (fieldName.equalsIgnoreCase("defaultCenterX")) {
model.setDefaultCenterX(parseDouble(value));
} else if (fieldName.equalsIgnoreCase("defaultCenterY")) {
model.setDefaultCenterY(parseDouble(value));
} else if (fieldName.equalsIgnoreCase("defaultZoomLevel")) {
model.setDefaultZoomLevel(parseInteger(value));
} else if (fieldName.equalsIgnoreCase("id")) {
if (!model.getId().equals(parseInteger(value))) {
throw new QueryException("Id doesn't match: " + value + ", " + model.getId());
}
} else {
throw new QueryException("Unknown field: " + fieldName);
}
}
getModelService().updateModel(model, authenticationToken);
return getModel(projectId, modelId, token);
}
private Integer parseInteger(Object value) throws QueryException {