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.notifications;
20
21 import java.io.Serializable;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Optional;
26 import java.util.stream.Collectors;
27 import org.apache.commons.lang3.tuple.Pair;
28 import org.apache.syncope.client.console.SyncopeConsoleSession;
29 import org.apache.syncope.client.console.events.EventCategoryPanel;
30 import org.apache.syncope.client.console.panels.search.AbstractSearchPanel;
31 import org.apache.syncope.client.console.panels.search.AnyObjectSearchPanel;
32 import org.apache.syncope.client.console.panels.search.GroupSearchPanel;
33 import org.apache.syncope.client.console.panels.search.SearchClause;
34 import org.apache.syncope.client.console.panels.search.UserSearchPanel;
35 import org.apache.syncope.client.console.rest.AnyTypeRestClient;
36 import org.apache.syncope.client.console.rest.ImplementationRestClient;
37 import org.apache.syncope.client.console.rest.NotificationRestClient;
38 import org.apache.syncope.client.console.rest.SchemaRestClient;
39 import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
40 import org.apache.syncope.client.console.wicket.markup.html.form.MultiPanel;
41 import org.apache.syncope.client.console.wizards.BaseAjaxWizardBuilder;
42 import org.apache.syncope.client.ui.commons.Constants;
43 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
44 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
45 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
46 import org.apache.syncope.common.lib.SyncopeClientException;
47 import org.apache.syncope.common.lib.audit.EventCategory;
48 import org.apache.syncope.common.lib.to.AnyTypeTO;
49 import org.apache.syncope.common.lib.to.DerSchemaTO;
50 import org.apache.syncope.common.lib.to.ImplementationTO;
51 import org.apache.syncope.common.lib.to.MailTemplateTO;
52 import org.apache.syncope.common.lib.to.NotificationTO;
53 import org.apache.syncope.common.lib.to.PlainSchemaTO;
54 import org.apache.syncope.common.lib.to.VirSchemaTO;
55 import org.apache.syncope.common.lib.types.AnyTypeKind;
56 import org.apache.syncope.common.lib.types.IdRepoImplementationType;
57 import org.apache.syncope.common.lib.types.SchemaType;
58 import org.apache.syncope.common.lib.types.TraceLevel;
59 import org.apache.wicket.PageReference;
60 import org.apache.wicket.ajax.AjaxRequestTarget;
61 import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
62 import org.apache.wicket.extensions.wizard.WizardModel;
63 import org.apache.wicket.extensions.wizard.WizardStep;
64 import org.apache.wicket.markup.html.WebMarkupContainer;
65 import org.apache.wicket.markup.html.list.ListItem;
66 import org.apache.wicket.markup.html.panel.Panel;
67 import org.apache.wicket.model.IModel;
68 import org.apache.wicket.model.LoadableDetachableModel;
69 import org.apache.wicket.model.Model;
70 import org.apache.wicket.model.PropertyModel;
71 import org.apache.wicket.model.ResourceModel;
72 import org.apache.wicket.model.util.ListModel;
73 import org.apache.wicket.validation.validator.EmailAddressValidator;
74
75 public class NotificationWizardBuilder extends BaseAjaxWizardBuilder<NotificationWrapper> {
76
77 private static final long serialVersionUID = -1975312550059578553L;
78
79 protected final NotificationRestClient notificationRestClient;
80
81 protected final AnyTypeRestClient anyTypeRestClient;
82
83 protected final ImplementationRestClient implementationRestClient;
84
85 protected final SchemaRestClient schemaRestClient;
86
87 protected final IModel<List<EventCategory>> eventCategories;
88
89 public NotificationWizardBuilder(
90 final NotificationTO notificationTO,
91 final NotificationRestClient notificationRestClient,
92 final AnyTypeRestClient anyTypeRestClient,
93 final ImplementationRestClient implementationRestClient,
94 final SchemaRestClient schemaRestClient,
95 final IModel<List<EventCategory>> eventCategories,
96 final PageReference pageRef) {
97
98 super(new NotificationWrapper(notificationTO), pageRef);
99
100 this.notificationRestClient = notificationRestClient;
101 this.anyTypeRestClient = anyTypeRestClient;
102 this.implementationRestClient = implementationRestClient;
103 this.schemaRestClient = schemaRestClient;
104 this.eventCategories = eventCategories;
105 }
106
107 @Override
108 protected Serializable onApplyInternal(final NotificationWrapper modelObject) {
109 modelObject.fillRecipientConditions();
110 modelObject.fillAboutConditions();
111
112 final boolean createFlag = modelObject.getInnerObject().getKey() == null;
113 if (createFlag) {
114 notificationRestClient.create(modelObject.getInnerObject());
115 } else {
116 notificationRestClient.update(modelObject.getInnerObject());
117 }
118
119 return null;
120 }
121
122 @Override
123 protected WizardModel buildModelSteps(final NotificationWrapper modelObject, final WizardModel wizardModel) {
124 wizardModel.add(new Details(modelObject));
125 wizardModel.add(new Recipients(modelObject));
126 wizardModel.add(new Events(modelObject));
127 wizardModel.add(new Abouts(modelObject));
128 return wizardModel;
129 }
130
131 public class Details extends WizardStep {
132
133 private static final long serialVersionUID = -7709805590497687958L;
134
135 public Details(final NotificationWrapper modelObject) {
136 NotificationTO notificationTO = modelObject.getInnerObject();
137 boolean createFlag = notificationTO.getKey() == null;
138
139 AjaxTextFieldPanel sender = new AjaxTextFieldPanel("sender", getString("sender"),
140 new PropertyModel<>(notificationTO, "sender"));
141 sender.addRequiredLabel();
142 sender.addValidator(EmailAddressValidator.getInstance());
143 add(sender);
144
145 AjaxTextFieldPanel subject = new AjaxTextFieldPanel("subject", getString("subject"),
146 new PropertyModel<>(notificationTO, "subject"));
147 subject.addRequiredLabel();
148 add(subject);
149
150 AjaxDropDownChoicePanel<String> template = new AjaxDropDownChoicePanel<>(
151 "template", getString("template"),
152 new PropertyModel<>(notificationTO, "template"));
153 template.setChoices(notificationRestClient.listTemplates().stream().
154 map(MailTemplateTO::getKey).collect(Collectors.toList()));
155
156 template.addRequiredLabel();
157 add(template);
158
159 AjaxDropDownChoicePanel<TraceLevel> traceLevel = new AjaxDropDownChoicePanel<>(
160 "traceLevel", getString("traceLevel"),
161 new PropertyModel<>(notificationTO, "traceLevel"));
162 traceLevel.setChoices(List.of(TraceLevel.values()));
163 traceLevel.addRequiredLabel();
164 add(traceLevel);
165
166 final AjaxCheckBoxPanel isActive = new AjaxCheckBoxPanel("isActive",
167 getString("isActive"), new PropertyModel<>(notificationTO, "active"));
168 if (createFlag) {
169 isActive.getField().setDefaultModelObject(Boolean.TRUE);
170 }
171 add(isActive);
172 }
173
174 }
175
176 public class Events extends WizardStep {
177
178 private static final long serialVersionUID = -7709805590497687958L;
179
180 public Events(final NotificationWrapper modelObject) {
181 setTitleModel(new ResourceModel("events"));
182
183 add(new EventCategoryPanel(
184 "eventSelection",
185 eventCategories.getObject(),
186 new PropertyModel<>(modelObject.getInnerObject(), "events")) {
187
188 private static final long serialVersionUID = 6429053774964787735L;
189
190 @Override
191 protected List<String> getListAuthRoles() {
192 return List.of();
193 }
194
195 @Override
196 protected List<String> getChangeAuthRoles() {
197 return List.of();
198 }
199 });
200 }
201 }
202
203 public class About extends Panel {
204
205 private static final long serialVersionUID = -9149543787708482882L;
206
207 public About(final String id, final IModel<Pair<String, List<SearchClause>>> model) {
208 super(id, model);
209 setOutputMarkupId(true);
210
211 AjaxDropDownChoicePanel<String> type =
212 new AjaxDropDownChoicePanel<>("about", "anyType", new Model<>() {
213
214 private static final long serialVersionUID = -2350296434572623272L;
215
216 @Override
217 public String getObject() {
218 return model.getObject().getLeft();
219 }
220
221 @Override
222 public void setObject(final String object) {
223 model.setObject(Pair.of(object, model.getObject().getRight()));
224 }
225
226 });
227 type.setChoices(anyTypeRestClient.list());
228 type.addRequiredLabel();
229 add(type);
230
231 ListModel<SearchClause> clauseModel = new ListModel<>() {
232
233 private static final long serialVersionUID = 3769540249683319782L;
234
235 @Override
236 public List<SearchClause> getObject() {
237 return model.getObject().getRight();
238 }
239
240 @Override
241 public void setObject(final List<SearchClause> object) {
242 model.getObject().setValue(object);
243 }
244 };
245
246 WebMarkupContainer searchContainer = new WebMarkupContainer("search");
247 add(searchContainer.setOutputMarkupId(true));
248
249 searchContainer.add(getClauseBuilder(model.getObject().getLeft(), clauseModel).build("clauses"));
250
251 type.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
252
253 private static final long serialVersionUID = -1107858522700306810L;
254
255 @Override
256 protected void onUpdate(final AjaxRequestTarget target) {
257 clauseModel.getObject().clear();
258 searchContainer.addOrReplace(getClauseBuilder(type.getModelObject(), clauseModel).
259 build("clauses").setRenderBodyOnly(true));
260 target.add(searchContainer);
261 }
262 });
263 }
264
265 private AbstractSearchPanel.Builder<?> getClauseBuilder(
266 final String type, final ListModel<SearchClause> clauseModel) {
267
268 AbstractSearchPanel.Builder<?> clause;
269
270 switch (type) {
271 case "USER":
272 clause = new UserSearchPanel.Builder(clauseModel, pageRef);
273 break;
274
275 case "GROUP":
276 clause = new GroupSearchPanel.Builder(clauseModel, pageRef);
277 break;
278
279 default:
280 clause = new AnyObjectSearchPanel.Builder(type, clauseModel, pageRef);
281 }
282
283 return clause;
284 }
285 }
286
287 public class Abouts extends WizardStep {
288
289 private static final long serialVersionUID = -7709805590497687958L;
290
291 public Abouts(final NotificationWrapper modelObject) {
292 setTitleModel(new ResourceModel("about"));
293
294 WebMarkupContainer aboutContainer = new WebMarkupContainer("about");
295 aboutContainer.setOutputMarkupId(true);
296 add(aboutContainer);
297
298 IModel<List<Pair<String, List<SearchClause>>>> model = new PropertyModel<>(modelObject, "aboutClauses");
299
300 aboutContainer.add(new MultiPanel<>("abouts", "abouts", model) {
301
302 private static final long serialVersionUID = -2481579077338205547L;
303
304 @Override
305 protected Pair<String, List<SearchClause>> newModelObject() {
306 return Pair.<String, List<SearchClause>>of(AnyTypeKind.USER.name(), new ArrayList<>());
307 }
308
309 @Override
310 protected About getItemPanel(final ListItem<Pair<String, List<SearchClause>>> item) {
311
312 return new About("panel", new Model<>() {
313
314 private static final long serialVersionUID = 6799404673615637845L;
315
316 @Override
317 public Pair<String, List<SearchClause>> getObject() {
318 return item.getModelObject();
319 }
320
321 @Override
322 public void setObject(final Pair<String, List<SearchClause>> object) {
323 item.setModelObject(object);
324 }
325
326 @Override
327 public void detach() {
328
329 }
330 });
331 }
332
333 @Override
334 protected void sendError(final String message) {
335 SyncopeConsoleSession.get().error(getString(Constants.OPERATION_ERROR));
336 }
337 }.hideLabel());
338 }
339 }
340
341 public class Recipients extends WizardStep {
342
343 private static final long serialVersionUID = -7709805590497687958L;
344
345 private final IModel<List<String>> recipientProviders = new LoadableDetachableModel<>() {
346
347 private static final long serialVersionUID = 5275935387613157447L;
348
349 @Override
350 protected List<String> load() {
351 return implementationRestClient.list(IdRepoImplementationType.RECIPIENTS_PROVIDER).stream().
352 map(ImplementationTO::getKey).sorted().collect(Collectors.toList());
353 }
354 };
355
356 public Recipients(final NotificationWrapper modelObject) {
357 setTitleModel(new ResourceModel("recipients"));
358
359 NotificationTO notificationTO = modelObject.getInnerObject();
360
361 AjaxTextFieldPanel recipientAttrName = new AjaxTextFieldPanel(
362 "recipientAttrName", new ResourceModel("recipientAttrName", "recipientAttrName").getObject(),
363 new PropertyModel<>(notificationTO, "recipientAttrName"));
364 recipientAttrName.setChoices(getSchemas());
365 recipientAttrName.addRequiredLabel();
366 recipientAttrName.setTitle(getString("intAttrNameInfo.help")
367 + "<code>groups[groupName].attribute</code>, "
368 + "<code>users[userName].attribute</code>, "
369 + "<code>anyObjects[anyObjectName].attribute</code>, "
370 + "<code>relationships[relationshipType][anyType].attribute</code> or "
371 + "<code>memberships[groupName].attribute</code> or "
372 + "<code>privileges[applicationKey]</code>", true);
373 add(recipientAttrName);
374
375 AjaxTextFieldPanel staticRecipientsFieldPanel =
376 new AjaxTextFieldPanel("panel", "staticRecipients", new Model<>());
377 staticRecipientsFieldPanel.addValidator(EmailAddressValidator.getInstance());
378 add(new MultiFieldPanel.Builder<>(
379 new PropertyModel<List<String>>(notificationTO, "staticRecipients")).
380 build("staticRecipients", "staticRecipients", staticRecipientsFieldPanel).hideLabel());
381
382 add(new UserSearchPanel.Builder(
383 new PropertyModel<>(modelObject, "recipientClauses"), pageRef).
384 required(false).build("recipients"));
385
386 AjaxDropDownChoicePanel<String> recipientsProvider = new AjaxDropDownChoicePanel<>(
387 "recipientsProvider", "recipientsProvider",
388 new PropertyModel<>(notificationTO, "recipientsProvider"), false);
389 recipientsProvider.setChoices(recipientProviders.getObject());
390 add(recipientsProvider);
391
392 AjaxCheckBoxPanel selfAsRecipient = new AjaxCheckBoxPanel("selfAsRecipient",
393 getString("selfAsRecipient"), new PropertyModel<>(notificationTO, "selfAsRecipient"));
394 if (notificationTO.getKey() == null) {
395 selfAsRecipient.getField().setDefaultModelObject(Boolean.FALSE);
396 }
397 add(selfAsRecipient);
398 }
399 }
400
401 protected List<String> getSchemas() {
402 AnyTypeTO type = null;
403 try {
404 type = anyTypeRestClient.read(AnyTypeKind.USER.name());
405 } catch (SyncopeClientException e) {
406 LOG.error("While reading all any types", e);
407 }
408
409 String[] anyTypeClasses = Optional.ofNullable(type).
410 map(anyTypeTO -> anyTypeTO.getClasses().toArray(String[]::new)).orElseGet(() -> new String[0]);
411
412 List<String> result = new ArrayList<>();
413 result.add(Constants.USERNAME_FIELD_NAME);
414
415 result.addAll(schemaRestClient.<PlainSchemaTO>getSchemas(SchemaType.PLAIN, null, anyTypeClasses).
416 stream().map(PlainSchemaTO::getKey).collect(Collectors.toList()));
417 result.addAll(schemaRestClient.<DerSchemaTO>getSchemas(SchemaType.DERIVED, null, anyTypeClasses).
418 stream().map(DerSchemaTO::getKey).collect(Collectors.toList()));
419 result.addAll(schemaRestClient.<VirSchemaTO>getSchemas(SchemaType.VIRTUAL, null, anyTypeClasses).
420 stream().map(VirSchemaTO::getKey).collect(Collectors.toList()));
421
422 Collections.sort(result);
423 return result;
424 }
425 }