blob: ae38a10c905e925f183a328715d078eec31fe34a [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.notifications;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.events.EventCategoryPanel;
import org.apache.syncope.client.console.panels.search.AbstractSearchPanel;
import org.apache.syncope.client.console.panels.search.AnyObjectSearchPanel;
import org.apache.syncope.client.console.panels.search.GroupSearchPanel;
import org.apache.syncope.client.console.panels.search.SearchClause;
import org.apache.syncope.client.console.panels.search.UserSearchPanel;
import org.apache.syncope.client.console.rest.AnyTypeRestClient;
import org.apache.syncope.client.console.rest.ImplementationRestClient;
import org.apache.syncope.client.console.rest.LoggerRestClient;
import org.apache.syncope.client.console.rest.NotificationRestClient;
import org.apache.syncope.client.console.rest.SchemaRestClient;
import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.MultiPanel;
import org.apache.syncope.client.console.wizards.BaseAjaxWizardBuilder;
import org.apache.syncope.client.ui.commons.Constants;
import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
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.SyncopeClientException;
import org.apache.syncope.common.lib.to.AnyTypeTO;
import org.apache.syncope.common.lib.to.DerSchemaTO;
import org.apache.syncope.common.lib.to.EntityTO;
import org.apache.syncope.common.lib.to.NotificationTO;
import org.apache.syncope.common.lib.to.PlainSchemaTO;
import org.apache.syncope.common.lib.to.VirSchemaTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IdRepoImplementationType;
import org.apache.syncope.common.lib.types.SchemaType;
import org.apache.syncope.common.lib.types.TraceLevel;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.extensions.wizard.WizardModel;
import org.apache.wicket.extensions.wizard.WizardStep;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.model.util.ListModel;
import org.apache.wicket.validation.validator.EmailAddressValidator;
public class NotificationWizardBuilder extends BaseAjaxWizardBuilder<NotificationWrapper> {
private static final long serialVersionUID = -1975312550059578553L;
private final NotificationRestClient restClient = new NotificationRestClient();
/**
* Construct.
*
* @param notificationTO notification.
* @param pageRef Caller page reference.
*/
public NotificationWizardBuilder(final NotificationTO notificationTO, final PageReference pageRef) {
super(new NotificationWrapper(notificationTO), pageRef);
}
@Override
protected Serializable onApplyInternal(final NotificationWrapper modelObject) {
modelObject.fillRecipientConditions();
modelObject.fillAboutConditions();
final boolean createFlag = modelObject.getInnerObject().getKey() == null;
if (createFlag) {
NotificationRestClient.create(modelObject.getInnerObject());
} else {
NotificationRestClient.update(modelObject.getInnerObject());
}
return null;
}
@Override
protected WizardModel buildModelSteps(final NotificationWrapper modelObject, final WizardModel wizardModel) {
wizardModel.add(new Details(modelObject));
wizardModel.add(new Recipients(modelObject));
wizardModel.add(new Events(modelObject));
wizardModel.add(new Abouts(modelObject));
return wizardModel;
}
public class Details extends WizardStep {
private static final long serialVersionUID = -7709805590497687958L;
public Details(final NotificationWrapper modelObject) {
NotificationTO notificationTO = modelObject.getInnerObject();
boolean createFlag = notificationTO.getKey() == null;
AjaxTextFieldPanel sender = new AjaxTextFieldPanel("sender", getString("sender"),
new PropertyModel<>(notificationTO, "sender"));
sender.addRequiredLabel();
sender.addValidator(EmailAddressValidator.getInstance());
add(sender);
AjaxTextFieldPanel subject = new AjaxTextFieldPanel("subject", getString("subject"),
new PropertyModel<>(notificationTO, "subject"));
subject.addRequiredLabel();
add(subject);
AjaxDropDownChoicePanel<String> template = new AjaxDropDownChoicePanel<>(
"template", getString("template"),
new PropertyModel<>(notificationTO, "template"));
template.setChoices(restClient.listTemplates().stream().
map(EntityTO::getKey).collect(Collectors.toList()));
template.addRequiredLabel();
add(template);
AjaxDropDownChoicePanel<TraceLevel> traceLevel = new AjaxDropDownChoicePanel<>(
"traceLevel", getString("traceLevel"),
new PropertyModel<>(notificationTO, "traceLevel"));
traceLevel.setChoices(List.of(TraceLevel.values()));
traceLevel.addRequiredLabel();
add(traceLevel);
final AjaxCheckBoxPanel isActive = new AjaxCheckBoxPanel("isActive",
getString("isActive"), new PropertyModel<>(notificationTO, "active"));
if (createFlag) {
isActive.getField().setDefaultModelObject(Boolean.TRUE);
}
add(isActive);
}
}
public static class Events extends WizardStep {
private static final long serialVersionUID = -7709805590497687958L;
public Events(final NotificationWrapper modelObject) {
setTitleModel(new ResourceModel("events"));
add(new EventCategoryPanel(
"eventSelection",
LoggerRestClient.listEvents(),
new PropertyModel<List<String>>(modelObject.getInnerObject(), "events")) {
private static final long serialVersionUID = 6429053774964787735L;
@Override
protected List<String> getListAuthRoles() {
return List.of();
}
@Override
protected List<String> getChangeAuthRoles() {
return List.of();
}
});
}
}
public static class About extends Panel {
private static final long serialVersionUID = -9149543787708482882L;
public About(final String id, final IModel<Pair<String, List<SearchClause>>> model) {
super(id, model);
setOutputMarkupId(true);
AjaxDropDownChoicePanel<String> type =
new AjaxDropDownChoicePanel<>("about", "anyType", new Model<String>() {
private static final long serialVersionUID = -2350296434572623272L;
@Override
public String getObject() {
return model.getObject().getLeft();
}
@Override
public void setObject(final String object) {
model.setObject(Pair.of(object, model.getObject().getRight()));
}
});
type.setChoices(AnyTypeRestClient.list());
type.addRequiredLabel();
add(type);
ListModel<SearchClause> clauseModel = new ListModel<SearchClause>() {
private static final long serialVersionUID = 3769540249683319782L;
@Override
public List<SearchClause> getObject() {
return model.getObject().getRight();
}
@Override
public void setObject(final List<SearchClause> object) {
model.getObject().setValue(object);
}
};
WebMarkupContainer searchContainer = new WebMarkupContainer("search");
add(searchContainer.setOutputMarkupId(true));
searchContainer.add(getClauseBuilder(model.getObject().getLeft(), clauseModel).build("clauses"));
type.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
private static final long serialVersionUID = -1107858522700306810L;
@Override
protected void onUpdate(final AjaxRequestTarget target) {
clauseModel.getObject().clear();
searchContainer.addOrReplace(getClauseBuilder(type.getModelObject(), clauseModel).
build("clauses").setRenderBodyOnly(true));
target.add(searchContainer);
}
});
}
private AbstractSearchPanel.Builder<?> getClauseBuilder(
final String type, final ListModel<SearchClause> clauseModel) {
AbstractSearchPanel.Builder<?> clause;
switch (type) {
case "USER":
clause = new UserSearchPanel.Builder(clauseModel);
break;
case "GROUP":
clause = new GroupSearchPanel.Builder(clauseModel);
break;
default:
clause = new AnyObjectSearchPanel.Builder(type, clauseModel);
}
return clause;
}
}
public class Abouts extends WizardStep {
private static final long serialVersionUID = -7709805590497687958L;
public Abouts(final NotificationWrapper modelObject) {
setTitleModel(new ResourceModel("about"));
WebMarkupContainer aboutContainer = new WebMarkupContainer("about");
aboutContainer.setOutputMarkupId(true);
add(aboutContainer);
IModel<List<Pair<String, List<SearchClause>>>> model = new PropertyModel<>(modelObject, "aboutClauses");
aboutContainer.add(new MultiPanel<Pair<String, List<SearchClause>>>("abouts", "abouts", model) {
private static final long serialVersionUID = -2481579077338205547L;
@Override
protected Pair<String, List<SearchClause>> newModelObject() {
return Pair.<String, List<SearchClause>>of(AnyTypeKind.USER.name(), new ArrayList<>());
}
@Override
protected About getItemPanel(final ListItem<Pair<String, List<SearchClause>>> item) {
return new About("panel", new Model<Pair<String, List<SearchClause>>>() {
private static final long serialVersionUID = 6799404673615637845L;
@Override
public Pair<String, List<SearchClause>> getObject() {
return item.getModelObject();
}
@Override
public void setObject(final Pair<String, List<SearchClause>> object) {
item.setModelObject(object);
}
@Override
public void detach() {
// no detach
}
});
}
@Override
protected void sendError(final String message) {
SyncopeConsoleSession.get().error(getString(Constants.OPERATION_ERROR));
}
}.hideLabel());
}
}
public static class Recipients extends WizardStep {
private static final long serialVersionUID = -7709805590497687958L;
private final IModel<List<String>> recipientProviders = new LoadableDetachableModel<List<String>>() {
private static final long serialVersionUID = 5275935387613157447L;
@Override
protected List<String> load() {
return ImplementationRestClient.list(IdRepoImplementationType.RECIPIENTS_PROVIDER).stream().
map(EntityTO::getKey).sorted().collect(Collectors.toList());
}
};
public Recipients(final NotificationWrapper modelObject) {
setTitleModel(new ResourceModel("recipients"));
NotificationTO notificationTO = modelObject.getInnerObject();
AjaxTextFieldPanel recipientAttrName = new AjaxTextFieldPanel(
"recipientAttrName", new ResourceModel("recipientAttrName", "recipientAttrName").getObject(),
new PropertyModel<>(notificationTO, "recipientAttrName"));
recipientAttrName.setChoices(getSchemas());
recipientAttrName.addRequiredLabel();
recipientAttrName.setTitle(getString("intAttrNameInfo.help")
+ "<code>groups[groupName].attribute</code>, "
+ "<code>users[userName].attribute</code>, "
+ "<code>anyObjects[anyObjectName].attribute</code>, "
+ "<code>relationships[relationshipType][anyType].attribute</code> or "
+ "<code>memberships[groupName].attribute</code> or "
+ "<code>privileges[applicationKey]</code>", true);
add(recipientAttrName);
AjaxTextFieldPanel staticRecipientsFieldPanel =
new AjaxTextFieldPanel("panel", "staticRecipients", new Model<>());
staticRecipientsFieldPanel.addValidator(EmailAddressValidator.getInstance());
add(new MultiFieldPanel.Builder<>(
new PropertyModel<List<String>>(notificationTO, "staticRecipients")).
build("staticRecipients", "staticRecipients", staticRecipientsFieldPanel).hideLabel());
add(new UserSearchPanel.Builder(
new PropertyModel<>(modelObject, "recipientClauses")).
required(false).build("recipients"));
AjaxDropDownChoicePanel<String> recipientsProvider = new AjaxDropDownChoicePanel<>(
"recipientsProvider", "recipientsProvider",
new PropertyModel<>(notificationTO, "recipientsProvider"), false);
recipientsProvider.setChoices(recipientProviders.getObject());
add(recipientsProvider);
AjaxCheckBoxPanel selfAsRecipient = new AjaxCheckBoxPanel("selfAsRecipient",
getString("selfAsRecipient"), new PropertyModel<>(notificationTO, "selfAsRecipient"));
if (notificationTO.getKey() == null) {
selfAsRecipient.getField().setDefaultModelObject(Boolean.FALSE);
}
add(selfAsRecipient);
}
}
private static List<String> getSchemas() {
AnyTypeTO type = null;
try {
type = AnyTypeRestClient.read(AnyTypeKind.USER.name());
} catch (SyncopeClientException e) {
LOG.error("While reading all any types", e);
}
String[] anyTypeClasses = Optional.ofNullable(type)
.map(anyTypeTO -> anyTypeTO.getClasses().toArray(new String[] {})).orElseGet(() -> new String[0]);
List<String> result = new ArrayList<>();
result.add(Constants.USERNAME_FIELD_NAME);
result.addAll(SchemaRestClient.<PlainSchemaTO>getSchemas(SchemaType.PLAIN, null, anyTypeClasses).
stream().map(EntityTO::getKey).collect(Collectors.toList()));
result.addAll(SchemaRestClient.<DerSchemaTO>getSchemas(SchemaType.DERIVED, null, anyTypeClasses).
stream().map(EntityTO::getKey).collect(Collectors.toList()));
result.addAll(SchemaRestClient.<VirSchemaTO>getSchemas(SchemaType.VIRTUAL, null, anyTypeClasses).
stream().map(EntityTO::getKey).collect(Collectors.toList()));
Collections.sort(result);
return result;
}
}