1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.client.console.status;
20
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.stream.Collectors;
25 import org.apache.commons.lang3.tuple.Pair;
26 import org.apache.syncope.client.console.commons.DirectoryDataProvider;
27 import org.apache.syncope.client.console.commons.IdMConstants;
28 import org.apache.syncope.client.console.commons.status.AbstractStatusBeanProvider;
29 import org.apache.syncope.client.console.panels.AjaxDataTablePanel;
30 import org.apache.syncope.client.console.panels.DirectoryPanel;
31 import org.apache.syncope.client.console.panels.LinkedAccountsStatusModalPanel;
32 import org.apache.syncope.client.console.panels.MultilevelPanel;
33 import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
34 import org.apache.syncope.client.console.rest.AnyObjectRestClient;
35 import org.apache.syncope.client.console.rest.GroupRestClient;
36 import org.apache.syncope.client.console.rest.ResourceRestClient;
37 import org.apache.syncope.client.console.rest.UserRestClient;
38 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
39 import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
40 import org.apache.syncope.client.ui.commons.Constants;
41 import org.apache.syncope.client.ui.commons.panels.ModalPanel;
42 import org.apache.syncope.client.ui.commons.status.Status;
43 import org.apache.syncope.client.ui.commons.status.StatusBean;
44 import org.apache.syncope.client.ui.commons.status.StatusUtils;
45 import org.apache.syncope.common.lib.to.AnyObjectTO;
46 import org.apache.syncope.common.lib.to.AnyTO;
47 import org.apache.syncope.common.lib.to.GroupTO;
48 import org.apache.syncope.common.lib.to.PullTaskTO;
49 import org.apache.syncope.common.lib.to.PushTaskTO;
50 import org.apache.syncope.common.lib.to.ReconStatus;
51 import org.apache.syncope.common.lib.to.ResourceTO;
52 import org.apache.syncope.common.lib.to.UserTO;
53 import org.apache.syncope.common.lib.types.AnyTypeKind;
54 import org.apache.syncope.common.lib.types.IdMEntitlement;
55 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
56 import org.apache.wicket.PageReference;
57 import org.apache.wicket.ajax.AjaxRequestTarget;
58 import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
59 import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
60 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
61 import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
62 import org.apache.wicket.markup.ComponentTag;
63 import org.apache.wicket.markup.html.basic.Label;
64 import org.apache.wicket.markup.repeater.Item;
65 import org.apache.wicket.model.IModel;
66 import org.apache.wicket.model.Model;
67 import org.apache.wicket.model.StringResourceModel;
68 import org.apache.wicket.spring.injection.annot.SpringBean;
69
70 public class AnyStatusDirectoryPanel
71 extends DirectoryPanel<StatusBean, StatusBean, DirectoryDataProvider<StatusBean>, AbstractAnyRestClient<?>>
72 implements ModalPanel {
73
74 private static final long serialVersionUID = -9148734710505211261L;
75
76 @SpringBean
77 protected ResourceRestClient resourceRestClient;
78
79 @SpringBean
80 protected ReconStatusUtils reconStatusUtils;
81
82 @SpringBean
83 protected UserRestClient userRestClient;
84
85 @SpringBean
86 protected GroupRestClient groupRestClient;
87
88 @SpringBean
89 protected AnyObjectRestClient anyObjectRestClient;
90
91 protected final MultilevelPanel multiLevelPanelRef;
92
93 protected final AnyTO anyTO;
94
95 protected final AnyTypeKind anyTypeKind;
96
97 protected final boolean statusOnly;
98
99 private final List<String> resources;
100
101 public AnyStatusDirectoryPanel(
102 final MultilevelPanel multiLevelPanelRef,
103 final PageReference pageRef,
104 final AnyTO anyTO,
105 final String itemKeyFieldName,
106 final boolean statusOnly) {
107
108 super(MultilevelPanel.FIRST_LEVEL_ID, null, pageRef);
109 this.multiLevelPanelRef = multiLevelPanelRef;
110 this.statusOnly = statusOnly;
111 this.anyTO = anyTO;
112 this.itemKeyFieldName = itemKeyFieldName;
113
114 if (anyTO instanceof UserTO) {
115 this.restClient = userRestClient;
116 anyTypeKind = AnyTypeKind.USER;
117 } else if (anyTO instanceof GroupTO) {
118 this.restClient = groupRestClient;
119 anyTypeKind = AnyTypeKind.GROUP;
120 } else {
121 this.restClient = anyObjectRestClient;
122 anyTypeKind = AnyTypeKind.ANY_OBJECT;
123 }
124
125 resources = resourceRestClient.list().stream().
126 filter(resource -> resource.getProvision(anyTO.getType()).isPresent()).
127 map(ResourceTO::getKey).collect(Collectors.toList());
128
129 initResultTable();
130 }
131
132 @Override
133 protected void resultTableCustomChanges(final AjaxDataTablePanel.Builder<StatusBean, String> resultTableBuilder) {
134 resultTableBuilder.setMultiLevelPanel(multiLevelPanelRef);
135 }
136
137 @Override
138 protected List<IColumn<StatusBean, String>> getColumns() {
139 List<IColumn<StatusBean, String>> columns = new ArrayList<>();
140
141 columns.add(new AbstractColumn<>(
142 new StringResourceModel("resource", this), "resource") {
143
144 private static final long serialVersionUID = 2054811145491901166L;
145
146 @Override
147 public void populateItem(
148 final Item<ICellPopulator<StatusBean>> cellItem,
149 final String componentId,
150 final IModel<StatusBean> model) {
151
152 cellItem.add(new Label(componentId, model.getObject().getResource()) {
153
154 private static final long serialVersionUID = 8432079838783825801L;
155
156 @Override
157 protected void onComponentTag(final ComponentTag tag) {
158 if (anyTO.getResources().contains(model.getObject().getResource())
159 || Constants.SYNCOPE.equalsIgnoreCase(model.getObject().getResource())) {
160
161 super.onComponentTag(tag);
162 } else {
163 tag.put("style", "font-style: italic");
164 }
165 }
166 });
167 }
168 });
169
170 if (statusOnly) {
171 columns.add(new PropertyColumn<>(
172 new StringResourceModel("connObjectLink", this), "connObjectLink", "connObjectLink"));
173
174 columns.add(new AbstractColumn<>(new StringResourceModel("status", this)) {
175
176 private static final long serialVersionUID = -3503023501954863131L;
177
178 @Override
179 public void populateItem(
180 final Item<ICellPopulator<StatusBean>> cellItem,
181 final String componentId,
182 final IModel<StatusBean> model) {
183
184 if (model.getObject().isLinked()) {
185 cellItem.add(StatusUtils.getStatusImage(componentId, model.getObject().getStatus()));
186 } else {
187 cellItem.add(new Label(componentId, ""));
188 }
189 }
190 });
191 }
192
193 return columns;
194 }
195
196 @Override
197 public ActionsPanel<StatusBean> getActions(final IModel<StatusBean> model) {
198 final ActionsPanel<StatusBean> panel = super.getActions(model);
199
200 if (!Constants.SYNCOPE.equalsIgnoreCase(model.getObject().getResource())) {
201 panel.add(new ActionLink<>() {
202
203 private static final long serialVersionUID = -7978723352517770645L;
204
205 @Override
206 public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
207 multiLevelPanelRef.next(bean.getResource(),
208 new ReconStatusPanel(bean.getResource(), anyTO.getType(), anyTO.getKey()),
209 target);
210 target.add(multiLevelPanelRef);
211 AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
212 }
213 }, ActionLink.ActionType.VIEW, IdMEntitlement.RESOURCE_GET_CONNOBJECT);
214 }
215
216 if (!statusOnly) {
217 panel.add(new ActionLink<>() {
218
219 private static final long serialVersionUID = -7978723352517770645L;
220
221 @Override
222 public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
223 multiLevelPanelRef.next("PUSH " + bean.getResource(),
224 new ReconTaskPanel(
225 bean.getResource(),
226 new PushTaskTO(),
227 anyTO.getType(),
228 anyTO.getKey(),
229 true,
230 multiLevelPanelRef,
231 pageRef),
232 target);
233 target.add(multiLevelPanelRef);
234 AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
235 }
236 }, ActionLink.ActionType.RECONCILIATION_PUSH, IdRepoEntitlement.TASK_EXECUTE);
237
238 panel.add(new ActionLink<>() {
239
240 private static final long serialVersionUID = -7978723352517770645L;
241
242 @Override
243 public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
244 multiLevelPanelRef.next("PULL " + bean.getResource(),
245 new ReconTaskPanel(
246 bean.getResource(),
247 new PullTaskTO(),
248 anyTO.getType(),
249 anyTO.getKey(),
250 true,
251 multiLevelPanelRef,
252 pageRef),
253 target);
254 target.add(multiLevelPanelRef);
255 AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
256 }
257 }, ActionLink.ActionType.RECONCILIATION_PULL, IdRepoEntitlement.TASK_EXECUTE);
258 }
259
260 if (anyTO instanceof UserTO && !UserTO.class.cast(anyTO).getLinkedAccounts().isEmpty()) {
261 UserTO userTO = UserTO.class.cast(anyTO);
262
263 if (!userTO.getLinkedAccounts().isEmpty()
264 && userTO.getLinkedAccounts().stream().anyMatch(linkedAccountTO -> {
265 return linkedAccountTO.getResource().equals(model.getObject().getResource());
266 })) {
267
268 panel.add(new ActionLink<>() {
269
270 private static final long serialVersionUID = 5168094747477174155L;
271
272 @Override
273 public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
274 multiLevelPanelRef.next("ACCOUNTS",
275 new LinkedAccountsStatusModalPanel(Model.of(UserTO.class.cast(anyTO)), pageRef),
276 target);
277 target.add(multiLevelPanelRef);
278 AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
279 }
280 }, ActionLink.ActionType.MANAGE_ACCOUNTS,
281 String.format("%s,%s,%s", IdRepoEntitlement.USER_READ, IdRepoEntitlement.USER_UPDATE,
282 IdMEntitlement.RESOURCE_GET_CONNOBJECT));
283 }
284 }
285
286 return panel;
287 }
288
289 @Override
290 protected Collection<ActionLink.ActionType> getBatches() {
291 List<ActionLink.ActionType> batches = new ArrayList<>();
292 if (statusOnly) {
293 batches.add(ActionLink.ActionType.SUSPEND);
294 batches.add(ActionLink.ActionType.REACTIVATE);
295 } else {
296 batches.add(ActionLink.ActionType.UNLINK);
297 batches.add(ActionLink.ActionType.LINK);
298 batches.add(ActionLink.ActionType.DEPROVISION);
299 batches.add(ActionLink.ActionType.PROVISION);
300 batches.add(ActionLink.ActionType.ASSIGN);
301 batches.add(ActionLink.ActionType.UNASSIGN);
302 }
303 return batches;
304 }
305
306 @Override
307 protected AnyStatusProvider dataProvider() {
308 return new AnyStatusProvider(rows);
309 }
310
311 @Override
312 protected String paginatorRowsKey() {
313 return IdMConstants.PREF_RESOURCE_STATUS_PAGINATOR_ROWS;
314 }
315
316 protected class AnyStatusProvider extends AbstractStatusBeanProvider {
317
318 private static final long serialVersionUID = 4586969457669796621L;
319
320 AnyStatusProvider(final int paginatorRows) {
321 super(paginatorRows, "resource");
322 }
323
324 @Override
325 protected List<StatusBean> getStatusBeans(final long first, final long count) {
326
327 final AnyTO actual = restClient.read(anyTO.getKey());
328
329 List<StatusBean> statusBeans = actual.getResources().stream().map(resource -> {
330 List<Pair<String, ReconStatus>> statuses = List.of();
331 if (statusOnly) {
332 statuses = reconStatusUtils.getReconStatuses(anyTO.getType(), anyTO.getKey(), List.of(resource));
333 }
334
335 return StatusUtils.getStatusBean(actual,
336 resource,
337 statuses.isEmpty() ? null : statuses.get(0).getRight().getOnResource(),
338 actual instanceof GroupTO);
339 }).collect(Collectors.toList());
340
341 if (statusOnly) {
342 StatusBean syncope = new StatusBean(actual, Constants.SYNCOPE);
343 switch (anyTypeKind) {
344 case USER:
345 syncope.setConnObjectLink(((UserTO) actual).getUsername());
346 break;
347
348 case GROUP:
349 syncope.setConnObjectLink(((GroupTO) actual).getName());
350 break;
351
352 case ANY_OBJECT:
353 syncope.setConnObjectLink(((AnyObjectTO) actual).getName());
354 break;
355
356 default:
357 }
358
359 Status syncopeStatus = Status.UNDEFINED;
360 if (actual.getStatus() != null) {
361 try {
362 syncopeStatus = Status.valueOf(actual.getStatus().toUpperCase());
363 } catch (IllegalArgumentException e) {
364 LOG.warn("Unexpected status found: {}", actual.getStatus(), e);
365 }
366 }
367 syncope.setStatus(syncopeStatus);
368
369 statusBeans.sort(comparator);
370 statusBeans.add(0, syncope);
371 } else {
372 statusBeans.addAll(resources.stream().
373 filter(resource -> !actual.getResources().contains(resource)).
374 map(resource -> {
375 StatusBean statusBean = StatusUtils.getStatusBean(actual,
376 resource,
377 null,
378 actual instanceof GroupTO);
379 statusBean.setLinked(false);
380 return statusBean;
381 }).collect(Collectors.toList()));
382
383 statusBeans.sort(comparator);
384 }
385
386 return first == -1 && count == -1
387 ? statusBeans
388 : statusBeans.subList((int) first, (int) first + (int) count);
389 }
390 }
391 }