You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2024/05/15 15:14:24 UTC
(syncope) 01/02: [SYNCOPE-1815] Further Macro improvements (#713)
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 58f9e1ae831a330096ff6eedd07bf7f0c04213dd
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Wed May 15 16:06:03 2024 +0200
[SYNCOPE-1815] Further Macro improvements (#713)
---
...IndicatorAjaxFormComponentUpdatingBehavior.java | 2 +-
.../markup/html/form/AjaxPasswordFieldPanel.java | 5 +
.../client/ui/commons/panels/SyncopeFormPanel.java | 102 ++++++++------
.../client/ui/commons/panels/SyncopeFormPanel.html | 2 +-
.../client/console/SyncopeConsoleSession.java | 2 +-
.../syncope/client/console/pages/Realms.java | 3 +-
.../console/tasks/FormPropertyDefsPanel.java | 148 ++++++++++++++++++---
.../console/tasks/MacroTaskDirectoryPanel.java | 2 +
.../console/wizards/any/ConsoleAuxClasses.java | 2 +-
.../client/console/wizards/any/Details.java | 18 +--
.../console/implementations/MyMacroActions.groovy | 18 ++-
.../console/tasks/FormPropertyDefsPanel.html | 18 +--
.../console/tasks/FormPropertyDefsPanel.properties | 8 +-
.../tasks/FormPropertyDefsPanel_fr_CA.properties | 8 +-
.../tasks/FormPropertyDefsPanel_it.properties | 8 +-
.../tasks/FormPropertyDefsPanel_ja.properties | 8 +-
.../tasks/FormPropertyDefsPanel_pt_BR.properties | 8 +-
.../tasks/FormPropertyDefsPanel_ru.properties | 8 +-
.../markup/html/form/ActionsPanel.properties | 6 +
.../markup/html/form/ActionsPanel_fr_CA.properties | 6 +
.../markup/html/form/ActionsPanel_it.properties | 6 +
.../markup/html/form/ActionsPanel_ja.properties | 6 +
.../markup/html/form/ActionsPanel_pt_BR.properties | 6 +
.../markup/html/form/ActionsPanel_ru.properties | 6 +
.../syncope/common/lib/form/FormProperty.java | 37 ++++++
.../syncope/common/lib/to/FormPropertyDefTO.java | 37 ++++++
.../org/apache/syncope/core/logic/TaskLogic.java | 3 +-
.../api/entity/task/FormPropertyDef.java | 13 ++
.../jpa/entity/task/JPAFormPropertyDef.java | 52 +++++++-
.../persistence/jpa/entity/task/JPAMacroTask.java | 9 +-
.../jpa/entity/task/JPAMacroTaskCommand.java | 6 +
.../neo4j/entity/task/Neo4jFormPropertyDef.java | 46 ++++++-
.../task/Neo4jFormPropertyDefRelationship.java | 102 ++++++++++++++
.../neo4j/entity/task/Neo4jMacroTask.java | 11 +-
.../core/provisioning/api/macro/MacroActions.java | 9 +-
.../java/data/ImplementationDataBinderImpl.java | 10 ++
.../provisioning/java/data/TaskDataBinderImpl.java | 15 ++-
.../provisioning/java/job/MacroJobDelegate.java | 137 +++++++++++--------
.../console/panels/UserRequestFormPanel.java | 4 +-
39 files changed, 728 insertions(+), 169 deletions(-)
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/ajax/form/IndicatorAjaxFormComponentUpdatingBehavior.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/ajax/form/IndicatorAjaxFormComponentUpdatingBehavior.java
index 93b58565d6..b38e1ea7f6 100644
--- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/ajax/form/IndicatorAjaxFormComponentUpdatingBehavior.java
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/ajax/form/IndicatorAjaxFormComponentUpdatingBehavior.java
@@ -23,7 +23,7 @@ import org.apache.wicket.ajax.IAjaxIndicatorAware;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
/**
- * An {@link AjaxFormComponentUpdatingBehavior} not showin veil.
+ * An {@link AjaxFormComponentUpdatingBehavior} not showing veil.
*/
public abstract class IndicatorAjaxFormComponentUpdatingBehavior
extends AjaxFormComponentUpdatingBehavior implements IAjaxIndicatorAware {
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java
index 6253f5f50a..da0a64337e 100644
--- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java
@@ -66,6 +66,11 @@ public class AjaxPasswordFieldPanel extends FieldPanel<String> {
}
}
+ public AjaxPasswordFieldPanel setResetPassword(final boolean resetPassword) {
+ ((PasswordTextField) field).setResetPassword(resetPassword);
+ return this;
+ }
+
@Override
public FieldPanel<String> addRequiredLabel() {
if (!isRequired()) {
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.java
index 2cfc3cb4fc..efc0e32371 100644
--- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.java
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.java
@@ -19,19 +19,24 @@
package org.apache.syncope.client.ui.commons.panels;
import java.text.ParseException;
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
+import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.syncope.client.ui.commons.MapChoiceRenderer;
+import org.apache.syncope.client.ui.commons.markup.html.form.AbstractFieldPanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDateTimeFieldPanel;
import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel;
import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPasswordFieldPanel;
import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel;
import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
-import org.apache.syncope.client.ui.commons.markup.html.form.FieldPanel;
import org.apache.syncope.common.lib.form.FormProperty;
import org.apache.syncope.common.lib.form.FormPropertyValue;
import org.apache.syncope.common.lib.form.SyncopeForm;
@@ -39,8 +44,9 @@ import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+import org.apache.wicket.validation.validator.PatternValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,47 +59,36 @@ public class SyncopeFormPanel<F extends SyncopeForm> extends Panel {
public SyncopeFormPanel(final String id, final F form) {
super(id);
- IModel<List<FormProperty>> formProps = new LoadableDetachableModel<>() {
+ ListModel<FormProperty> model = new ListModel<>(new ArrayList<>());
+ model.getObject().addAll(form.getProperties());
- private static final long serialVersionUID = 3169142472626817508L;
-
- @Override
- protected List<FormProperty> load() {
- return form.getProperties();
- }
- };
-
- ListView<FormProperty> propView = new ListView<>("propView", formProps) {
+ ListView<FormProperty> propView = new ListView<>("propView", model) {
private static final long serialVersionUID = 9101744072914090143L;
@Override
- @SuppressWarnings({ "unchecked", "rawtypes" })
protected void populateItem(final ListItem<FormProperty> item) {
FormProperty prop = item.getModelObject();
String label = StringUtils.isBlank(prop.getName()) ? prop.getId() : prop.getName();
- FieldPanel field;
+ AbstractFieldPanel<?> field;
switch (prop.getType()) {
case Boolean:
- field = new AjaxDropDownChoicePanel("value", label, new PropertyModel<String>(prop, "value") {
+ field = new AjaxCheckBoxPanel("value", label, new PropertyModel<Boolean>(prop, "value") {
private static final long serialVersionUID = -3743432456095828573L;
@Override
- public String getObject() {
- return StringUtils.isBlank(prop.getValue())
- ? null
- : prop.getValue().equals("true") ? "Yes" : "No";
+ public Boolean getObject() {
+ return BooleanUtils.toBoolean(prop.getValue());
}
@Override
- public void setObject(final String object) {
- prop.setValue(String.valueOf(object.equalsIgnoreCase("yes")));
+ public void setObject(final Boolean object) {
+ prop.setValue(BooleanUtils.toStringTrueFalse(object));
}
-
- }, false).setChoices(List.of("Yes", "No"));
+ }, false);
break;
case Date:
@@ -122,25 +117,56 @@ public class SyncopeFormPanel<F extends SyncopeForm> extends Panel {
break;
case Enum:
- field = new AjaxDropDownChoicePanel(
+ field = new AjaxDropDownChoicePanel<>(
"value", label, new PropertyModel<String>(prop, "value"), false).
setChoiceRenderer(new MapChoiceRenderer(prop.getEnumValues().stream().
collect(Collectors.toMap(
FormPropertyValue::getKey,
FormPropertyValue::getValue)))).
- setChoices(prop.getEnumValues().stream().
- map(FormPropertyValue::getKey).collect(Collectors.toList()));
+ setChoices(prop.getEnumValues().stream().map(FormPropertyValue::getKey).toList());
break;
case Dropdown:
- field = new AjaxDropDownChoicePanel(
- "value", label, new PropertyModel<String>(prop, "value"), false).
- setChoiceRenderer(new MapChoiceRenderer(prop.getDropdownValues().stream().
- collect(Collectors.toMap(
- FormPropertyValue::getKey,
- FormPropertyValue::getValue)))).
- setChoices(prop.getDropdownValues().stream().
- map(FormPropertyValue::getKey).collect(Collectors.toList()));
+ if (prop.isDropdownFreeForm()) {
+ field = new AjaxTextFieldPanel("value", label, new PropertyModel<>(prop, "value"), false);
+ ((AjaxTextFieldPanel) field).setChoices(prop.getDropdownValues().stream().
+ map(FormPropertyValue::getKey).toList());
+ } else if (prop.isDropdownSingleSelection()) {
+ field = new AjaxDropDownChoicePanel<>(
+ "value", label, new PropertyModel<String>(prop, "value"), false).
+ setChoiceRenderer(new MapChoiceRenderer(prop.getDropdownValues().stream().
+ collect(Collectors.toMap(
+ FormPropertyValue::getKey,
+ FormPropertyValue::getValue)))).
+ setChoices(prop.getDropdownValues().stream().
+ map(FormPropertyValue::getKey).toList());
+ } else {
+ field = new AjaxPalettePanel.Builder<String>().setName(label).
+ setRenderer(new MapChoiceRenderer(prop.getDropdownValues().stream().
+ collect(Collectors.toMap(
+ FormPropertyValue::getKey,
+ FormPropertyValue::getValue)))).build(
+ "value",
+ new IModel<List<String>>() {
+
+ private static final long serialVersionUID = 1015030402166681242L;
+
+ @Override
+ public List<String> getObject() {
+ return Optional.ofNullable(prop.getValue()).
+ map(v -> List.of(v.split(";"))).
+ orElse(null);
+ }
+
+ @Override
+ public void setObject(final List<String> object) {
+ prop.setValue(Optional.ofNullable(object).
+ map(v -> v.stream().collect(Collectors.joining(";"))).
+ orElse(null));
+ }
+ }, new ListModel<>(prop.getDropdownValues().stream().
+ map(FormPropertyValue::getKey).toList()));
+ }
break;
case Long:
@@ -167,12 +193,15 @@ public class SyncopeFormPanel<F extends SyncopeForm> extends Panel {
break;
case Password:
- field = new AjaxPasswordFieldPanel("value", label, new PropertyModel<>(prop, "value"), false);
+ field = new AjaxPasswordFieldPanel("value", label, new PropertyModel<>(prop, "value"), false).
+ setResetPassword(false);
break;
case String:
default:
field = new AjaxTextFieldPanel("value", label, new PropertyModel<>(prop, "value"), false);
+ Optional.ofNullable(prop.getStringRegEx()).
+ ifPresent(re -> ((AjaxTextFieldPanel) field).addValidator(new PatternValidator(re)));
break;
}
@@ -184,7 +213,6 @@ public class SyncopeFormPanel<F extends SyncopeForm> extends Panel {
item.add(field);
}
};
-
- add(propView);
+ add(propView.setReuseItems(true));
}
}
diff --git a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.html b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.html
index 127037bc48..6271a58363 100644
--- a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.html
+++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.html
@@ -22,6 +22,6 @@ under the License.
<span wicket:id="value">[value]</span>
</div>
- <wicket:child/>
+ <wicket:child/>
</wicket:panel>
</html>
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
index 153a4d4118..543089041b 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
@@ -162,7 +162,7 @@ public class SyncopeConsoleSession extends AuthenticatedWebSession implements Ba
message = getApplication().getResourceSettings().getLocalizer().
getString(message, null, null, null, null, message);
- error(message);
+ error(message.replace("\n", "<br/>"));
}
public MediaType getMediaType() {
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
index 47ebc8bea4..8f52b00750 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
@@ -257,8 +257,7 @@ public class Realms extends BasePage {
target.add(content);
} catch (Exception e) {
LOG.error("While deleting realm", e);
- // Escape line breaks
- SyncopeConsoleSession.get().error(e.getMessage().replace("\n", " "));
+ SyncopeConsoleSession.get().onException(e);
}
((BaseWebPage) Realms.this.getPage()).getNotificationPanel().refresh(target);
}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.java
index 3d6210f97f..8b59be9fb3 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.java
@@ -21,6 +21,9 @@ package org.apache.syncope.client.console.tasks;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.panels.AbstractModalPanel;
@@ -49,6 +52,9 @@ import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.util.ListModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.apache.wicket.validation.IValidatable;
+import org.apache.wicket.validation.IValidator;
+import org.apache.wicket.validation.ValidationError;
public class FormPropertyDefsPanel extends AbstractModalPanel<MacroTaskTO> {
@@ -70,8 +76,7 @@ public class FormPropertyDefsPanel extends AbstractModalPanel<MacroTaskTO> {
this.task = task;
WebMarkupContainer propertyDefContainer = new WebMarkupContainer("propertyDefContainer");
- propertyDefContainer.setOutputMarkupId(true);
- add(propertyDefContainer);
+ add(propertyDefContainer.setOutputMarkupId(true));
model = new ListModel<>(new ArrayList<>());
model.getObject().addAll(task.getFormPropertyDefs());
@@ -127,20 +132,69 @@ public class FormPropertyDefsPanel extends AbstractModalPanel<MacroTaskTO> {
type.setChoices(List.of(FormPropertyType.values())).setNullValid(false);
item.add(type.setRequired(true).hideLabel());
+ AjaxTextFieldPanel stringRegEx = new AjaxTextFieldPanel(
+ "stringRegEx",
+ "stringRegEx",
+ new IModel<String>() {
+
+ private static final long serialVersionUID = 1015030402166681242L;
+
+ @Override
+ public String getObject() {
+ return Optional.ofNullable(fpd.getStringRegEx()).map(Pattern::pattern).orElse(null);
+ }
+
+ @Override
+ public void setObject(final String object) {
+ fpd.setStringRegEx(Optional.ofNullable(object).map(Pattern::compile).orElse(null));
+ }
+ }, true);
+ stringRegEx.getField().add(new IValidator<String>() {
+
+ private static final long serialVersionUID = 3978328825079032964L;
+
+ @Override
+ public void validate(final IValidatable<String> validatable) {
+ try {
+ Pattern.compile(validatable.getValue());
+ } catch (PatternSyntaxException e) {
+ validatable.error(new ValidationError(fpd.getKey() + ": invalid RegEx"));
+ }
+ }
+ });
+ stringRegEx.setVisible(fpd.getType() == FormPropertyType.String);
+ item.add(stringRegEx.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
+
AjaxTextFieldPanel datePattern = new AjaxTextFieldPanel(
"datePattern",
"datePattern",
new PropertyModel<>(fpd, "datePattern"),
true);
- datePattern.setEnabled(fpd.getType() == FormPropertyType.Date);
- item.add(datePattern.hideLabel().setOutputMarkupId(true));
+ datePattern.setVisible(fpd.getType() == FormPropertyType.Date);
+ item.add(datePattern.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
AjaxGridFieldPanel<String, String> enumValues = new AjaxGridFieldPanel<>(
"enumValues",
"enumValues",
new PropertyModel<>(fpd, "enumValues"));
- enumValues.setEnabled(fpd.getType() == FormPropertyType.Enum);
- item.add(enumValues.hideLabel().setOutputMarkupId(true));
+ enumValues.setVisible(fpd.getType() == FormPropertyType.Enum);
+ item.add(enumValues.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
+
+ WebMarkupContainer dropdownConf = new WebMarkupContainer("dropdownConf");
+ dropdownConf.setVisible(fpd.getType() == FormPropertyType.Dropdown);
+ item.add(dropdownConf.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
+ AjaxCheckBoxPanel dropdownSingleSelection = new AjaxCheckBoxPanel(
+ "dropdownSingleSelection",
+ "dropdownSingleSelection",
+ new PropertyModel<>(fpd, "dropdownSingleSelection"),
+ true);
+ dropdownConf.add(dropdownSingleSelection.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
+ AjaxCheckBoxPanel dropdownFreeForm = new AjaxCheckBoxPanel(
+ "dropdownFreeForm",
+ "dropdownFreeForm",
+ new PropertyModel<>(fpd, "dropdownFreeForm"),
+ true);
+ dropdownConf.add(dropdownFreeForm.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
type.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
@@ -149,30 +203,59 @@ public class FormPropertyDefsPanel extends AbstractModalPanel<MacroTaskTO> {
@Override
protected void onUpdate(final AjaxRequestTarget target) {
switch (type.getModelObject()) {
+ case String -> {
+ stringRegEx.setVisible(true);
+ datePattern.setVisible(false);
+ enumValues.setVisible(false);
+ fpd.getEnumValues().clear();
+ dropdownConf.setVisible(false);
+ }
+
case Date -> {
- datePattern.setEnabled(true);
- enumValues.setEnabled(false);
+ stringRegEx.setVisible(false);
+ fpd.setStringRegEx(null);
+ datePattern.setVisible(true);
+ enumValues.setVisible(false);
fpd.getEnumValues().clear();
+ dropdownConf.setVisible(false);
}
case Enum -> {
- datePattern.setEnabled(false);
- enumValues.setEnabled(true);
+ stringRegEx.setVisible(false);
+ fpd.setStringRegEx(null);
+ datePattern.setVisible(false);
+ enumValues.setVisible(true);
+ dropdownConf.setVisible(false);
+ }
+
+ case Dropdown -> {
+ stringRegEx.setVisible(false);
+ fpd.setStringRegEx(null);
+ datePattern.setVisible(false);
+ enumValues.setVisible(false);
+ fpd.getEnumValues().clear();
+ dropdownConf.setVisible(true);
}
default -> {
- datePattern.setEnabled(false);
- enumValues.setEnabled(false);
+ stringRegEx.setVisible(false);
+ fpd.setStringRegEx(null);
+ datePattern.setVisible(false);
+ enumValues.setVisible(false);
fpd.getEnumValues().clear();
+ dropdownConf.setVisible(false);
}
}
+ target.add(stringRegEx);
target.add(datePattern);
target.add(enumValues);
+ target.add(dropdownConf);
}
});
- ActionsPanel<Serializable> actions = new ActionsPanel<>("toRemove", null);
+ ActionsPanel<Serializable> actions = new ActionsPanel<>("actions", null);
+ item.add(actions);
actions.add(new ActionLink<>() {
private static final long serialVersionUID = -3722207913631435501L;
@@ -180,15 +263,48 @@ public class FormPropertyDefsPanel extends AbstractModalPanel<MacroTaskTO> {
@Override
public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
model.getObject().remove(item.getIndex());
+
item.getParent().removeAll();
target.add(propertyDefContainer);
}
}, ActionLink.ActionType.DELETE, StringUtils.EMPTY, true).hideLabel();
- item.add(actions);
+ if (model.getObject().size() > 1) {
+ if (item.getIndex() > 0) {
+ actions.add(new ActionLink<>() {
+
+ private static final long serialVersionUID = 2041211756396714619L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+ FormPropertyDefTO pre = model.getObject().get(item.getIndex() - 1);
+ model.getObject().set(item.getIndex(), pre);
+ model.getObject().set(item.getIndex() - 1, fpd);
+
+ item.getParent().removeAll();
+ target.add(propertyDefContainer);
+ }
+ }, ActionLink.ActionType.UP, StringUtils.EMPTY).hideLabel();
+ }
+ if (item.getIndex() < model.getObject().size() - 1) {
+ actions.add(new ActionLink<>() {
+
+ private static final long serialVersionUID = 2041211756396714619L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+ FormPropertyDefTO post = model.getObject().get(item.getIndex() + 1);
+ model.getObject().set(item.getIndex(), post);
+ model.getObject().set(item.getIndex() + 1, fpd);
+
+ item.getParent().removeAll();
+ target.add(propertyDefContainer);
+ }
+ }, ActionLink.ActionType.DOWN, StringUtils.EMPTY).hideLabel();
+ }
+ }
}
};
- propertyDefs.setReuseItems(true);
- propertyDefContainer.add(propertyDefs);
+ propertyDefContainer.add(propertyDefs.setReuseItems(true));
IndicatingAjaxButton addPropertyDef = new IndicatingAjaxButton("addPropertyDef") {
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/MacroTaskDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/MacroTaskDirectoryPanel.java
index 345fda7a3b..31cd627472 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/MacroTaskDirectoryPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/MacroTaskDirectoryPanel.java
@@ -138,6 +138,7 @@ public class MacroTaskDirectoryPanel extends SchedTaskDirectoryPanel<MacroTaskTO
@Override
public void onClick(final AjaxRequestTarget target, final MacroTaskTO ignore) {
+ model.setObject(restClient.readTask(TaskType.MACRO, model.getObject().getKey()));
MacroTaskExecWizardBuilder wb = new MacroTaskExecWizardBuilder(model.getObject(), restClient, pageRef);
wb.setEventSink(new ExecModalEventSink());
@@ -164,6 +165,7 @@ public class MacroTaskDirectoryPanel extends SchedTaskDirectoryPanel<MacroTaskTO
@Override
public void onClick(final AjaxRequestTarget target, final MacroTaskTO ignore) {
+ model.setObject(restClient.readTask(TaskType.MACRO, model.getObject().getKey()));
target.add(modal.setContent(new CommandComposeDirectoryPanel(
model.getObject().getKey(), commandRestClient, modal, pageRef)));
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConsoleAuxClasses.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConsoleAuxClasses.java
index 0fb1f700a0..bdb8a6168f 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConsoleAuxClasses.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConsoleAuxClasses.java
@@ -38,7 +38,7 @@ public class ConsoleAuxClasses extends AbstractAuxClasses {
}
@Override
- protected final List<AnyTypeClassTO> listAnyTypecClasses() {
+ protected List<AnyTypeClassTO> listAnyTypecClasses() {
return anyTypeClassRestClient.list();
}
}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
index 735fb6d73d..096e813744 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
@@ -45,9 +45,17 @@ import org.slf4j.LoggerFactory;
public class Details<T extends AnyTO> extends WizardStep {
+ private static final long serialVersionUID = -8995647450549098844L;
+
protected static final Logger LOG = LoggerFactory.getLogger(Details.class);
- private static final long serialVersionUID = -8995647450549098844L;
+ protected static List<RealmTO> getRealmsFromLinks(final List<AbstractLink> realmLinks) {
+ return realmLinks.stream().
+ map(Component::getDefaultModelObject).
+ filter(RealmTO.class::isInstance).
+ map(RealmTO.class::cast).
+ toList();
+ }
@SpringBean
protected RealmRestClient realmRestClient;
@@ -113,12 +121,4 @@ public class Details<T extends AnyTO> extends WizardStep {
protected AnnotatedBeanPanel getGeneralStatusInformation(final String id, final T anyTO) {
return new AnnotatedBeanPanel(id, anyTO);
}
-
- private static List<RealmTO> getRealmsFromLinks(final List<AbstractLink> realmLinks) {
- return realmLinks.stream().
- map(Component::getDefaultModelObject).
- filter(RealmTO.class::isInstance).
- map(RealmTO.class::cast).
- collect(Collectors.toList());
- }
}
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/implementations/MyMacroActions.groovy b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/implementations/MyMacroActions.groovy
index c920b030a7..354fa91ea2 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/implementations/MyMacroActions.groovy
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/implementations/MyMacroActions.groovy
@@ -18,9 +18,10 @@
*/
import groovy.transform.CompileStatic
import java.util.Map
-import javax.xml.bind.ValidationException
+import java.util.Optional
+import javax.validation.ValidationException
import org.apache.syncope.common.lib.command.CommandArgs
-import org.apache.syncope.common.lib.form.MacroTaskForm
+import org.apache.syncope.common.lib.form.SyncopeForm
import org.apache.syncope.core.provisioning.api.macro.Command
import org.apache.syncope.core.provisioning.api.macro.MacroActions
@@ -28,14 +29,19 @@ import org.apache.syncope.core.provisioning.api.macro.MacroActions
class MyMacroActions implements MacroActions {
@Override
- void validate(MacroTaskForm macroTaskForm) throws ValidationException {
+ Optional<String> getDefaultValue(String formProperty) {
+ return Optional.empty();
}
-
+
@Override
Map<String, String> getDropdownValues(String formProperty) {
- return Map.of();
+ return Map.of()
}
+ @Override
+ void validate(SyncopeForm form, Map<String, Object> vars) throws ValidationException {
+ }
+
@Override
void beforeAll() {
}
@@ -50,6 +56,6 @@ class MyMacroActions implements MacroActions {
@Override
StringBuilder afterAll(StringBuilder output) {
- return output;
+ return output
}
}
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.html
index f40c2b55d7..933b16e786 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.html
@@ -27,12 +27,11 @@ under the License.
<tr>
<th><wicket:message key="key"/></th>
<th><wicket:message key="name"/></th>
- <th><wicket:message key="type"/></th>
<th><wicket:message key="readable"/></th>
<th><wicket:message key="writable"/></th>
<th><wicket:message key="required"/></th>
- <th><wicket:message key="datePattern"/></th>
- <th><wicket:message key="enumValues"/></th>
+ <th><wicket:message key="type"/></th>
+ <th><wicket:message key="conf"/></th>
<th></th>
</tr>
@@ -43,9 +42,6 @@ under the License.
<td>
<span wicket:id="name"/>
</td>
- <td>
- <span wicket:id="type"/>
- </td>
<td>
<span wicket:id="readable"/>
</td>
@@ -56,14 +52,20 @@ under the License.
<span wicket:id="required"/>
</td>
<td>
- <span wicket:id="datePattern"/>
+ <span wicket:id="type"/>
</td>
<td>
+ <span wicket:id="stringRegEx"/>
+ <span wicket:id="datePattern"/>
<span wicket:id="enumValues"/>
+ <div wicket:id="dropdownConf">
+ <span wicket:id="dropdownSingleSelection"/>
+ <span wicket:id="dropdownFreeForm"/>
+ </div>
</td>
<td>
<div id="inline-actions">
- <span wicket:id="toRemove"/>
+ <span wicket:id="actions"/>
</div>
</td>
</tr>
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.properties
index 8ba3a3a829..5831fc80ca 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel.properties
@@ -18,5 +18,9 @@ type=Type
readable=Readable
writable=Writable
required=Required
-datePattern=Date pattern
-enumValues=Enum values
+conf=Configuration
+stringRegEx=Regular Expression
+enumValues=Values
+datePattern=Pattern
+dropdownSingleSelection=Single Selection
+dropdownFreeForm=Free Form
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_fr_CA.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_fr_CA.properties
index 8ba3a3a829..5831fc80ca 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_fr_CA.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_fr_CA.properties
@@ -18,5 +18,9 @@ type=Type
readable=Readable
writable=Writable
required=Required
-datePattern=Date pattern
-enumValues=Enum values
+conf=Configuration
+stringRegEx=Regular Expression
+enumValues=Values
+datePattern=Pattern
+dropdownSingleSelection=Single Selection
+dropdownFreeForm=Free Form
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_it.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_it.properties
index 62a3a2d422..5cd41d2b8b 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_it.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_it.properties
@@ -18,5 +18,9 @@ type=Tipo
readable=Lettura
writable=Scrittura
required=Obbligatorio
-datePattern=Modello data
-enumValues=Valori enum
+conf=Configurazione
+stringRegEx=Espressione Regolare
+enumValues=Valori
+datePattern=Modello
+dropdownSingleSelection=Selezione Singola
+dropdownFreeForm=Modalit\u00e0 libera
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_ja.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_ja.properties
index 8ba3a3a829..5831fc80ca 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_ja.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_ja.properties
@@ -18,5 +18,9 @@ type=Type
readable=Readable
writable=Writable
required=Required
-datePattern=Date pattern
-enumValues=Enum values
+conf=Configuration
+stringRegEx=Regular Expression
+enumValues=Values
+datePattern=Pattern
+dropdownSingleSelection=Single Selection
+dropdownFreeForm=Free Form
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_pt_BR.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_pt_BR.properties
index 8ba3a3a829..5831fc80ca 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_pt_BR.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_pt_BR.properties
@@ -18,5 +18,9 @@ type=Type
readable=Readable
writable=Writable
required=Required
-datePattern=Date pattern
-enumValues=Enum values
+conf=Configuration
+stringRegEx=Regular Expression
+enumValues=Values
+datePattern=Pattern
+dropdownSingleSelection=Single Selection
+dropdownFreeForm=Free Form
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_ru.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_ru.properties
index 8ba3a3a829..5831fc80ca 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_ru.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/tasks/FormPropertyDefsPanel_ru.properties
@@ -18,5 +18,9 @@ type=Type
readable=Readable
writable=Writable
required=Required
-datePattern=Date pattern
-enumValues=Enum values
+conf=Configuration
+stringRegEx=Regular Expression
+enumValues=Values
+datePattern=Pattern
+dropdownSingleSelection=Single Selection
+dropdownFreeForm=Free Form
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties
index 0e53e9e9f2..b8d5d685ee 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel.properties
@@ -276,3 +276,9 @@ merge_accounts.alt=merge accounts icon
explore_resource.class=fa fa-eye
explore_resource.title=explore resource
explore_resource.alt=explore resource icon
+up.alt=up icon
+up.class=fas fa-arrow-up
+up.title=move up
+down.alt=down icon
+down.class=fas fa-arrow-down
+down.title=move down
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_fr_CA.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_fr_CA.properties
index 48d13be1b2..b42f43a855 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_fr_CA.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_fr_CA.properties
@@ -221,3 +221,9 @@ merge_accounts.alt=merge accounts icon
explore_resource.class=fa fa-eye
explore_resource.title=explorer la ressource
explore_resource.alt=ic\u00f4ne explorer la ressource
+up.alt=up icon
+up.class=fas fa-arrow-up
+up.title=move up
+down.alt=down icon
+down.class=fas fa-arrow-down
+down.title=move down
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties
index dbbab266f3..e5d20e0446 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_it.properties
@@ -276,3 +276,9 @@ merge_accounts.alt=merge accounts icon
explore_resource.class=fa fa-eye
explore_resource.title=esplora risorsa
explore_resource.alt=explore resource icon
+up.alt=up icon
+up.class=fas fa-arrow-up
+up.title=sposta su
+down.alt=down icon
+down.class=fas fa-arrow-down
+down.title=sposta gi\u00f9
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties
index 12f5a73617..1a97e92fb5 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ja.properties
@@ -277,3 +277,9 @@ merge_accounts.alt=merge accounts icon
explore_resource.class=fa fa-eye
explore_resource.title=\u30ea\u30bd\u30fc\u30b9\u3092\u63a2\u7d22\u3059\u308b
explore_resource.alt=\u30ea\u30bd\u30fc\u30b9\u30a2\u30a4\u30b3\u30f3\u3092\u63a2\u3059
+up.alt=up icon
+up.class=fas fa-arrow-up
+up.title=move up
+down.alt=down icon
+down.class=fas fa-arrow-down
+down.title=move down
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties
index 368df37cc3..dbb9c181a4 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_pt_BR.properties
@@ -281,3 +281,9 @@ merge_accounts.alt=merge accounts icon
explore_resource.class=fa fa-eye
explore_resource.title=explorar recurso
explore_resource.alt=\u00edcone de explorar recurso
+up.alt=up icon
+up.class=fas fa-arrow-up
+up.title=move up
+down.alt=down icon
+down.class=fas fa-arrow-down
+down.title=move down
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties
index 822849583a..7277a38550 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionsPanel_ru.properties
@@ -277,3 +277,9 @@ merge_accounts.alt=merge accounts icon
explore_resource.class=fa fa-eye
explore_resource.title=\u0438\u0437\u0443\u0447\u0438\u0442\u044c\u0020\u0440\u0435\u0441\u0443\u0440\u0441
explore_resource.alt=\u0438\u0437\u0443\u0447\u0438\u0442\u044c\u0020\u0437\u043d\u0430\u0447\u043e\u043a\u0020\u0440\u0435\u0441\u0443\u0440\u0441\u0430
+up.alt=up icon
+up.class=fas fa-arrow-up
+up.title=move up
+down.alt=down icon
+down.class=fas fa-arrow-down
+down.title=move down
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/form/FormProperty.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/form/FormProperty.java
index 471f072870..dbf8745ef9 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/form/FormProperty.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/form/FormProperty.java
@@ -23,6 +23,7 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
+import java.util.regex.Pattern;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -42,12 +43,18 @@ public class FormProperty implements Serializable {
private boolean required;
+ private Pattern stringRegEx;
+
private String datePattern;
private final List<FormPropertyValue> enumValues = new ArrayList<>();
private final List<FormPropertyValue> dropdownValues = new ArrayList<>();
+ private boolean dropdownSingleSelection = true;
+
+ private boolean dropdownFreeForm;
+
private String value;
public String getId() {
@@ -82,6 +89,14 @@ public class FormProperty implements Serializable {
this.required = required;
}
+ public Pattern getStringRegEx() {
+ return stringRegEx;
+ }
+
+ public void setStringRegEx(final Pattern stringRegEx) {
+ this.stringRegEx = stringRegEx;
+ }
+
public FormPropertyType getType() {
return type;
}
@@ -118,6 +133,22 @@ public class FormProperty implements Serializable {
return dropdownValues;
}
+ public boolean isDropdownSingleSelection() {
+ return dropdownSingleSelection;
+ }
+
+ public void setDropdownSingleSelection(final boolean dropdownSingleSelection) {
+ this.dropdownSingleSelection = dropdownSingleSelection;
+ }
+
+ public boolean isDropdownFreeForm() {
+ return dropdownFreeForm;
+ }
+
+ public void setDropdownFreeForm(final boolean dropdownFreeForm) {
+ this.dropdownFreeForm = dropdownFreeForm;
+ }
+
public String getValue() {
return value;
}
@@ -135,9 +166,12 @@ public class FormProperty implements Serializable {
append(readable).
append(writable).
append(required).
+ append(stringRegEx).
append(datePattern).
append(enumValues).
append(dropdownValues).
+ append(dropdownSingleSelection).
+ append(dropdownFreeForm).
append(value).
build();
}
@@ -161,9 +195,12 @@ public class FormProperty implements Serializable {
append(readable, other.readable).
append(writable, other.writable).
append(required, other.required).
+ append(stringRegEx, other.stringRegEx).
append(datePattern, other.datePattern).
append(enumValues, other.enumValues).
append(dropdownValues, other.dropdownValues).
+ append(dropdownSingleSelection, other.dropdownSingleSelection).
+ append(dropdownFreeForm, other.dropdownFreeForm).
append(value, other.value).
build();
}
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/FormPropertyDefTO.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/FormPropertyDefTO.java
index 5357b1df39..4f1d24aba5 100644
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/FormPropertyDefTO.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/FormPropertyDefTO.java
@@ -20,6 +20,7 @@ package org.apache.syncope.common.lib.to;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.regex.Pattern;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.syncope.common.lib.form.FormPropertyType;
@@ -40,10 +41,16 @@ public class FormPropertyDefTO implements NamedEntityTO {
private boolean required;
+ private Pattern stringRegEx;
+
private String datePattern;
private final Map<String, String> enumValues = new LinkedHashMap<>();
+ private boolean dropdownSingleSelection = true;
+
+ private boolean dropdownFreeForm;
+
@Override
public String getKey() {
return key;
@@ -96,6 +103,14 @@ public class FormPropertyDefTO implements NamedEntityTO {
this.required = required;
}
+ public Pattern getStringRegEx() {
+ return stringRegEx;
+ }
+
+ public void setStringRegEx(final Pattern stringRegEx) {
+ this.stringRegEx = stringRegEx;
+ }
+
public String getDatePattern() {
return datePattern;
}
@@ -108,6 +123,22 @@ public class FormPropertyDefTO implements NamedEntityTO {
return enumValues;
}
+ public boolean isDropdownSingleSelection() {
+ return dropdownSingleSelection;
+ }
+
+ public void setDropdownSingleSelection(final boolean dropdownSingleSelection) {
+ this.dropdownSingleSelection = dropdownSingleSelection;
+ }
+
+ public boolean isDropdownFreeForm() {
+ return dropdownFreeForm;
+ }
+
+ public void setDropdownFreeForm(final boolean dropdownFreeForm) {
+ this.dropdownFreeForm = dropdownFreeForm;
+ }
+
@Override
public int hashCode() {
return new HashCodeBuilder().
@@ -117,8 +148,11 @@ public class FormPropertyDefTO implements NamedEntityTO {
append(readable).
append(writable).
append(required).
+ append(stringRegEx).
append(datePattern).
append(enumValues).
+ append(dropdownSingleSelection).
+ append(dropdownFreeForm).
build();
}
@@ -141,8 +175,11 @@ public class FormPropertyDefTO implements NamedEntityTO {
append(readable, other.readable).
append(writable, other.writable).
append(required, other.required).
+ append(stringRegEx, other.stringRegEx).
append(datePattern, other.datePattern).
append(enumValues, other.enumValues).
+ append(dropdownSingleSelection, other.dropdownSingleSelection).
+ append(dropdownFreeForm, other.dropdownFreeForm).
build();
}
}
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
index 3030630e14..99c57b1a19 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
@@ -420,7 +420,8 @@ public class TaskLogic extends AbstractExecutableLogic<TaskTO> {
if (TaskType.SCHEDULED == taskUtils.getType()
|| TaskType.PULL == taskUtils.getType()
- || TaskType.PUSH == taskUtils.getType()) {
+ || TaskType.PUSH == taskUtils.getType()
+ || TaskType.MACRO == taskUtils.getType()) {
jobManager.unregister(task);
}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/FormPropertyDef.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/FormPropertyDef.java
index dbfcadd620..518ab750d7 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/FormPropertyDef.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/task/FormPropertyDef.java
@@ -19,6 +19,7 @@
package org.apache.syncope.core.persistence.api.entity.task;
import java.util.Map;
+import java.util.regex.Pattern;
import org.apache.syncope.common.lib.form.FormPropertyType;
import org.apache.syncope.core.persistence.api.entity.ProvidedKeyEntity;
@@ -48,6 +49,10 @@ public interface FormPropertyDef extends ProvidedKeyEntity {
void setRequired(boolean required);
+ Pattern getStringRegEx();
+
+ void setStringRegExp(Pattern stringRegEx);
+
String getDatePattern();
void setDatePattern(String datePattern);
@@ -55,4 +60,12 @@ public interface FormPropertyDef extends ProvidedKeyEntity {
Map<String, String> getEnumValues();
void setEnumValues(Map<String, String> enumValues);
+
+ boolean isDropdownSingleSelection();
+
+ void setDropdownSingleSelection(boolean dropdownSingleSelection);
+
+ boolean isDropdownFreeForm();
+
+ void setDropdownFreeForm(boolean dropdownFreeForm);
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAFormPropertyDef.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAFormPropertyDef.java
index 0d86db3fa7..f877ddacee 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAFormPropertyDef.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAFormPropertyDef.java
@@ -28,6 +28,7 @@ import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import java.util.Map;
import java.util.Optional;
+import java.util.regex.Pattern;
import org.apache.syncope.common.lib.form.FormPropertyType;
import org.apache.syncope.core.persistence.api.entity.task.FormPropertyDef;
import org.apache.syncope.core.persistence.api.entity.task.MacroTask;
@@ -44,6 +45,11 @@ public class JPAFormPropertyDef extends AbstractProvidedKeyEntity implements For
public static final String TABLE = "FormPropertyDef";
+ protected static final TypeReference<Map<String, String>> TYPEREF = new TypeReference<Map<String, String>>() {
+ };
+
+ private int idx;
+
@ManyToOne(optional = false)
private JPAMacroTask macroTask;
@@ -63,11 +69,23 @@ public class JPAFormPropertyDef extends AbstractProvidedKeyEntity implements For
@NotNull
private Boolean required = Boolean.FALSE;
+ private String stringRegEx;
+
private String datePattern;
@Lob
private String enumValues;
+ @NotNull
+ private Boolean dropdownSingleSelection = Boolean.TRUE;
+
+ @NotNull
+ private Boolean dropdownFreeForm = Boolean.FALSE;
+
+ public void setIdx(final int idx) {
+ this.idx = idx;
+ }
+
@Override
public JPAMacroTask getMacroTask() {
return macroTask;
@@ -129,6 +147,16 @@ public class JPAFormPropertyDef extends AbstractProvidedKeyEntity implements For
this.required = required;
}
+ @Override
+ public Pattern getStringRegEx() {
+ return Optional.ofNullable(stringRegEx).map(Pattern::compile).orElse(null);
+ }
+
+ @Override
+ public void setStringRegExp(final Pattern stringRegEx) {
+ this.stringRegEx = Optional.ofNullable(stringRegEx).map(Pattern::pattern).orElse(null);
+ }
+
@Override
public String getDatePattern() {
return datePattern;
@@ -141,13 +169,31 @@ public class JPAFormPropertyDef extends AbstractProvidedKeyEntity implements For
@Override
public Map<String, String> getEnumValues() {
- return Optional.ofNullable(enumValues).
- map(v -> POJOHelper.deserialize(v, new TypeReference<Map<String, String>>() {
- })).orElse(Map.of());
+ return Optional.ofNullable(enumValues).map(v -> POJOHelper.deserialize(v, TYPEREF)).orElse(Map.of());
}
@Override
public void setEnumValues(final Map<String, String> enumValues) {
this.enumValues = Optional.ofNullable(enumValues).map(POJOHelper::serialize).orElse(null);
}
+
+ @Override
+ public boolean isDropdownSingleSelection() {
+ return dropdownSingleSelection == null ? false : dropdownSingleSelection;
+ }
+
+ @Override
+ public void setDropdownSingleSelection(final boolean dropdownSingleSelection) {
+ this.dropdownSingleSelection = dropdownSingleSelection;
+ }
+
+ @Override
+ public boolean isDropdownFreeForm() {
+ return dropdownFreeForm == null ? false : dropdownFreeForm;
+ }
+
+ @Override
+ public void setDropdownFreeForm(final boolean dropdownFreeForm) {
+ this.dropdownFreeForm = dropdownFreeForm;
+ }
}
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAMacroTask.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAMacroTask.java
index 8660cd8e3a..64725466b5 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAMacroTask.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAMacroTask.java
@@ -23,6 +23,7 @@ import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
+import jakarta.persistence.OrderBy;
import jakarta.persistence.Table;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
@@ -57,9 +58,11 @@ public class JPAMacroTask extends JPASchedTask implements MacroTask {
private Boolean saveExecs = true;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "macroTask")
+ @OrderBy("idx")
private List<JPAMacroTaskCommand> macroTaskCommands = new ArrayList<>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "macroTask")
+ @OrderBy("idx")
@Valid
private List<JPAFormPropertyDef> formPropertyDefs = new ArrayList<>();
@@ -114,7 +117,8 @@ public class JPAMacroTask extends JPASchedTask implements MacroTask {
@Override
public void add(final MacroTaskCommand macroTaskCommand) {
checkType(macroTaskCommand, JPAMacroTaskCommand.class);
- this.macroTaskCommands.add((JPAMacroTaskCommand) macroTaskCommand);
+ ((JPAMacroTaskCommand) macroTaskCommand).setIdx(macroTaskCommands.size());
+ macroTaskCommands.add((JPAMacroTaskCommand) macroTaskCommand);
}
@Override
@@ -125,7 +129,8 @@ public class JPAMacroTask extends JPASchedTask implements MacroTask {
@Override
public void add(final FormPropertyDef formPropertyDef) {
checkType(formPropertyDef, JPAFormPropertyDef.class);
- this.formPropertyDefs.add((JPAFormPropertyDef) formPropertyDef);
+ ((JPAFormPropertyDef) formPropertyDef).setIdx(formPropertyDefs.size());
+ formPropertyDefs.add((JPAFormPropertyDef) formPropertyDef);
}
@Override
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAMacroTaskCommand.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAMacroTaskCommand.java
index df3bea0465..86ca5037c1 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAMacroTaskCommand.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/task/JPAMacroTaskCommand.java
@@ -41,6 +41,8 @@ public class JPAMacroTaskCommand extends AbstractGeneratedKeyEntity implements M
public static final String TABLE = "MacroTaskCommand";
+ private int idx;
+
@ManyToOne(optional = false)
private JPAMacroTask macroTask;
@@ -50,6 +52,10 @@ public class JPAMacroTaskCommand extends AbstractGeneratedKeyEntity implements M
@Lob
private String args;
+ public void setIdx(final int idx) {
+ this.idx = idx;
+ }
+
@Override
public JPAMacroTask getMacroTask() {
return macroTask;
diff --git a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jFormPropertyDef.java b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jFormPropertyDef.java
index af494c82e6..ab6f9c9caa 100644
--- a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jFormPropertyDef.java
+++ b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jFormPropertyDef.java
@@ -22,6 +22,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
import jakarta.validation.constraints.NotNull;
import java.util.Map;
import java.util.Optional;
+import java.util.regex.Pattern;
import org.apache.syncope.common.lib.form.FormPropertyType;
import org.apache.syncope.core.persistence.api.entity.task.FormPropertyDef;
import org.apache.syncope.core.persistence.api.entity.task.MacroTask;
@@ -39,6 +40,9 @@ public class Neo4jFormPropertyDef extends AbstractProvidedKeyNode implements For
public static final String NODE = "FormPropertyDef";
+ protected static final TypeReference<Map<String, String>> TYPEREF = new TypeReference<Map<String, String>>() {
+ };
+
@NotNull
@Relationship(type = Neo4jMacroTask.MACRO_TASK_FORM_PROPERTY_DEF_REL, direction = Relationship.Direction.OUTGOING)
private Neo4jMacroTask macroTask;
@@ -58,10 +62,18 @@ public class Neo4jFormPropertyDef extends AbstractProvidedKeyNode implements For
@NotNull
private Boolean required = Boolean.FALSE;
+ private String stringRegEx;
+
private String datePattern;
private String enumValues;
+ @NotNull
+ private Boolean dropdownSingleSelection = Boolean.TRUE;
+
+ @NotNull
+ private Boolean dropdownFreeForm = Boolean.FALSE;
+
@Override
public Neo4jMacroTask getMacroTask() {
return macroTask;
@@ -123,6 +135,16 @@ public class Neo4jFormPropertyDef extends AbstractProvidedKeyNode implements For
this.required = required;
}
+ @Override
+ public Pattern getStringRegEx() {
+ return Optional.ofNullable(stringRegEx).map(Pattern::compile).orElse(null);
+ }
+
+ @Override
+ public void setStringRegExp(final Pattern stringRegEx) {
+ this.stringRegEx = Optional.ofNullable(stringRegEx).map(Pattern::pattern).orElse(null);
+ }
+
@Override
public String getDatePattern() {
return datePattern;
@@ -135,13 +157,31 @@ public class Neo4jFormPropertyDef extends AbstractProvidedKeyNode implements For
@Override
public Map<String, String> getEnumValues() {
- return Optional.ofNullable(enumValues).
- map(v -> POJOHelper.deserialize(v, new TypeReference<Map<String, String>>() {
- })).orElse(Map.of());
+ return Optional.ofNullable(enumValues).map(v -> POJOHelper.deserialize(v, TYPEREF)).orElse(Map.of());
}
@Override
public void setEnumValues(final Map<String, String> enumValues) {
this.enumValues = Optional.ofNullable(enumValues).map(POJOHelper::serialize).orElse(null);
}
+
+ @Override
+ public boolean isDropdownSingleSelection() {
+ return dropdownSingleSelection == null ? false : dropdownSingleSelection;
+ }
+
+ @Override
+ public void setDropdownSingleSelection(final boolean dropdownSingleSelection) {
+ this.dropdownSingleSelection = dropdownSingleSelection;
+ }
+
+ @Override
+ public boolean isDropdownFreeForm() {
+ return dropdownFreeForm == null ? false : dropdownFreeForm;
+ }
+
+ @Override
+ public void setDropdownFreeForm(final boolean dropdownFreeForm) {
+ this.dropdownFreeForm = dropdownFreeForm;
+ }
}
diff --git a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jFormPropertyDefRelationship.java b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jFormPropertyDefRelationship.java
new file mode 100644
index 0000000000..be1cfc5fb7
--- /dev/null
+++ b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jFormPropertyDefRelationship.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.neo4j.entity.task;
+
+import jakarta.validation.Valid;
+import java.util.function.BiFunction;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.syncope.core.persistence.neo4j.entity.Neo4jSortedRelationsihip;
+import org.springframework.data.neo4j.core.schema.RelationshipId;
+import org.springframework.data.neo4j.core.schema.RelationshipProperties;
+import org.springframework.data.neo4j.core.schema.TargetNode;
+
+@RelationshipProperties
+public class Neo4jFormPropertyDefRelationship
+ extends Neo4jSortedRelationsihip<Neo4jFormPropertyDef>
+ implements Comparable<Neo4jFormPropertyDefRelationship> {
+
+ public static BiFunction<Integer, Neo4jFormPropertyDef, Neo4jFormPropertyDefRelationship> builder() {
+ return (Integer i, Neo4jFormPropertyDef e) -> new Neo4jFormPropertyDefRelationship(i, e);
+ }
+
+ @RelationshipId
+ private Long id;
+
+ private int index;
+
+ @TargetNode
+ @Valid
+ private Neo4jFormPropertyDef formPropertyDef;
+
+ public Neo4jFormPropertyDefRelationship(final int index, final Neo4jFormPropertyDef formPropertyDef) {
+ this.index = index;
+ this.formPropertyDef = formPropertyDef;
+ }
+
+ @Override
+ public int getIndex() {
+ return index;
+ }
+
+ @Override
+ public Neo4jFormPropertyDef getEntity() {
+ return formPropertyDef;
+ }
+
+ @Override
+ public int compareTo(final Neo4jFormPropertyDefRelationship object) {
+ return Integer.compare(index, object.getIndex());
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Neo4jFormPropertyDefRelationship other = (Neo4jFormPropertyDefRelationship) obj;
+ return new EqualsBuilder().
+ append(index, other.index).
+ append(formPropertyDef, other.formPropertyDef).
+ build();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder().
+ append(index).
+ append(formPropertyDef).
+ build();
+ }
+
+ @Override
+ public String toString() {
+ return "Neo4jMacroTaskCommandRelationship{"
+ + "id=" + id
+ + ", index=" + index
+ + ", formPropertyDef=" + formPropertyDef
+ + '}';
+ }
+}
diff --git a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jMacroTask.java b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jMacroTask.java
index ff830350df..8427d08c85 100644
--- a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jMacroTask.java
+++ b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/task/Neo4jMacroTask.java
@@ -74,7 +74,11 @@ public class Neo4jMacroTask extends Neo4jSchedTask implements MacroTask {
@Relationship(type = MACRO_TASK_FORM_PROPERTY_DEF_REL, direction = Relationship.Direction.INCOMING)
@Valid
- private List<Neo4jFormPropertyDef> formPropertyDefs = new ArrayList<>();
+ private SortedSet<Neo4jFormPropertyDefRelationship> formPropertyDefs = new TreeSet<>();
+
+ @Transient
+ private List<Neo4jFormPropertyDef> sortedFormPropertyDefs = new SortedSetList<>(
+ formPropertyDefs, Neo4jFormPropertyDefRelationship.builder());
@Relationship(type = MACRO_TASK_MACRO_ACTIONS_REL, direction = Relationship.Direction.OUTGOING)
private Neo4jImplementation macroActions;
@@ -142,12 +146,12 @@ public class Neo4jMacroTask extends Neo4jSchedTask implements MacroTask {
@Override
public void add(final FormPropertyDef formPropertyDef) {
checkType(formPropertyDef, Neo4jFormPropertyDef.class);
- this.formPropertyDefs.add((Neo4jFormPropertyDef) formPropertyDef);
+ sortedFormPropertyDefs.add((Neo4jFormPropertyDef) formPropertyDef);
}
@Override
public List<? extends FormPropertyDef> getFormPropertyDefs() {
- return formPropertyDefs;
+ return sortedFormPropertyDefs;
}
@Override
@@ -165,5 +169,6 @@ public class Neo4jMacroTask extends Neo4jSchedTask implements MacroTask {
@PostLoad
public void postLoad() {
sortedCommands = new SortedSetList<>(commands, Neo4jMacroTaskCommandRelationship.builder());
+ sortedFormPropertyDefs = new SortedSetList<>(formPropertyDefs, Neo4jFormPropertyDefRelationship.builder());
}
}
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/macro/MacroActions.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/macro/MacroActions.java
index a631586731..b0de301083 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/macro/MacroActions.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/macro/MacroActions.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.provisioning.api.macro;
import jakarta.validation.ValidationException;
import java.util.Map;
+import java.util.Optional;
import org.apache.syncope.common.lib.command.CommandArgs;
import org.apache.syncope.common.lib.form.SyncopeForm;
@@ -28,14 +29,18 @@ import org.apache.syncope.common.lib.form.SyncopeForm;
*/
public interface MacroActions {
- default void validate(SyncopeForm macroTaskForm) throws ValidationException {
- // does nothing by default
+ default Optional<String> getDefaultValue(String formProperty) {
+ return Optional.empty();
}
default Map<String, String> getDropdownValues(String formProperty) {
return Map.of();
}
+ default void validate(SyncopeForm form, Map<String, Object> vars) throws ValidationException {
+ // does nothing by default
+ }
+
default void beforeAll() {
// does nothing by default
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
index b92d98ebc8..53eec0b341 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
@@ -34,6 +34,7 @@ import org.apache.syncope.core.persistence.api.entity.EntityFactory;
import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.provisioning.api.data.ImplementationDataBinder;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -133,6 +134,15 @@ public class ImplementationDataBinderImpl implements ImplementationDataBinder {
}
break;
}
+ } else if (implementation.getEngine() == ImplementationEngine.GROOVY) {
+ try {
+ ImplementationManager.build(implementation);
+ } catch (Exception e) {
+ LOG.error("While building Groovy class {}", implementation.getKey(), e);
+
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
}
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
index d4eb8492a6..2c19d573aa 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
@@ -275,9 +275,12 @@ public class TaskDataBinderImpl extends AbstractExecutableDatabinder implements
fpd.setType(fpdTO.getType());
fpd.setReadable(fpdTO.isReadable());
fpd.setWritable(fpdTO.isWritable());
+ fpd.setStringRegExp(fpdTO.getStringRegEx());
fpd.setRequired(fpdTO.isRequired());
fpd.setDatePattern(fpdTO.getDatePattern());
fpd.setEnumValues(fpdTO.getEnumValues());
+ fpd.setDropdownSingleSelection(fpdTO.isDropdownSingleSelection());
+ fpd.setDropdownFreeForm(fpdTO.isDropdownFreeForm());
fpd.setMacroTask(macroTask);
macroTask.add(fpd);
@@ -500,8 +503,11 @@ public class TaskDataBinderImpl extends AbstractExecutableDatabinder implements
fpdTO.setReadable(fpd.isReadable());
fpdTO.setWritable(fpd.isWritable());
fpdTO.setRequired(fpd.isRequired());
+ fpdTO.setStringRegEx(fpd.getStringRegEx());
fpdTO.setDatePattern(fpd.getDatePattern());
fpdTO.getEnumValues().putAll(fpd.getEnumValues());
+ fpdTO.setDropdownSingleSelection(fpd.isDropdownSingleSelection());
+ fpdTO.setDropdownFreeForm(fpd.isDropdownFreeForm());
macroTaskTO.getFormPropertyDefs().add(fpdTO);
});
@@ -608,7 +614,11 @@ public class TaskDataBinderImpl extends AbstractExecutableDatabinder implements
prop.setRequired(fpd.isRequired());
prop.setWritable(fpd.isWritable());
prop.setType(fpd.getType());
+ actions.flatMap(a -> a.getDefaultValue(fpd.getKey())).ifPresent(v -> prop.setValue(v));
switch (prop.getType()) {
+ case String ->
+ prop.setStringRegEx(fpd.getStringRegEx());
+
case Date ->
prop.setDatePattern(fpd.getDatePattern());
@@ -616,9 +626,12 @@ public class TaskDataBinderImpl extends AbstractExecutableDatabinder implements
fpd.getEnumValues().
forEach((key, value) -> prop.getEnumValues().add(new FormPropertyValue(key, value)));
- case Dropdown ->
+ case Dropdown -> {
actions.ifPresent(a -> a.getDropdownValues(fpd.getKey()).
forEach((key, value) -> prop.getDropdownValues().add(new FormPropertyValue(key, value))));
+ prop.setDropdownSingleSelection(fpd.isDropdownSingleSelection());
+ prop.setDropdownFreeForm(fpd.isDropdownFreeForm());
+ }
default -> {
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/MacroJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/MacroJobDelegate.java
index e563026212..69e1a26856 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/MacroJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/MacroJobDelegate.java
@@ -22,7 +22,9 @@ import jakarta.annotation.Resource;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ValidationException;
import jakarta.validation.Validator;
+import java.time.format.DateTimeParseException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -39,6 +41,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.command.CommandArgs;
+import org.apache.syncope.common.lib.form.FormProperty;
import org.apache.syncope.common.lib.form.SyncopeForm;
import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
import org.apache.syncope.core.persistence.api.entity.task.FormPropertyDef;
@@ -54,6 +57,7 @@ import org.apache.syncope.core.provisioning.api.macro.MacroActions;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import org.apache.syncope.core.spring.implementation.ImplementationManager;
import org.apache.syncope.core.spring.task.VirtualThreadPoolTaskExecutor;
+import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.concurrent.DelegatingSecurityContextCallable;
import org.springframework.util.ReflectionUtils;
@@ -75,21 +79,6 @@ public class MacroJobDelegate extends AbstractSchedTaskJobDelegate<MacroTask> {
protected final Map<String, Command<?>> perContextCommands = new ConcurrentHashMap<>();
- protected boolean validate(final FormPropertyDef fpd, final String value, final Optional<MacroActions> actions) {
- if (!fpd.isWritable()) {
- return false;
- }
-
- return switch (fpd.getType()) {
- case Enum ->
- fpd.getEnumValues().containsKey(value);
- case Dropdown ->
- actions.map(a -> a.getDropdownValues(fpd.getKey()).containsKey(value)).orElse(false);
- default ->
- value != null;
- };
- }
-
protected Optional<JexlContext> check(
final SyncopeForm macroTaskForm,
final Optional<MacroActions> actions,
@@ -112,47 +101,81 @@ public class MacroJobDelegate extends AbstractSchedTaskJobDelegate<MacroTask> {
throw new JobExecutionException("Required form properties missing: " + missingFormProperties);
}
+ // build the JEXL context where variables are mapped to property values, built according to the defined type
+ Map<String, Object> vars = new HashMap<>();
+ for (FormPropertyDef fpd : task.getFormPropertyDefs()) {
+ String value = macroTaskForm.getProperty(fpd.getKey()).map(FormProperty::getValue).orElse(null);
+ if (value == null) {
+ continue;
+ }
+
+ switch (fpd.getType()) {
+ case String -> {
+ if (Optional.ofNullable(fpd.getStringRegEx()).
+ map(pattern -> !pattern.matcher(value).matches()).
+ orElse(false)) {
+
+ throw new JobExecutionException("RegEx not matching for " + fpd.getKey() + ": " + value);
+ }
+
+ vars.put(fpd.getKey(), value);
+ }
+
+ case Password ->
+ vars.put(fpd.getKey(), value);
+
+ case Boolean ->
+ vars.put(fpd.getKey(), BooleanUtils.toBoolean(value));
+
+ case Date -> {
+ try {
+ vars.put(fpd.getKey(), StringUtils.isBlank(fpd.getDatePattern())
+ ? FormatUtils.parseDate(value)
+ : FormatUtils.parseDate(value, fpd.getDatePattern()));
+ } catch (DateTimeParseException e) {
+ throw new JobExecutionException("Unparseable date " + fpd.getKey() + ": " + value, e);
+ }
+ }
+
+ case Long ->
+ vars.put(fpd.getKey(), NumberUtils.toLong(value));
+
+ case Enum -> {
+ if (!fpd.getEnumValues().containsKey(value)) {
+ throw new JobExecutionException("Not allowed for " + fpd.getKey() + ": " + value);
+ }
+
+ vars.put(fpd.getKey(), value);
+ }
+
+ case Dropdown -> {
+ if (!fpd.isDropdownFreeForm()) {
+ List<String> values = fpd.isDropdownSingleSelection()
+ ? List.of(value)
+ : List.of(value.split(";"));
+
+ if (!actions.map(a -> a.getDropdownValues(fpd.getKey()).keySet()).
+ orElse(Set.of()).containsAll(values)) {
+
+ throw new JobExecutionException("Not allowed for " + fpd.getKey() + ": " + values);
+ }
+ }
+
+ vars.put(fpd.getKey(), value);
+ }
+
+ default -> {
+ }
+ }
+ }
+
// if validator is defined, validate the provided form
try {
- actions.ifPresent(a -> a.validate(macroTaskForm));
+ actions.ifPresent(a -> a.validate(macroTaskForm, vars));
} catch (ValidationException e) {
throw new JobExecutionException("Invalid form submitted for task " + task.getKey(), e);
}
- // build the JEXL context where variables are mapped to property values, built according to the defined type
- Map<String, Object> vars = macroTaskForm.getProperties().stream().
- map(p -> task.getFormPropertyDefs().stream().
- filter(fpd -> fpd.getKey().equals(p.getId()) && validate(fpd, p.getValue(), actions)).findFirst().
- map(fpd -> Pair.of(fpd, p.getValue()))).
- filter(Optional::isPresent).map(Optional::get).
- map(pair -> {
- Object value;
- switch (pair.getLeft().getType()) {
- case Boolean:
- value = BooleanUtils.toBoolean(pair.getRight());
- break;
-
- case Date:
- value = StringUtils.isBlank(pair.getLeft().getDatePattern())
- ? FormatUtils.parseDate(pair.getRight())
- : FormatUtils.parseDate(pair.getRight(), pair.getLeft().getDatePattern());
- break;
-
- case Long:
- value = NumberUtils.toLong(pair.getRight());
- break;
-
- case Enum:
- case Dropdown:
- case String:
- case Password:
- default:
- value = pair.getRight();
- }
-
- return Pair.of(pair.getLeft().getKey(), value);
- }).collect(Collectors.toMap(Pair::getLeft, Pair::getRight));
-
output.append("Form parameter values: ").append(vars).append("\n\n");
return vars.isEmpty() ? Optional.empty() : Optional.of(new MapContext(vars));
@@ -165,10 +188,10 @@ public class MacroJobDelegate extends AbstractSchedTaskJobDelegate<MacroTask> {
final boolean dryRun)
throws JobExecutionException {
- Future<AtomicReference<Pair<String, Exception>>> future = executor.submit(
+ Future<AtomicReference<Pair<String, Throwable>>> future = executor.submit(
new DelegatingSecurityContextCallable<>(() -> {
- AtomicReference<Pair<String, Exception>> error = new AtomicReference<>();
+ AtomicReference<Pair<String, Throwable>> error = new AtomicReference<>();
for (int i = 0; i < commands.size() && error.get() == null; i++) {
Pair<Command<CommandArgs>, CommandArgs> command = commands.get(i);
@@ -187,14 +210,14 @@ public class MacroJobDelegate extends AbstractSchedTaskJobDelegate<MacroTask> {
output.append(cmdOut);
}
- } catch (Exception e) {
+ } catch (Throwable t) {
if (task.isContinueOnError()) {
- output.append("Continuing on error: <").append(e.getMessage()).append('>');
+ output.append("Continuing on error: <").append(t.getMessage()).append('>');
LOG.error("While running {} with args {}, continuing on error",
- command.getLeft().getClass().getName(), command.getRight(), e);
+ command.getLeft().getClass().getName(), command.getRight(), t);
} else {
- error.set(Pair.of(command.getLeft().getClass().getName(), e));
+ error.set(Pair.of(AopUtils.getTargetClass(command.getLeft()).getName(), t));
}
}
output.append("\n\n");
@@ -204,7 +227,7 @@ public class MacroJobDelegate extends AbstractSchedTaskJobDelegate<MacroTask> {
}));
try {
- AtomicReference<Pair<String, Exception>> error = future.get();
+ AtomicReference<Pair<String, Throwable>> error = future.get();
if (error.get() != null) {
throw new JobExecutionException("While running " + error.get().getLeft(), error.get().getRight());
}
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormPanel.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormPanel.java
index 78f64fa198..e2e80e488a 100644
--- a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormPanel.java
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormPanel.java
@@ -44,9 +44,7 @@ public abstract class UserRequestFormPanel extends SyncopeFormPanel<UserRequestF
MetaDataRoleAuthorizationStrategy.authorize(userDetails, ENABLE, IdRepoEntitlement.USER_READ);
boolean enabled = form.getUserTO() != null;
- userDetails.setVisible(enabled).setEnabled(enabled);
-
- add(userDetails);
+ add(userDetails.setVisible(enabled).setEnabled(enabled));
}
protected abstract void viewDetails(AjaxRequestTarget target);