blob: 29796bae8bc0543cef3b24dddf3eb4cad62443b5 [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.status;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.client.ui.commons.Constants;
import org.apache.syncope.client.ui.commons.DirectoryDataProvider;
import org.apache.syncope.client.console.commons.IdMConstants;
import org.apache.syncope.client.console.commons.status.AbstractStatusBeanProvider;
import org.apache.syncope.client.ui.commons.status.Status;
import org.apache.syncope.client.ui.commons.status.StatusBean;
import org.apache.syncope.client.ui.commons.status.StatusUtils;
import org.apache.syncope.client.console.panels.DirectoryPanel;
import org.apache.syncope.client.console.panels.AjaxDataTablePanel;
import org.apache.syncope.client.console.panels.LinkedAccountsStatusModalPanel;
import org.apache.syncope.client.console.panels.MultilevelPanel;
import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
import org.apache.syncope.client.console.rest.AnyObjectRestClient;
import org.apache.syncope.client.console.rest.GroupRestClient;
import org.apache.syncope.client.console.rest.ResourceRestClient;
import org.apache.syncope.client.console.rest.UserRestClient;
import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
import org.apache.syncope.client.ui.commons.panels.ModalPanel;
import org.apache.syncope.common.lib.to.AnyObjectTO;
import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.to.EntityTO;
import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.to.ReconStatus;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IdMEntitlement;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.StringResourceModel;
public class AnyStatusDirectoryPanel
extends DirectoryPanel<StatusBean, StatusBean, DirectoryDataProvider<StatusBean>, AbstractAnyRestClient<?>>
implements ModalPanel {
private static final long serialVersionUID = -9148734710505211261L;
private final BaseModal<?> baseModal;
private final MultilevelPanel multiLevelPanelRef;
private final AnyTO anyTO;
private final AnyTypeKind anyTypeKind;
private final boolean statusOnly;
private final List<String> resources;
public AnyStatusDirectoryPanel(
final BaseModal<?> baseModal,
final MultilevelPanel multiLevelPanelRef,
final PageReference pageRef,
final AnyTO anyTO,
final String itemKeyFieldName,
final boolean statusOnly) {
super(MultilevelPanel.FIRST_LEVEL_ID, pageRef);
this.baseModal = baseModal;
this.multiLevelPanelRef = multiLevelPanelRef;
this.statusOnly = statusOnly;
this.anyTO = anyTO;
this.itemKeyFieldName = itemKeyFieldName;
if (anyTO instanceof UserTO) {
this.restClient = new UserRestClient();
anyTypeKind = AnyTypeKind.USER;
} else if (anyTO instanceof GroupTO) {
this.restClient = new GroupRestClient();
anyTypeKind = AnyTypeKind.GROUP;
} else {
this.restClient = new AnyObjectRestClient();
anyTypeKind = AnyTypeKind.ANY_OBJECT;
}
resources = ResourceRestClient.list().stream().
filter(resource -> resource.getProvision(anyTO.getType()).isPresent()).
map(EntityTO::getKey).collect(Collectors.toList());
initResultTable();
}
@Override
protected void resultTableCustomChanges(final AjaxDataTablePanel.Builder<StatusBean, String> resultTableBuilder) {
resultTableBuilder.setMultiLevelPanel(baseModal, multiLevelPanelRef);
}
@Override
protected List<IColumn<StatusBean, String>> getColumns() {
final List<IColumn<StatusBean, String>> columns = new ArrayList<>();
columns.add(new AbstractColumn<>(
new StringResourceModel("resource", this), "resource") {
private static final long serialVersionUID = 2054811145491901166L;
@Override
public void populateItem(
final Item<ICellPopulator<StatusBean>> cellItem,
final String componentId,
final IModel<StatusBean> model) {
cellItem.add(new Label(componentId, model.getObject().getResource()) {
private static final long serialVersionUID = 8432079838783825801L;
@Override
protected void onComponentTag(final ComponentTag tag) {
if (anyTO.getResources().contains(model.getObject().getResource())
|| Constants.SYNCOPE.equalsIgnoreCase(model.getObject().getResource())) {
super.onComponentTag(tag);
} else {
tag.put("style", "font-style: italic");
}
}
});
}
});
if (statusOnly) {
columns.add(new PropertyColumn<>(
new StringResourceModel("connObjectLink", this), "connObjectLink", "connObjectLink"));
columns.add(new AbstractColumn<>(new StringResourceModel("status", this)) {
private static final long serialVersionUID = -3503023501954863131L;
@Override
public void populateItem(
final Item<ICellPopulator<StatusBean>> cellItem,
final String componentId,
final IModel<StatusBean> model) {
if (model.getObject().isLinked()) {
cellItem.add(StatusUtils.getStatusImage(componentId, model.getObject().getStatus()));
} else {
cellItem.add(new Label(componentId, ""));
}
}
});
}
return columns;
}
@Override
public ActionsPanel<StatusBean> getActions(final IModel<StatusBean> model) {
final ActionsPanel<StatusBean> panel = super.getActions(model);
if (!Constants.SYNCOPE.equalsIgnoreCase(model.getObject().getResource())) {
panel.add(new ActionLink<>() {
private static final long serialVersionUID = -7978723352517770645L;
@Override
public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
multiLevelPanelRef.next(bean.getResource(),
new ReconStatusPanel(bean.getResource(), anyTO.getType(), anyTO.getKey()),
target);
target.add(multiLevelPanelRef);
AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
}
}, ActionLink.ActionType.VIEW, IdMEntitlement.RESOURCE_GET_CONNOBJECT);
}
if (!statusOnly) {
panel.add(new ActionLink<>() {
private static final long serialVersionUID = -7978723352517770645L;
@Override
public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
multiLevelPanelRef.next("PUSH " + bean.getResource(),
new ReconTaskPanel(
bean.getResource(),
new PushTaskTO(),
anyTO.getType(),
anyTO.getKey(),
true,
multiLevelPanelRef,
pageRef),
target);
target.add(multiLevelPanelRef);
AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
}
}, ActionLink.ActionType.RECONCILIATION_PUSH, IdRepoEntitlement.TASK_EXECUTE);
panel.add(new ActionLink<>() {
private static final long serialVersionUID = -7978723352517770645L;
@Override
public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
multiLevelPanelRef.next("PULL " + bean.getResource(),
new ReconTaskPanel(
bean.getResource(),
new PullTaskTO(),
anyTO.getType(),
anyTO.getKey(),
true,
multiLevelPanelRef,
pageRef),
target);
target.add(multiLevelPanelRef);
AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
}
}, ActionLink.ActionType.RECONCILIATION_PULL, IdRepoEntitlement.TASK_EXECUTE);
}
if (anyTO instanceof UserTO && !UserTO.class.cast(anyTO).getLinkedAccounts().isEmpty()) {
UserTO userTO = UserTO.class.cast(anyTO);
if (!userTO.getLinkedAccounts().isEmpty()
&& userTO.getLinkedAccounts().stream().anyMatch(linkedAccountTO -> {
return linkedAccountTO.getResource().equals(model.getObject().getResource());
})) {
panel.add(new ActionLink<>() {
private static final long serialVersionUID = 5168094747477174155L;
@Override
public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
multiLevelPanelRef.next("ACCOUNTS",
new LinkedAccountsStatusModalPanel(Model.of(UserTO.class.cast(anyTO)), pageRef),
target);
target.add(multiLevelPanelRef);
AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
}
}, ActionLink.ActionType.MANAGE_ACCOUNTS,
String.format("%s,%s,%s", IdRepoEntitlement.USER_READ, IdRepoEntitlement.USER_UPDATE,
IdMEntitlement.RESOURCE_GET_CONNOBJECT));
}
}
return panel;
}
@Override
protected Collection<ActionLink.ActionType> getBatches() {
List<ActionLink.ActionType> batches = new ArrayList<>();
if (statusOnly) {
batches.add(ActionLink.ActionType.SUSPEND);
batches.add(ActionLink.ActionType.REACTIVATE);
} else {
batches.add(ActionLink.ActionType.UNLINK);
batches.add(ActionLink.ActionType.LINK);
batches.add(ActionLink.ActionType.DEPROVISION);
batches.add(ActionLink.ActionType.PROVISION);
batches.add(ActionLink.ActionType.ASSIGN);
batches.add(ActionLink.ActionType.UNASSIGN);
}
return batches;
}
@Override
protected AnyStatusProvider dataProvider() {
return new AnyStatusProvider(rows);
}
@Override
protected String paginatorRowsKey() {
return IdMConstants.PREF_RESOURCE_STATUS_PAGINATOR_ROWS;
}
protected class AnyStatusProvider extends AbstractStatusBeanProvider {
private static final long serialVersionUID = 4586969457669796621L;
AnyStatusProvider(final int paginatorRows) {
super(paginatorRows, "resource");
}
@Override
protected List<StatusBean> getStatusBeans(final long first, final long count) {
// this is required to retrieve updated data by reloading table
final AnyTO actual = restClient.read(anyTO.getKey());
List<StatusBean> statusBeans = actual.getResources().stream().map(resource -> {
List<Pair<String, ReconStatus>> statuses = List.of();
if (statusOnly) {
statuses = ReconStatusUtils.getReconStatuses(anyTO.getType(), anyTO.getKey(), List.of(resource));
}
return StatusUtils.getStatusBean(actual,
resource,
statuses.isEmpty() ? null : statuses.get(0).getRight().getOnResource(),
actual instanceof GroupTO);
}).collect(Collectors.toList());
if (statusOnly) {
StatusBean syncope = new StatusBean(actual, Constants.SYNCOPE);
switch (anyTypeKind) {
case USER:
syncope.setConnObjectLink(((UserTO) actual).getUsername());
break;
case GROUP:
syncope.setConnObjectLink(((GroupTO) actual).getName());
break;
case ANY_OBJECT:
syncope.setConnObjectLink(((AnyObjectTO) actual).getName());
break;
default:
}
Status syncopeStatus = Status.UNDEFINED;
if (actual.getStatus() != null) {
try {
syncopeStatus = Status.valueOf(actual.getStatus().toUpperCase());
} catch (IllegalArgumentException e) {
LOG.warn("Unexpected status found: {}", actual.getStatus(), e);
}
}
syncope.setStatus(syncopeStatus);
statusBeans.sort(comparator);
statusBeans.add(0, syncope);
} else {
statusBeans.addAll(resources.stream().
filter(resource -> !actual.getResources().contains(resource)).
map(resource -> {
StatusBean statusBean = StatusUtils.getStatusBean(actual,
resource,
null,
actual instanceof GroupTO);
statusBean.setLinked(false);
return statusBean;
}).collect(Collectors.toList()));
statusBeans.sort(comparator);
}
return first == -1 && count == -1
? statusBeans
: statusBeans.subList((int) first, (int) first + (int) count);
}
}
}