Commit bc7342d0 authored by Nuno Oliveira's avatar Nuno Oliveira
Browse files

[GEOS-7347] Allow to enter an allowed area in Geofence UI

parent eb197202
......@@ -41,6 +41,10 @@
<label for="access"><wicket:message key="access"></wicket:message></label>
<select wicket:id="access" id="access" />
</li>
<li>
<label wicket:id="allowedAreaLabel"></label>
<textarea wicket:id="allowedArea" id="allowedArea" style="width: 50%; height:100px;"></textarea>
</li>
</ul>
</fieldset>
</li>
......
......@@ -5,6 +5,7 @@
package org.geoserver.geofence.web;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
......@@ -13,13 +14,15 @@ import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Level;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.WKTReader;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.*;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.ResourceModel;
......@@ -27,10 +30,12 @@ import org.geoserver.catalog.Predicates;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.catalog.util.CloseableIterator;
import org.geoserver.geofence.core.model.RuleLimits;
import org.geoserver.geofence.core.model.enums.GrantType;
import org.geoserver.geofence.services.dto.ShortRule;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.Service;
import org.geoserver.platform.exception.GeoServerRuntimException;
import org.geoserver.security.GeoServerRoleService;
import org.geoserver.security.GeoServerSecurityManager;
import org.geoserver.security.impl.GeoServerRole;
......@@ -52,76 +57,128 @@ import org.springframework.dao.DuplicateKeyException;
*
*/
public class GeofenceRulePage extends GeoServerSecuredPage {
private class RuleFormData implements Serializable {
ShortRule rule;
RuleLimits ruleLimits;
String allowedArea;
}
protected DropDownChoice<String> userChoice, roleChoice, serviceChoice, requestChoice, workspaceChoice, layerChoice, accessChoice;
protected DropDownChoice<GrantType> grantTypeChoice;
protected TextArea<String> allowedArea;
protected Label allowedAreaLabel;
public GeofenceRulePage(final ShortRule rule, final GeofenceRulesModel rules) {
RuleFormData ruleFormData = new RuleFormData();
ruleFormData.rule = rule;
final RuleLimits ruleLimits = rules.getRulesLimits(rule.getId());
if (ruleLimits == null) {
ruleFormData.ruleLimits = new RuleLimits();
} else {
ruleFormData.ruleLimits = ruleLimits;
ruleFormData.allowedArea = getAllowedAreaAsString(ruleLimits);
}
CompoundPropertyModel ruleFormModel = new CompoundPropertyModel<RuleFormData>(ruleFormData);
// build the form
final Form<ShortRule> form = new Form<ShortRule>("form", new CompoundPropertyModel<ShortRule>(rule));
final Form<RuleFormData> form = new Form<>("form", ruleFormModel);
add(form);
form.add(new TextField<Integer>("priority").setRequired(true));
form.add(roleChoice = new DropDownChoice<String>("roleName", getRoleNames()));
form.add(new TextField<>("priority", ruleFormModel.bind("rule.priority")).setRequired(true));
form.add(roleChoice = new DropDownChoice<>("roleName", ruleFormModel.bind("rule.roleName"), getRoleNames()));
roleChoice.add(new OnChangeAjaxBehavior() {
private static final long serialVersionUID = -2880886409750911044L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
userChoice.setChoices(getUserNames(roleChoice.getConvertedInput()));
((ShortRule) form.getModelObject()).setUserName(null);
form.getModelObject().rule.setUserName(null);
userChoice.modelChanged();
target.addComponent(userChoice);
}
});
roleChoice.setNullValid(true);
form.add(userChoice = new DropDownChoice<String>("userName", getUserNames(rule.getRoleName())));
form.add(userChoice = new DropDownChoice<>("userName", ruleFormModel.bind("rule.userName"), getUserNames(rule.getRoleName())));
userChoice.setOutputMarkupId(true);
userChoice.setNullValid(true);
form.add(serviceChoice = new DropDownChoice<String>("service", getServiceNames()));
form.add(serviceChoice = new DropDownChoice<>("service", ruleFormModel.bind("rule.service"), getServiceNames()));
serviceChoice.add(new OnChangeAjaxBehavior() {
private static final long serialVersionUID = -5925784823433092831L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
requestChoice.setChoices(getOperationNames(serviceChoice.getConvertedInput()));
((ShortRule) form.getModelObject()).setRequest(null);
form.getModelObject().rule.setRequest(null);
requestChoice.modelChanged();
target.addComponent(requestChoice);
}
});
serviceChoice.setNullValid(true);
form.add(requestChoice = new DropDownChoice<String>("request", getOperationNames(rule.getService()),
new CaseConversionRenderer()));
form.add(requestChoice = new DropDownChoice<>("request", ruleFormModel.bind("rule.request"),
getOperationNames(rule.getService()), new CaseConversionRenderer()));
requestChoice.setOutputMarkupId(true);
requestChoice.setNullValid(true);
form.add(workspaceChoice = new DropDownChoice<String>("workspace", getWorkspaceNames()));
form.add(workspaceChoice = new DropDownChoice<>("workspace", ruleFormModel.bind("rule.workspace"),
getWorkspaceNames()));
workspaceChoice.add(new OnChangeAjaxBehavior() {
private static final long serialVersionUID = 732177308220189475L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
layerChoice.setChoices(getLayerNames(workspaceChoice.getConvertedInput()));
((ShortRule) form.getModelObject()).setLayer(null);
form.getModelObject().rule.setLayer(null);
layerChoice.modelChanged();
target.addComponent(layerChoice);
}
});
workspaceChoice.setNullValid(true);
form.add(layerChoice = new DropDownChoice<String>("layer", getLayerNames(rule.getWorkspace())));
form.add(layerChoice = new DropDownChoice<>("layer", ruleFormModel.bind("rule.layer"), getLayerNames(rule.getWorkspace())));
layerChoice.setOutputMarkupId(true);
layerChoice.setNullValid(true);
form.add(grantTypeChoice =
new DropDownChoice<GrantType>("access", Arrays.asList(GrantType.values()), new GrantTypeRenderer()));
form.add(grantTypeChoice = new DropDownChoice<>("access", ruleFormModel.bind("rule.access"),
Arrays.asList(GrantType.values()), new GrantTypeRenderer()));
grantTypeChoice.setRequired(true);
grantTypeChoice.add(new OnChangeAjaxBehavior() {
@Override
protected void onUpdate(AjaxRequestTarget target) {
if (grantTypeChoice.getConvertedInput().equals(GrantType.LIMIT)) {
allowedAreaLabel.setVisible(true);
allowedArea.setVisible(true);
} else {
allowedAreaLabel.setVisible(false);
allowedArea.setVisible(false);
}
target.addComponent(allowedAreaLabel);
target.addComponent(allowedArea);
}
});
form.add(allowedAreaLabel = new Label("allowedAreaLabel", new ResourceModel("allowedArea", "Allow area")));
allowedAreaLabel.setVisible(form.getModelObject().rule.getAccess() != null
&& form.getModelObject().rule.getAccess().equals(GrantType.LIMIT));
allowedAreaLabel.setOutputMarkupId(true);
allowedAreaLabel.setOutputMarkupPlaceholderTag(true);
form.add(allowedArea = new TextArea<>("allowedArea", ruleFormModel.bind("allowedArea")));
allowedArea.setConvertedInput(form.getModelObject().allowedArea);
allowedArea.setVisible(form.getModelObject().rule.getAccess() != null
&& form.getModelObject().rule.getAccess().equals(GrantType.LIMIT));
allowedArea.setOutputMarkupId(true);
allowedArea.setOutputMarkupPlaceholderTag(true);
// build the submit/cancel
form.add(new SubmitLink("save") {
......@@ -129,9 +186,12 @@ public class GeofenceRulePage extends GeoServerSecuredPage {
@Override
public void onSubmit() {
ShortRule rule = (ShortRule) getForm().getModelObject();
RuleFormData ruleFormData = (RuleFormData) getForm().getModelObject();
try {
rules.save(rule);
rules.save(ruleFormData.rule);
if (ruleFormData.rule.getAccess().equals(GrantType.LIMIT)) {
rules.save(ruleFormData.rule.getId(), parseAllowedArea(ruleFormData.allowedArea));
}
doReturn(GeofenceServerPage.class);
} catch (DuplicateKeyException e) {
error(new ResourceModel("GeofenceRulePage.duplicate").getObject());
......@@ -143,6 +203,50 @@ public class GeofenceRulePage extends GeoServerSecuredPage {
form.add(new BookmarkablePageLink<ShortRule>("cancel", GeofenceServerPage.class));
}
private String getAllowedAreaAsString(RuleLimits ruleLimits) {
if (ruleLimits == null || ruleLimits.getAllowedArea() == null) {
return "";
}
MultiPolygon multiPolygon = ruleLimits.getAllowedArea();
return "SRID=" + multiPolygon.getSRID() + ";" + multiPolygon.toText();
}
private MultiPolygon parseAllowedArea(String allowedArea) {
if (allowedArea == null || allowedArea.isEmpty()) {
return null;
}
String[] allowedAreaParts = allowedArea.split(";");
if (allowedAreaParts.length != 2) {
throw new GeoServerRuntimException(String.format(
"Invalid allowed area '%s' expecting SRID=<CODE>;<WKT>.", allowedArea));
}
Integer srid;
Geometry geometry;
try {
srid = Integer.valueOf(allowedAreaParts[0].split("=")[1]);
geometry = new WKTReader().read(allowedAreaParts[1]);
} catch (Exception exception) {
String message = String.format(
"Error parsing SRID '%s' or WKT geometry '%s' expecting SRID=<CODE>;<WKT>.",
allowedAreaParts[0], allowedAreaParts[1]);
LOGGER.log(Level.WARNING, message, exception);
throw new GeoServerRuntimException(message, exception);
}
MultiPolygon multiPolygon = castToMultiPolygon(geometry);
multiPolygon.setSRID(srid);
return multiPolygon;
}
private MultiPolygon castToMultiPolygon(Geometry geometry) {
if (geometry instanceof MultiPolygon) {
return (MultiPolygon) geometry;
}
if (geometry instanceof Polygon) {
return new MultiPolygon(new Polygon[]{(Polygon) geometry}, new GeometryFactory());
}
throw new GeoServerRuntimException(String.format(
"Invalid geometry of type '%s' expect a Polygon or MultiPolygon.", geometry.getClass().getSimpleName()));
}
/**
* Returns a sorted list of workspace names
......
......@@ -10,10 +10,12 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.vividsolutions.jts.geom.MultiPolygon;
import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.geoserver.geofence.core.model.Rule;
import org.geoserver.geofence.core.model.RuleLimits;
import org.geoserver.geofence.core.model.enums.GrantType;
import org.geoserver.geofence.services.RuleAdminService;
import org.geoserver.geofence.services.dto.ShortRule;
......@@ -204,7 +206,28 @@ public class GeofenceRulesModel extends GeoServerDataProvider<ShortRule> {
rule.setPriority(0);
return rule;
}
public void save(Long ruleId, MultiPolygon allowedArea) {
Rule rule = adminService().get(ruleId);
RuleLimits ruleLimits = rule.getRuleLimits();
if (ruleLimits == null) {
ruleLimits = new RuleLimits();
ruleLimits.setRule(rule);
}
ruleLimits.setAllowedArea(allowedArea);
adminService().setLimits(ruleId, ruleLimits);
}
public RuleLimits getRulesLimits(Long ruleId) {
if(ruleId != null) {
Rule rule = adminService().get(ruleId);
if(rule != null) {
return rule.getRuleLimits();
}
}
return null;
}
protected static void syncRule(ShortRule shortRule, Rule rule) {
rule.setPriority(shortRule.getPriority());
rule.setUsername(shortRule.getUserName());
......
......@@ -41,4 +41,5 @@ GeofenceRulePage.access.nullValid=*
GeofenceRulePage.ALLOW=ALLOW
GeofenceRulePage.DENY=DENY
GeofenceRulePage.LIMIT=LIMIT
GeofenceRulePage.duplicate=An identical rule is already present. Duplicates are not allowed.
\ No newline at end of file
GeofenceRulePage.duplicate=An identical rule is already present. Duplicates are not allowed.
GeofenceRulePage.allowedArea=Allowed area (WKT)
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment