diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMExternalResourceProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMExternalResourceProvider.java index bb92a285545..53b47ff6859 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMExternalResourceProvider.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMExternalResourceProvider.java @@ -22,6 +22,7 @@ import java.util.stream.Collectors; import org.apache.syncope.client.console.rest.ResourceRestClient; import org.apache.syncope.common.lib.to.ResourceTO; +import org.apache.syncope.common.lib.types.AnyTypeKind; public class IdMExternalResourceProvider implements ExternalResourceProvider { @@ -34,7 +35,18 @@ public IdMExternalResourceProvider(final ResourceRestClient resourceRestClient) } @Override - public List get() { - return resourceRestClient.list().stream().map(ResourceTO::getKey).collect(Collectors.toList()); + public List get(final String anyType) { + return resourceRestClient.list().stream(). + filter(r -> AnyTypeKind.GROUP.name().equals(anyType) || r.getProvision(anyType).isPresent()). + map(ResourceTO::getKey). + collect(Collectors.toList()); + } + + @Override + public List getForRealms() { + return resourceRestClient.list().stream(). + filter(r -> r.getOrgUnit() != null). + map(ResourceTO::getKey). + collect(Collectors.toList()); } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/Resources.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/Resources.java index ac1d1e131cd..db2aeec6351 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/Resources.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/Resources.java @@ -47,10 +47,10 @@ public Resources(final AnyWrapper modelObject) { public boolean evaluate() { if (SyncopeWebApplication.get().getSecuritySettings(). getAuthorizationStrategy().isActionAuthorized(this, RENDER)) { - available.setObject(SyncopeWebApplication.get().getResourceProvider().get()); + + available.setObject(SyncopeWebApplication.get().getResourceProvider().get(anyTO.getType())); return !available.getObject().isEmpty(); - } else { - return false; } + return false; } } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/layout/AbstractAnyFormLayout.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/layout/AbstractAnyFormLayout.java index f9980393846..2a7b6df7277 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/layout/AbstractAnyFormLayout.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/layout/AbstractAnyFormLayout.java @@ -28,10 +28,20 @@ public abstract class AbstractAnyFormLayout whichPlainAttrs = new ArrayList<>(); private final List whichDerAttrs = new ArrayList<>(); + public boolean isRelationships() { + return relationships; + } + + public void setRelationships(final boolean relationships) { + this.relationships = relationships; + } + public List getWhichPlainAttrs() { return whichPlainAttrs; } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractResources.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractResources.java index ad1107db3f0..f6fde2dd452 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractResources.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractResources.java @@ -34,15 +34,17 @@ public abstract class AbstractResources extends WizardStep implements ICondition private static final long serialVersionUID = 552437609667518888L; + protected final AnyTO anyTO; + protected final ListModel available; public AbstractResources(final AnyWrapper modelObject) { - final T entityTO = modelObject.getInnerObject(); + anyTO = modelObject.getInnerObject(); - if (modelObject instanceof UserWrapper - && UserWrapper.class.cast(modelObject).getPreviousUserTO() != null + if (modelObject instanceof UserWrapper userWrapper + && userWrapper.getPreviousUserTO() != null && !modelObject.getInnerObject().getResources().equals( - UserWrapper.class.cast(modelObject).getPreviousUserTO().getResources())) { + userWrapper.getPreviousUserTO().getResources())) { add(new LabelInfo("changed", StringUtils.EMPTY)); } else { @@ -52,19 +54,19 @@ public AbstractResources(final AnyWrapper modelObject) { this.setOutputMarkupId(true); this.available = new ListModel<>(List.of()); - add(new AjaxPalettePanel.Builder().build("resources", new PropertyModel<>(entityTO, "resources") { + add(new AjaxPalettePanel.Builder().build("resources", new PropertyModel<>(anyTO, "resources") { private static final long serialVersionUID = 3799387950428254072L; @Override public List getObject() { - return new ArrayList<>(entityTO.getResources()); + return new ArrayList<>(anyTO.getResources()); } @Override public void setObject(final List object) { - entityTO.getResources().clear(); - entityTO.getResources().addAll(object); + anyTO.getResources().clear(); + anyTO.getResources().addAll(object); } }, available).hideLabel().setOutputMarkupId(true)); } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/ExternalResourceProvider.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/ExternalResourceProvider.java index fc419cff9f6..0b860692399 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/ExternalResourceProvider.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/ExternalResourceProvider.java @@ -21,8 +21,9 @@ import java.io.Serializable; import java.util.List; -@FunctionalInterface public interface ExternalResourceProvider extends Serializable { - List get(); + List get(String anyType); + + List getForRealms(); } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/IdRepoExternalResourceProvider.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/IdRepoExternalResourceProvider.java index e21f6225bc9..5c0a5e776ad 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/IdRepoExternalResourceProvider.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/commons/IdRepoExternalResourceProvider.java @@ -25,7 +25,12 @@ public class IdRepoExternalResourceProvider implements ExternalResourceProvider private static final long serialVersionUID = 3002474783308961295L; @Override - public List get() { + public List get(final String anyType) { + return List.of(); + } + + @Override + public List getForRealms() { return List.of(); } } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java index 22e7e899809..4c9d2336195 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java @@ -31,8 +31,6 @@ public class UserFormLayoutInfo extends AbstractAnyFormLayout private boolean roles = true; - private boolean relationships = true; - @Override protected Class getDefaultFormClass() { return UserWizardBuilder.class; @@ -53,12 +51,4 @@ public boolean isRoles() { public void setRoles(final boolean roles) { this.roles = roles; } - - public boolean isRelationships() { - return relationships; - } - - public void setRelationships(final boolean relationships) { - this.relationships = relationships; - } } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmDetails.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmDetails.java index 86bfecf4953..5f57098eb83 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmDetails.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmDetails.java @@ -88,7 +88,7 @@ protected List load() { @Override protected List load() { - return SyncopeWebApplication.get().getResourceProvider().get(); + return SyncopeWebApplication.get().getResourceProvider().getForRealms(); } }; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipViewPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipViewPanel.java index d979d2f96de..9272776b30f 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipViewPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipViewPanel.java @@ -28,6 +28,7 @@ import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.common.lib.to.AnyObjectTO; import org.apache.syncope.common.lib.to.AnyTO; +import org.apache.syncope.common.lib.to.GroupTO; import org.apache.syncope.common.lib.to.RelationshipTO; import org.apache.syncope.common.lib.to.UserTO; import org.apache.syncope.common.lib.types.AnyEntitlement; @@ -56,8 +57,15 @@ private RelationshipViewPanel( final AnyTO anyTO, final boolean reuseItem, final boolean wizardInModal) { + super(id, wizardInModal); - addInnerObject(getHeader()); + + WebMarkupContainer header = new WebMarkupContainer("header"); + header.add(new Label("header_left_end", getString("left.end"))); + header.add(new Label("header_relationship", new ResourceModel("relationship"))); + header.add(new Label("header_right_end", new ResourceModel("right.end"))); + addInnerObject(header); + relationshipsList = new ListView<>("relationships", relationships) { private static final long serialVersionUID = 4983556433071042668L; @@ -101,9 +109,8 @@ protected void onEvent(final AjaxRequestTarget target) { if (togglePanel == null) { relationshipItem.add(action); } else { - relationshipItem.add(new ActionsPanel<>("action", new Model<>(relationshipTO)) - .setVisible(false) - .setEnabled(false)); + relationshipItem.add(new ActionsPanel<>("action", new Model<>(relationshipTO)). + setVisible(false).setEnabled(false)); } } }; @@ -112,25 +119,20 @@ protected void onEvent(final AjaxRequestTarget target) { relationshipsList.setRenderBodyOnly(true); addInnerObject(relationshipsList); - - } - - private WebMarkupContainer getHeader() { - WebMarkupContainer headerContainer = new WebMarkupContainer("header"); - headerContainer.add(new Label("header_left_end", getString("left.end"))); - headerContainer.add(new Label("header_relationship", new ResourceModel("relationship"))); - headerContainer.add(new Label("header_right_end", new ResourceModel("right.end"))); - return headerContainer; } - private void buildRowLabels( + private static void buildRowLabels( final ListItem row, final RelationshipTO relationshipTO, final AnyTO anyTO) { + boolean isLeftRelation = relationshipTO.getEnd() == RelationshipTO.End.LEFT; - String anyName = anyTO instanceof UserTO - ? UserTO.class.cast(anyTO).getUsername() - : AnyObjectTO.class.cast(anyTO).getName(); + + String anyName = anyTO instanceof UserTO userTO + ? userTO.getUsername() + : anyTO instanceof GroupTO groupTO + ? groupTO.getName() + : AnyObjectTO.class.cast(anyTO).getName(); row.add(new Label("relationship", relationshipTO.getType())); Label leftEnd = new Label("left_end", isLeftRelation @@ -149,7 +151,7 @@ private void buildRowLabels( row.add(leftEnd, rightEnd); } - private void setBold(final Label... labels) { + private static void setBold(final Label... labels) { for (Label label : labels) { label.add(new AttributeModifier("style", "font-weight: bold;")); } @@ -176,7 +178,6 @@ public RelationshipViewPanel.Builder setAnyTO(final AnyTO anyTO) { return this; } - public RelationshipViewPanel.Builder setRelationships(final List relationships) { this.relationships = relationships; return this; @@ -204,8 +205,5 @@ public RelationshipViewPanel.Builder setReuseItem(final boolean reuseItem) { protected WizardMgtPanel newInstance(final String id, final boolean wizardInModal) { return new RelationshipViewPanel(id, relationships, anyTO, reuseItem, wizardInModal); } - } - } - diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/AbstractSearchPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/AbstractSearchPanel.java index bbe164e84eb..fb71837ce08 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/AbstractSearchPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/AbstractSearchPanel.java @@ -87,7 +87,7 @@ public abstract class AbstractSearchPanel extends Panel { protected final AnyTypeKind typeKind; - protected final String type; + protected final String anyType; public abstract static class Builder implements Serializable { @@ -150,7 +150,7 @@ protected AbstractSearchPanel( this.model = builder.model; this.typeKind = kind; - this.type = type; + this.anyType = type; setOutputMarkupId(true); @@ -233,8 +233,8 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { protected abstract String getFIQLQueryTarget(); protected void updateFIQL(final AjaxRequestTarget target, final String fiql) { - model.setObject(SearchUtils.getSearchClauses( - fiql.replaceAll(SearchUtils.getTypeConditionPattern(type).pattern(), ""))); + model.setObject(SearchUtils.getSearchClauses(fiql.replaceAll(SearchUtils.getTypeConditionPattern(anyType). + pattern(), ""))); target.add(searchFormContainer); } @@ -275,17 +275,17 @@ protected List load() { @Override protected List load() { - return SyncopeWebApplication.get().getResourceProvider().get(); + return SyncopeWebApplication.get().getResourceProvider().get(anyType); } }; } public IModel> getModel() { - return this.model; + return model; } - public String getBackObjectType() { - return this.type; + public String getAnyType() { + return anyType; } public Map getAvailableSchemaTypes() { diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSearchPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSearchPanel.java index 908168830c4..4045b8f03aa 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSearchPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSearchPanel.java @@ -77,12 +77,12 @@ protected AnyObjectSearchPanel(final String id, final AnyTypeKind kind, final St @Override protected AbstractFiqlSearchConditionBuilder getSearchConditionBuilder() { - return SyncopeClient.getAnyObjectSearchConditionBuilder(type); + return SyncopeClient.getAnyObjectSearchConditionBuilder(anyType); } @Override protected String getFIQLQueryTarget() { - return type; + return anyType; } @Override @@ -121,8 +121,8 @@ protected List load() { @Override protected Map load() { - return schemaRestClient.getSchemas(SchemaType.PLAIN, null, anyTypeRestClient.read(type). - getClasses().toArray(String[]::new)). + return schemaRestClient.getSchemas( + SchemaType.PLAIN, null, anyTypeRestClient.read(anyType).getClasses().toArray(String[]::new)). stream().collect(Collectors.toMap(SchemaTO::getKey, Function.identity())); } }; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSearchPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSearchPanel.java index 66251893ddc..22da0fad1a5 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSearchPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSearchPanel.java @@ -110,7 +110,7 @@ protected List load() { @Override protected Map load() { return schemaRestClient.getSchemas( - SchemaType.PLAIN, null, anyTypeRestClient.read(type).getClasses().toArray(String[]::new)). + SchemaType.PLAIN, null, anyTypeRestClient.read(anyType).getClasses().toArray(String[]::new)). stream().collect(Collectors.toMap(SchemaTO::getKey, Function.identity())); } }; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchUtils.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchUtils.java index 6101b96b5f6..c45c38b550c 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchUtils.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/search/SearchUtils.java @@ -246,14 +246,14 @@ public static String buildFIQL( switch (clause.getType()) { case GROUP_MEMBER: - if (builder instanceof GroupFiqlSearchConditionBuilder) { + if (builder instanceof final GroupFiqlSearchConditionBuilder gbuilder) { switch (clause.getComparator()) { case EQUALS: - condition = ((GroupFiqlSearchConditionBuilder) builder).withMembers(value); + condition = gbuilder.withMembers(value); break; case NOT_EQUALS: - condition = ((GroupFiqlSearchConditionBuilder) builder).withoutMembers(value); + condition = gbuilder.withoutMembers(value); break; default: @@ -265,14 +265,14 @@ public static String buildFIQL( if (StringUtils.isNotBlank(clause.getProperty())) { String groupKey = clause.getProperty(); - if (builder instanceof final UserFiqlSearchConditionBuilder conditionBuilder) { + if (builder instanceof final UserFiqlSearchConditionBuilder ubuilder) { condition = clause.getComparator() == SearchClause.Comparator.EQUALS - ? conditionBuilder.inGroups(groupKey) - : conditionBuilder.notInGroups(groupKey); - } else { + ? ubuilder.inGroups(groupKey) + : ubuilder.notInGroups(groupKey); + } else if (builder instanceof final AnyObjectFiqlSearchConditionBuilder abuilder) { condition = clause.getComparator() == SearchClause.Comparator.EQUALS - ? ((AnyObjectFiqlSearchConditionBuilder) builder).inGroups(groupKey) - : ((AnyObjectFiqlSearchConditionBuilder) builder).notInGroups(groupKey); + ? abuilder.inGroups(groupKey) + : abuilder.notInGroups(groupKey); } } break; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java index cedd20287e0..bf322d4b3bf 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java @@ -26,7 +26,6 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.SyncopeWebApplication; -import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo; import org.apache.syncope.client.console.layout.GroupFormLayoutInfo; import org.apache.syncope.client.console.layout.UserFormLayoutInfo; import org.apache.syncope.client.ui.commons.layout.AbstractAnyFormLayout; @@ -127,8 +126,7 @@ protected WizardModel buildModelSteps(final AnyWrapper modelObject, final Wiz // attributes panel steps if (formLayoutInfo.isPlainAttrs()) { - wizardModel.add( - new PlainAttrs(modelObject, mode, anyTypeClasses, formLayoutInfo.getWhichPlainAttrs()) { + wizardModel.add(new PlainAttrs(modelObject, mode, anyTypeClasses, formLayoutInfo.getWhichPlainAttrs()) { private static final long serialVersionUID = 8167894751609598306L; @@ -151,12 +149,7 @@ public PageReference getPageReference() { wizardModel.add(new Roles(userWrapper)); } - // relationship panel step (available for users and any objects) - if ((formLayoutInfo instanceof UserFormLayoutInfo - && UserFormLayoutInfo.class.cast(formLayoutInfo).isRelationships()) - || (formLayoutInfo instanceof AnyObjectFormLayoutInfo - && AnyObjectFormLayoutInfo.class.cast(formLayoutInfo).isRelationships())) { - + if (formLayoutInfo.isRelationships()) { wizardModel.add(new Relationships(modelObject, pageRef)); } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java index 13df8494e2d..608130945a6 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java @@ -20,7 +20,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; @@ -32,8 +34,6 @@ import org.apache.syncope.client.console.panels.search.SearchClausePanel; import org.apache.syncope.client.console.panels.search.SearchUtils; import org.apache.syncope.client.console.rest.AnyObjectRestClient; -import org.apache.syncope.client.console.rest.AnyTypeClassRestClient; -import org.apache.syncope.client.console.rest.AnyTypeRestClient; import org.apache.syncope.client.console.rest.RelationshipTypeRestClient; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType; @@ -44,16 +44,15 @@ import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; import org.apache.syncope.client.ui.commons.ajax.markup.html.LabelInfo; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper; import org.apache.syncope.client.ui.commons.wizards.any.UserWrapper; import org.apache.syncope.common.lib.to.AnyObjectTO; import org.apache.syncope.common.lib.to.AnyTO; -import org.apache.syncope.common.lib.to.AnyTypeTO; -import org.apache.syncope.common.lib.to.GroupableRelatableTO; +import org.apache.syncope.common.lib.to.RelatableTO; import org.apache.syncope.common.lib.to.RelationshipTO; import org.apache.syncope.common.lib.to.RelationshipTypeTO; import org.apache.syncope.common.lib.types.AnyEntitlement; -import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.wicket.Component; import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -63,10 +62,8 @@ import org.apache.wicket.extensions.wizard.WizardStep; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.form.IChoiceRenderer; import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.markup.html.panel.Panel; -import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; @@ -80,12 +77,6 @@ public class Relationships extends WizardStep implements ICondition { @SpringBean protected RelationshipTypeRestClient relationshipTypeRestClient; - @SpringBean - protected AnyTypeRestClient anyTypeRestClient; - - @SpringBean - protected AnyTypeClassRestClient anyTypeClassRestClient; - @SpringBean protected AnyObjectRestClient anyObjectRestClient; @@ -158,18 +149,19 @@ public void onClick(final AjaxRequestTarget target, final RelationshipTO ignore) } protected List getCurrentRelationships() { - return anyTO instanceof GroupableRelatableTO - ? GroupableRelatableTO.class.cast(anyTO).getRelationships() + return anyTO instanceof RelatableTO relatableTO + ? relatableTO.getRelationships() : List.of(); } - protected void addNewRelationships(final RelationshipTO... rels) { - getCurrentRelationships().addAll(List.of(rels)); + protected void addNewRelationship(final RelationshipTO relaltionship) { + if (anyTO instanceof RelatableTO relatableTO) { + relatableTO.getRelationships().add(relaltionship); + } } @Override public boolean evaluate() { - // [SYNCOPE-1171] - skip current step when the are no relationships types in Syncope return !relationshipTypeRestClient.list().isEmpty(); } @@ -179,10 +171,6 @@ public class Specification extends Panel { protected final RelationshipTO rel; - protected final AjaxDropDownChoicePanel type; - - protected final AjaxDropDownChoicePanel otherType; - protected final WebMarkupContainer container; protected final Fragment emptyFragment; @@ -198,60 +186,18 @@ public Specification() { rel = new RelationshipTO(); rel.setEnd(RelationshipTO.End.LEFT); - List availableRels = relationshipTypeRestClient.list().stream(). - map(RelationshipTypeTO::getKey).collect(Collectors.toList()); - - type = new AjaxDropDownChoicePanel<>("type", "type", new PropertyModel<>(rel, "type")); - type.setChoices(availableRels); + Map relationshipTypes = relationshipTypeRestClient.list().stream(). + filter(relationshipType -> relationshipType.getLeftEndAnyType().equals(anyTO.getType())). + collect(Collectors.toMap(RelationshipTypeTO::getKey, Function.identity())); + AjaxDropDownChoicePanel type = new AjaxDropDownChoicePanel<>( + "type", "type", new PropertyModel<>(rel, "type"), false); + type.setChoices(relationshipTypes.keySet().stream().sorted().toList()); + type.setNullValid(false); add(type.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true).setRenderBodyOnly(true)); - List availableTypes = anyTypeRestClient.listAnyTypes().stream(). - filter(anyType -> anyType.getKind() != AnyTypeKind.GROUP - && anyType.getKind() != AnyTypeKind.USER).collect(Collectors.toList()); - - otherType = new AjaxDropDownChoicePanel<>("otherType", "otherType", new PropertyModel<>(rel, "otherType") { - - private static final long serialVersionUID = -5861057041758169508L; - - @Override - public AnyTypeTO getObject() { - for (AnyTypeTO obj : availableTypes) { - if (obj.getKey().equals(rel.getOtherEndType())) { - return obj; - } - } - return null; - } - - @Override - public void setObject(final AnyTypeTO object) { - rel.setOtherEndType(Optional.ofNullable(object).map(AnyTypeTO::getKey).orElse(null)); - } - }, false); - otherType.setChoices(availableTypes); - otherType.setChoiceRenderer(new IChoiceRenderer<>() { - - private static final long serialVersionUID = -734743540442190178L; - - @Override - public Object getDisplayValue(final AnyTypeTO object) { - return object.getKey(); - } - - @Override - public String getIdValue(final AnyTypeTO object, final int index) { - return object.getKey(); - } - - @Override - public AnyTypeTO getObject(final String id, final IModel> choices) { - return choices.getObject().stream(). - filter(anyTypeTO -> id.equals(anyTypeTO.getKey())).findAny().orElse(null); - } - }); - // enable "otherType" dropdown only if "type" option is selected - SYNCOPE-1140 - otherType.setEnabled(false); - add(otherType.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true)); + AjaxTextFieldPanel otherEndType = new AjaxTextFieldPanel( + "otherType", "otherType", new PropertyModel<>(rel, "otherEndType")); + add(otherEndType.setEnabled(false).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true)); container = new WebMarkupContainer("searchPanelContainer"); add(container.setOutputMarkupId(true)); @@ -268,35 +214,29 @@ public AnyTypeTO getObject(final String id, final IModel { + otherEndType.setModelObject(oet); + + setupFragment(oet); + container.addOrReplace(fragment.setRenderBodyOnly(true)); + }); } + + target.add(otherEndType); target.add(container); } }); } - protected void setupFragment(final AnyTypeTO anyType) { + protected void setupFragment(final String anyType) { anyObjectSearchPanel = new AnyObjectSearchPanel.Builder( - anyType.getKey(), + anyType, new ListModel<>(new ArrayList<>()), pageRef). enableSearch(Specification.this). @@ -304,11 +244,11 @@ protected void setupFragment(final AnyTypeTO anyType) { fragment.addOrReplace(anyObjectSearchPanel.setRenderBodyOnly(true)); anyObjectDirectoryPanel = new AnyObjectSelectionDirectoryPanel.Builder( - anyTypeClassRestClient.list(anyType.getClasses()), + List.of(), anyObjectRestClient, - anyType.getKey(), + anyType, pageRef). - setFiql(SyncopeClient.getAnyObjectSearchConditionBuilder(anyType.getKey()). + setFiql(SyncopeClient.getAnyObjectSearchConditionBuilder(anyType). is(Constants.KEY_FIELD_NAME).notNullValue().query()). setWizardInModal(true).build("searchResultPanel"); fragment.addOrReplace(anyObjectDirectoryPanel.setRenderBodyOnly(true)); @@ -320,8 +260,8 @@ public void onEvent(final IEvent event) { AjaxRequestTarget target = SearchClausePanel.SearchEvent.class.cast(event.getPayload()).getTarget(); String fiql = SearchUtils.buildFIQL(anyObjectSearchPanel.getModel().getObject(), - SyncopeClient.getAnyObjectSearchConditionBuilder(anyObjectSearchPanel.getBackObjectType())); - AnyDirectoryPanel.class.cast(Specification.this.anyObjectDirectoryPanel).search(fiql, target); + SyncopeClient.getAnyObjectSearchConditionBuilder(anyObjectSearchPanel.getAnyType())); + AnyDirectoryPanel.class.cast(anyObjectDirectoryPanel).search(fiql, target); } else if (event.getPayload() instanceof AnySelectionDirectoryPanel.ItemSelection) { AjaxRequestTarget target = AnySelectionDirectoryPanel.ItemSelection.class.cast(event.getPayload()).getTarget(); @@ -330,7 +270,7 @@ public void onEvent(final IEvent event) { rel.setOtherEndKey(right.getKey()); rel.setOtherEndName(AnyObjectTO.class.cast(right).getName()); - Relationships.this.addNewRelationships(rel); + Relationships.this.addNewRelationship(rel); Relationships.this.addOrReplace(getViewFragment().setRenderBodyOnly(true)); target.add(Relationships.this); diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Relationships$Specification.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Relationships$Specification.html index c58eb6f5956..18e2b521890 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Relationships$Specification.html +++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Relationships$Specification.html @@ -19,7 +19,7 @@
- +
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java index 7fd3ed12273..9ea7ca0b857 100644 --- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java +++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java @@ -175,7 +175,7 @@ public static AnyObjectUR diff( EntityTOUtils.buildRelationshipMap(original.getRelationships()); updatedRels.entrySet().stream(). - filter(entry -> (!originalRels.containsKey(entry.getKey()))). + filter(entry -> !originalRels.containsKey(entry.getKey())). forEach(entry -> result.getRelationships().add(new RelationshipUR.Builder(entry.getValue()). operation(PatchOperation.ADD_REPLACE).build())); @@ -277,7 +277,7 @@ public static UserUR diff(final UserTO updated, final UserTO original, final boo EntityTOUtils.buildRelationshipMap(original.getRelationships()); updatedRels.entrySet().stream(). - filter(entry -> (!originalRels.containsKey(entry.getKey()))). + filter(entry -> !originalRels.containsKey(entry.getKey())). forEach(entry -> result.getRelationships().add(new RelationshipUR.Builder(entry.getValue()). operation(PatchOperation.ADD_REPLACE).build())); @@ -358,6 +358,23 @@ public static GroupUR diff(final GroupTO updated, final GroupTO original, final // 4. type extensions result.getTypeExtensions().addAll(updated.getTypeExtensions()); + // 5. relationships + Map, RelationshipTO> updatedRels = + EntityTOUtils.buildRelationshipMap(updated.getRelationships()); + Map, RelationshipTO> originalRels = + EntityTOUtils.buildRelationshipMap(original.getRelationships()); + + updatedRels.entrySet().stream(). + filter(entry -> !originalRels.containsKey(entry.getKey())). + forEach(entry -> result.getRelationships().add(new RelationshipUR.Builder(entry.getValue()). + operation(PatchOperation.ADD_REPLACE).build())); + + if (!incremental) { + originalRels.keySet().stream().filter(relationship -> !updatedRels.containsKey(relationship)). + forEach(key -> result.getRelationships().add(new RelationshipUR.Builder(originalRels.get(key)). + operation(PatchOperation.DELETE).build())); + } + return result; } @@ -367,10 +384,11 @@ public static P diff( if (updated instanceof UserTO updatedUserTO && original instanceof UserTO originalUserTO) { return (P) diff(updatedUserTO, originalUserTO, incremental); - } else if (updated instanceof GroupTO updatedGroupTO && original instanceof GroupTO originalGroupTO) { + } + if (updated instanceof GroupTO updatedGroupTO && original instanceof GroupTO originalGroupTO) { return (P) diff(updatedGroupTO, originalGroupTO, incremental); - } else if (updated instanceof AnyObjectTO updatedAnyObjectTO - && original instanceof AnyObjectTO originalObjectTO) { + } + if (updated instanceof AnyObjectTO updatedAnyObjectTO && original instanceof AnyObjectTO originalObjectTO) { return (P) diff(updatedAnyObjectTO, originalObjectTO, incremental); } diff --git a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/validation/RelationshipValidator.java b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/validation/RelationshipValidator.java index 38fc2a2666e..15f414a3048 100644 --- a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/validation/RelationshipValidator.java +++ b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/validation/RelationshipValidator.java @@ -33,7 +33,9 @@ public boolean isValid(final Relationship relationship, final ConstraintVa RelationshipType relationshipType = relationship.getType(); - if (!relationshipType.getLeftEndAnyType().equals(relationship.getLeftEnd().getType())) { + if (relationship.getLeftEnd() != null + && !relationshipType.getLeftEndAnyType().equals(relationship.getLeftEnd().getType())) { + context.buildConstraintViolationWithTemplate( getTemplate(EntityViolationType.InvalidAnyType, relationship.getLeftEnd().getType().getKey())). addPropertyNode("leftEnd").addConstraintViolation(); @@ -41,7 +43,9 @@ public boolean isValid(final Relationship relationship, final ConstraintVa isValid = false; } - if (!relationshipType.getRightEndAnyType().equals(relationship.getRightEnd().getType())) { + if (relationship.getRightEnd() != null + && !relationshipType.getRightEndAnyType().equals(relationship.getRightEnd().getType())) { + context.buildConstraintViolationWithTemplate( getTemplate(EntityViolationType.InvalidAnyType, relationship.getRightEnd().getType().getKey())). addPropertyNode("rightEnd").addConstraintViolation(); diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java index 901ccbf10b5..fcae9ee53e8 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java @@ -108,103 +108,6 @@ public void clickToCloneUser() { formTester.submit("buttons:cancel"); } - @Test - public void editRelationships() { - TESTER.clickLink("body:realmsLI:realms", false); - TESTER.clickLink("body:content:body:container:content:tabbedPanel:tabs-container:tabs:1:link"); - - Component component = findComponentByProp("username", CONTAINER - + ":searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", "puccini"); - assertNotNull(component); - - TESTER.executeAjaxEvent(component.getPageRelativePath(), Constants.ON_CLICK); - TESTER.clickLink(TAB_PANEL - + "outerObjectsRepeater:1:outer:container:content:togglePanelContainer:container:" - + "actions:actions:actionRepeater:0:action:action"); - - TESTER.assertComponent(TAB_PANEL - + "outerObjectsRepeater:0:outer:form:content:form:view:username:textField", - TextField.class); - - FormTester formTester = TESTER.newFormTester(TAB_PANEL - + "outerObjectsRepeater:0:outer:form:content:form"); - assertNotNull(formTester); - - formTester.submit("buttons:next"); - - formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); - assertNotNull(formTester); - formTester.submit("buttons:next"); - - formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); - assertNotNull(formTester); - formTester.submit("buttons:next"); - - formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); - assertNotNull(formTester); - formTester.submit("buttons:next"); - - formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); - assertNotNull(formTester); - formTester.submit("buttons:next"); - - formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); - assertNotNull(formTester); - formTester.submit("buttons:next"); - - // Add first RELATIONSHIP - addRelationship("Canon MF 8030cn"); - component = TESTER.getComponentFromLastRenderedPage(TAB_PANEL + "outerObjectsRepeater:0:outer" - + ":form:content:form:view:relationships:relationships:container:content:relationships:0:right_end"); - assertNotNull(component); - assertEquals("PRINTER Canon MF 8030cn", component.getDefaultModel().getObject()); - - // Add second RELATIONSHIP - addRelationship("HP LJ 1300n"); - component = TESTER.getComponentFromLastRenderedPage(TAB_PANEL + "outerObjectsRepeater:0:outer" - + ":form:content:form:view:relationships:relationships:container:content:relationships:1:right_end"); - assertNotNull(component); - assertEquals("PRINTER HP LJ 1300n", component.getDefaultModel().getObject()); - - formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); - assertNotNull(formTester); - formTester.submit("buttons:cancel"); - } - - // issue SYNCOPE-1846 - private void addRelationship(final String printerName) { - TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form:view:relationships:actions:" - + "actionRepeater:0:action:action", Constants.ON_CLICK); - FormTester formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); - assertNotNull(formTester); - - formTester.setValue("view:relationships:specification:type:dropDownChoiceField", "neighborhood"); - TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form:view:relationships:" - + "specification:type:dropDownChoiceField", Constants.ON_CHANGE); - formTester.setValue("view:relationships:specification:type:dropDownChoiceField", "neighborhood"); - // The ON_CHANGE above should enable this component, but it doesn't; doing it by hand - Component otherType = findComponentById( - TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form:view:relationships:specification", - "otherType"); - assertNotNull(otherType); - otherType.setEnabled(true); - - formTester.setValue("view:relationships:specification:otherType:dropDownChoiceField", "PRINTER"); - TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form:view:relationships:" - + "specification:otherType:dropDownChoiceField", Constants.ON_CHANGE); - - Component component = findComponentByProp("name", TAB_PANEL + "outerObjectsRepeater:" - + "0:outer:form:content:form:view:relationships:specification:searchPanelContainer:searchPanel:" - + "searchResultPanel:container:content:searchContainer:resultTable:tablePanel:groupForm:checkgroup:" - + "dataTable:body:rows:1:cells:2:cell", printerName); - assertNotNull(component); - TESTER.executeAjaxEvent(component, Constants.ON_CLICK); - TESTER.clickLink(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form:view:relationships:specification:" - + "searchPanelContainer:searchPanel:searchResultPanel:" - + "outerObjectsRepeater:1:outer:container:content:togglePanelContainer:container:" - + "actions:actions:actionRepeater:0:action:action"); - } - @Test public void editUser() { TESTER.clickLink("body:realmsLI:realms", false); diff --git a/pom.xml b/pom.xml index 4678a2af0c4..28e99c3fb23 100644 --- a/pom.xml +++ b/pom.xml @@ -447,7 +447,7 @@ under the License. 4.0.4 2.2.36 - 5.27.1 + 5.28.0 1.3.8 1.4.1-1 @@ -507,7 +507,7 @@ under the License. 10.1.44 37.0.0.Final - 6.2025.8 + 6.2025.9 4.1.3 17-alpine