blob: 92b812e46cfd8139df4ecf7572efd9b8118d19b2 [file] [log] [blame]
/*
* 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.client.console.wizards.any;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.client.console.rest.ResourceRestClient;
import org.apache.syncope.client.lib.SyncopeClient;
import org.apache.syncope.client.ui.commons.ConnIdSpecialName;
import org.apache.syncope.client.ui.commons.Constants;
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.common.lib.to.ConnObjectTO;
import org.apache.syncope.common.lib.to.LinkedAccountTO;
import org.apache.syncope.common.lib.to.ResourceTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.rest.api.beans.ConnObjectTOQuery;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.attributes.AjaxCallListener;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.ajax.attributes.ThrottlingSettings;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
import org.apache.wicket.extensions.wizard.WizardStep;
import org.apache.wicket.model.PropertyModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicReference;
public class LinkedAccountDetailsPanel extends WizardStep {
private static final long serialVersionUID = 1221037007528732347L;
private static final Logger LOG = LoggerFactory.getLogger(LinkedAccountDetailsPanel.class);
private static final int SEARCH_SIZE = 20;
private final ResourceRestClient resourceRestClient = new ResourceRestClient();
private List<String> connObjectKeyFieldValues;
public LinkedAccountDetailsPanel(final LinkedAccountTO linkedAccountTO) {
super();
setOutputMarkupId(true);
AjaxDropDownChoicePanel<String> dropdownResourceField = new AjaxDropDownChoicePanel<>(
"resource",
"resource",
new PropertyModel<>(linkedAccountTO, "resource"),
false);
dropdownResourceField.setChoices(resourceRestClient.list().stream().
filter(resource -> resource.getProvision(AnyTypeKind.USER.name()).isPresent()
&& resource.getProvision(AnyTypeKind.USER.name()).get().getMapping() != null
&& !resource.getProvision(AnyTypeKind.USER.name()).get().getMapping().getItems().isEmpty()).
map(ResourceTO::getKey).
collect(Collectors.toList()));
dropdownResourceField.setOutputMarkupId(true);
dropdownResourceField.addRequiredLabel();
dropdownResourceField.setNullValid(false);
dropdownResourceField.setRequired(true);
add(dropdownResourceField);
final String connObjectKeyFieldId = "connObjectKeyValue";
AjaxTextFieldPanel connObjectKeyField = new AjaxTextFieldPanel(
"connObjectKeyValue",
"connObjectKeyValue",
new PropertyModel<>(linkedAccountTO, "connObjectKeyValue"),
false);
connObjectKeyField.setOutputMarkupId(true);
connObjectKeyField.addRequiredLabel();
connObjectKeyField.setChoices(List.of());
connObjectKeyField.setEnabled(false);
add(connObjectKeyField);
dropdownResourceField.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
private static final long serialVersionUID = -1107858522700306810L;
@Override
protected void onUpdate(final AjaxRequestTarget target) {
boolean enabled = dropdownResourceField.getModelObject() != null
&& !dropdownResourceField.getModelObject().isEmpty();
connObjectKeyField.setEnabled(enabled);
if (enabled) {
setConnObjectFieldChoices(connObjectKeyField, dropdownResourceField.getModelObject(), null);
}
target.add(connObjectKeyField);
}
});
connObjectKeyField.getField().setMarkupId(connObjectKeyFieldId);
connObjectKeyField.getField().add(new AjaxEventBehavior(Constants.ON_KEYDOWN) {
private static final long serialVersionUID = 3533589614190959822L;
@Override
protected void onEvent(final AjaxRequestTarget target) {
String searchTerm = connObjectKeyField.getField().getInput();
if (StringUtils.isNotBlank(searchTerm) && searchTerm.length() > 1) {
setConnObjectFieldChoices(connObjectKeyField, dropdownResourceField.getModelObject(), searchTerm);
// If elements are found, send an "arrow down" key event to open input autocomplete dropdown
target.appendJavaScript(connObjectKeyFieldValues.isEmpty()
? "$('#" + connObjectKeyFieldId + "-autocomplete-container').hide();"
: "var simulatedEvent = new KeyboardEvent('keydown', {keyCode: 40, which: 40}); "
+ "document.getElementById('" + connObjectKeyFieldId + "').dispatchEvent(simulatedEvent);");
}
}
@Override
protected void updateAjaxAttributes(final AjaxRequestAttributes attributes) {
super.updateAjaxAttributes(attributes);
AjaxCallListener listener = new AjaxCallListener() {
private static final long serialVersionUID = 2208168001920794667L;
@Override
public CharSequence getPrecondition(final Component component) {
// Eevaluates weather an ajax call will be executed or not.
// If the key code is "arrow down" or "arrow up" do NOT trigger the event callback
return "var keycode = Wicket.Event.keyCode(attrs.event); "
+ "if ((keycode == 40) || (keycode == 38)) {return false;} return true;";
}
};
attributes.getAjaxCallListeners().add(listener);
attributes.setThrottlingSettings(
new ThrottlingSettings("id", Duration.of(1, ChronoUnit.SECONDS), true));
}
});
}
private void setConnObjectFieldChoices(
final AjaxTextFieldPanel ajaxTextFieldPanel,
final String resource,
final String searchTerm) {
AtomicReference<String> resourceRemoteKey = new AtomicReference<>(ConnIdSpecialName.NAME);
try {
resourceRemoteKey.set(resourceRestClient.read(resource).getProvision(AnyTypeKind.USER.name()).get().
getMapping().getConnObjectKeyItem().getExtAttrName());
} catch (Exception ex) {
LOG.error("While reading mapping for resource {}", resource, ex);
}
ConnObjectTOQuery.Builder builder = new ConnObjectTOQuery.Builder().size(SEARCH_SIZE);
if (StringUtils.isNotBlank(searchTerm)) {
builder.fiql(SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder().
is(resourceRemoteKey.get()).equalTo(searchTerm + "*").query()).build();
}
Pair<String, List<ConnObjectTO>> items = resourceRestClient.searchConnObjects(resource,
AnyTypeKind.USER.name(),
builder,
new SortParam<>(resourceRemoteKey.get(), true));
connObjectKeyFieldValues = items.getRight().stream().
map(item -> item.getAttr(resourceRemoteKey.get()).get().getValues().get(0)).
collect(Collectors.toList());
ajaxTextFieldPanel.setChoices(connObjectKeyFieldValues);
}
}