http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java new file mode 100644 index 0000000..aa3c3eb --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java @@ -0,0 +1,468 @@ +/* + * 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.panels; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.console.commons.Constants; +import org.apache.syncope.client.console.panels.SelectedEventsPanel.EventSelectionChanged; +import org.apache.syncope.client.console.panels.SelectedEventsPanel.InspectSelectedEvent; +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel; +import org.apache.syncope.common.lib.to.EventCategoryTO; +import org.apache.syncope.common.lib.types.AuditElements; +import org.apache.syncope.common.lib.types.AuditElements.EventCategoryType; +import org.apache.syncope.common.lib.types.AuditLoggerName; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; +import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; +import org.apache.wicket.event.Broadcast; +import org.apache.wicket.event.IEvent; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.IChoiceRenderer; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.ResourceModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class LoggerCategoryPanel extends Panel { + + /** + * Logger. + */ + private static final Logger LOG = LoggerFactory.getLogger(LoggerCategoryPanel.class); + + private static final long serialVersionUID = 6429053774964787734L; + + private final List<EventCategoryTO> eventCategoryTOs; + + private final EventCategoryTO eventCategoryTO = new EventCategoryTO(); + + private final WebMarkupContainer categoryContainer; + + private final WebMarkupContainer eventsContainer; + + private final SelectedEventsPanel selectedEventsPanel; + + private final AjaxDropDownChoicePanel<EventCategoryType> type; + + private final AjaxDropDownChoicePanel<String> category; + + private final AjaxDropDownChoicePanel<String> subcategory; + + private final AjaxTextFieldPanel custom; + + private final ActionLinksPanel actionPanel; + + private final IModel<List<String>> model; + + public LoggerCategoryPanel( + final String id, + final List<EventCategoryTO> eventCategoryTOs, + final IModel<List<String>> model, + final PageReference pageReference, + final String pageId) { + super(id); + + this.model = model; + selectedEventsPanel = new SelectedEventsPanel("selectedEventsPanel", model); + add(selectedEventsPanel); + + this.eventCategoryTOs = eventCategoryTOs; + + categoryContainer = new WebMarkupContainer("categoryContainer"); + categoryContainer.setOutputMarkupId(true); + add(categoryContainer); + + eventsContainer = new WebMarkupContainer("eventsContainer"); + eventsContainer.setOutputMarkupId(true); + add(eventsContainer); + + authorizeList(); + authorizeChanges(); + + categoryContainer.add(new Label("typeLabel", new ResourceModel("type", "type"))); + + type = new AjaxDropDownChoicePanel<EventCategoryType>( + "type", + "type", + new PropertyModel<EventCategoryType>(eventCategoryTO, "type"), + false); + type.setChoices(Arrays.asList(EventCategoryType.values())); + type.setStyleSheet("ui-widget-content ui-corner-all"); + type.setChoiceRenderer(new IChoiceRenderer<EventCategoryType>() { + + private static final long serialVersionUID = 2317134950949778735L; + + @Override + public String getDisplayValue(final EventCategoryType eventCategoryType) { + return eventCategoryType.name(); + } + + @Override + public String getIdValue(final EventCategoryType eventCategoryType, final int i) { + return eventCategoryType.name(); + } + }); + categoryContainer.add(type); + + type.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -1107858522700306810L; + + @Override + protected void onUpdate(final AjaxRequestTarget target) { + send(LoggerCategoryPanel.this, Broadcast.EXACT, new ChangeCategoryEvent(target, type)); + } + }); + + categoryContainer.add(new Label("categoryLabel", new ResourceModel("category", "category"))); + + category = new AjaxDropDownChoicePanel<String>( + "category", + "category", + new PropertyModel<String>(eventCategoryTO, "category"), + false); + category.setChoices(filter(eventCategoryTOs, type.getModelObject())); + category.setStyleSheet("ui-widget-content ui-corner-all"); + categoryContainer.add(category); + + category.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -1107858522700306811L; + + @Override + protected void onUpdate(final AjaxRequestTarget target) { + send(LoggerCategoryPanel.this, Broadcast.EXACT, new ChangeCategoryEvent(target, category)); + } + }); + + categoryContainer.add(new Label("subcategoryLabel", new ResourceModel("subcategory", "subcategory"))); + + subcategory = new AjaxDropDownChoicePanel<String>( + "subcategory", + "subcategory", + new PropertyModel<String>(eventCategoryTO, "subcategory"), + false); + subcategory.setChoices(filter(eventCategoryTOs, type.getModelObject(), category.getModelObject())); + subcategory.setStyleSheet("ui-widget-content ui-corner-all"); + categoryContainer.add(subcategory); + + subcategory.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -1107858522700306812L; + + @Override + protected void onUpdate(final AjaxRequestTarget target) { + send(LoggerCategoryPanel.this, Broadcast.EXACT, new ChangeCategoryEvent(target, subcategory)); + } + }); + + categoryContainer.add(new Label("customLabel", new ResourceModel("custom", "custom")).setVisible(false)); + + custom = new AjaxTextFieldPanel("custom", "custom", new Model<String>(null)); + custom.setStyleSheet("ui-widget-content ui-corner-all short_fixedsize"); + custom.setVisible(false); + custom.setEnabled(false); + + categoryContainer.add(custom); + + actionPanel = new ActionLinksPanel("customActions", new Model(), pageReference); + categoryContainer.add(actionPanel); + + actionPanel.add(new ActionLink() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target) { + if (StringUtils.isNotBlank(custom.getModelObject())) { + final Map.Entry<EventCategoryTO, AuditElements.Result> parsed = + AuditLoggerName.parseEventCategory(custom.getModelObject()); + + final String eventString = AuditLoggerName.buildEvent( + parsed.getKey().getType(), + null, + null, + parsed.getKey().getEvents().isEmpty() + ? StringUtils.EMPTY : parsed.getKey().getEvents().iterator().next(), + parsed.getValue()); + + custom.setModelObject(StringUtils.EMPTY); + send(LoggerCategoryPanel.this.getPage(), Broadcast.BREADTH, new EventSelectionChanged( + target, + Collections.<String>singleton(eventString), + Collections.<String>emptySet())); + target.add(categoryContainer); + } + } + }, ActionLink.ActionType.CREATE, pageId, true); + + actionPanel.add(new ActionLink() { + + private static final long serialVersionUID = -3722207913631435502L; + + @Override + public void onClick(AjaxRequestTarget target) { + if (StringUtils.isNotBlank(custom.getModelObject())) { + final Map.Entry<EventCategoryTO, AuditElements.Result> parsed = + AuditLoggerName.parseEventCategory(custom.getModelObject()); + + final String eventString = AuditLoggerName.buildEvent( + parsed.getKey().getType(), + null, + null, + parsed.getKey().getEvents().isEmpty() + ? StringUtils.EMPTY : parsed.getKey().getEvents().iterator().next(), + parsed.getValue()); + + custom.setModelObject(StringUtils.EMPTY); + send(LoggerCategoryPanel.this.getPage(), Broadcast.BREADTH, new EventSelectionChanged( + target, + Collections.<String>emptySet(), + Collections.<String>singleton(eventString))); + target.add(categoryContainer); + } + } + }, ActionLink.ActionType.DELETE, pageId, true); + + actionPanel.setVisible(false); + actionPanel.setEnabled(false); + + eventsContainer.add(new EventSelectionPanel("eventsPanel", eventCategoryTO, model) { + + private static final long serialVersionUID = 3513194801190026082L; + + @Override + protected void onEventAction(final IEvent<?> event) { + LoggerCategoryPanel.this.onEventAction(event); + } + }); + } + + private List<String> filter( + final List<EventCategoryTO> eventCategoryTOs, final EventCategoryType type) { + final Set<String> res = new HashSet<String>(); + + for (EventCategoryTO eventCategory : eventCategoryTOs) { + if (type == eventCategory.getType() && StringUtils.isNotEmpty(eventCategory.getCategory())) { + res.add(eventCategory.getCategory()); + } + } + + final List<String> filtered = new ArrayList<String>(res); + Collections.sort(filtered); + return filtered; + } + + private List<String> filter( + final List<EventCategoryTO> eventCategoryTOs, final EventCategoryType type, final String category) { + final Set<String> res = new HashSet<String>(); + + for (EventCategoryTO eventCategory : eventCategoryTOs) { + if (type == eventCategory.getType() && StringUtils.equals(category, eventCategory.getCategory()) + && StringUtils.isNotEmpty(eventCategory.getSubcategory())) { + res.add(eventCategory.getSubcategory()); + } + } + + final List<String> filtered = new ArrayList<String>(res); + Collections.sort(filtered); + return filtered; + } + + @Override + @SuppressWarnings("unchecked") + public void onEvent(final IEvent<?> event) { + if (event.getPayload() instanceof ChangeCategoryEvent) { + // update objects .... + eventCategoryTO.getEvents().clear(); + + final ChangeCategoryEvent change = (ChangeCategoryEvent) event.getPayload(); + + final Panel changedPanel = change.getChangedPanel(); + if ("type".equals(changedPanel.getId())) { + eventCategoryTO.setType(type.getModelObject()); + eventCategoryTO.setCategory(null); + eventCategoryTO.setSubcategory(null); + + if (type.getModelObject() == EventCategoryType.CUSTOM) { + category.setChoices(Collections.<String>emptyList()); + subcategory.setChoices(Collections.<String>emptyList()); + category.setEnabled(false); + subcategory.setEnabled(false); + custom.setVisible(true); + custom.setEnabled(true); + actionPanel.setVisible(true); + actionPanel.setEnabled(true); + + } else { + category.setChoices(filter(eventCategoryTOs, type.getModelObject())); + subcategory.setChoices(Collections.<String>emptyList()); + category.setEnabled(true); + subcategory.setEnabled(true); + custom.setVisible(false); + custom.setEnabled(false); + actionPanel.setVisible(false); + actionPanel.setEnabled(false); + } + change.getTarget().add(categoryContainer); + } else if ("category".equals(changedPanel.getId())) { + subcategory.setChoices(filter(eventCategoryTOs, type.getModelObject(), category.getModelObject())); + eventCategoryTO.setCategory(category.getModelObject()); + eventCategoryTO.setSubcategory(null); + change.getTarget().add(categoryContainer); + } else { + eventCategoryTO.setSubcategory(subcategory.getModelObject()); + } + + updateEventsContainer(change.getTarget()); + } else if (event.getPayload() instanceof InspectSelectedEvent) { + // update objects .... + eventCategoryTO.getEvents().clear(); + + final InspectSelectedEvent inspectSelectedEvent = (InspectSelectedEvent) event.getPayload(); + + final Map.Entry<EventCategoryTO, AuditElements.Result> categoryEvent = + AuditLoggerName.parseEventCategory(inspectSelectedEvent.getEvent()); + + eventCategoryTO.setType(categoryEvent.getKey().getType()); + category.setChoices(filter(eventCategoryTOs, type.getModelObject())); + + eventCategoryTO.setCategory(categoryEvent.getKey().getCategory()); + subcategory.setChoices(filter(eventCategoryTOs, type.getModelObject(), category.getModelObject())); + + eventCategoryTO.setSubcategory(categoryEvent.getKey().getSubcategory()); + + if (categoryEvent.getKey().getType() == EventCategoryType.CUSTOM) { + custom.setModelObject(AuditLoggerName.buildEvent( + categoryEvent.getKey().getType(), + categoryEvent.getKey().getCategory(), + categoryEvent.getKey().getSubcategory(), + categoryEvent.getKey().getEvents().isEmpty() + ? StringUtils.EMPTY : categoryEvent.getKey().getEvents().iterator().next(), + categoryEvent.getValue())); + + category.setEnabled(false); + subcategory.setEnabled(false); + custom.setVisible(true); + custom.setEnabled(true); + actionPanel.setVisible(true); + actionPanel.setEnabled(true); + } else { + category.setEnabled(true); + subcategory.setEnabled(true); + custom.setVisible(false); + custom.setEnabled(false); + actionPanel.setVisible(false); + actionPanel.setEnabled(false); + } + + inspectSelectedEvent.getTarget().add(categoryContainer); + updateEventsContainer(inspectSelectedEvent.getTarget()); + } + } + + private void setEvents() { + final Iterator<EventCategoryTO> itor = eventCategoryTOs.iterator(); + while (itor.hasNext() && eventCategoryTO.getEvents().isEmpty()) { + final EventCategoryTO eventCategory = itor.next(); + if (eventCategory.getType() == eventCategoryTO.getType() + && StringUtils.equals(eventCategory.getCategory(), eventCategoryTO.getCategory()) + && StringUtils.equals(eventCategory.getSubcategory(), eventCategoryTO.getSubcategory())) { + eventCategoryTO.getEvents().addAll(eventCategory.getEvents()); + } + } + } + + private class ChangeCategoryEvent { + + private final AjaxRequestTarget target; + + private final Panel changedPanel; + + public ChangeCategoryEvent(final AjaxRequestTarget target, final Panel changedPanel) { + this.target = target; + this.changedPanel = changedPanel; + } + + public AjaxRequestTarget getTarget() { + return target; + } + + public Panel getChangedPanel() { + return changedPanel; + } + } + + /** + * To be extended in order to add actions on events. + * + * @param event event. + */ + protected void onEventAction(final IEvent<?> event) { + // nothing by default + } + + private void authorizeList() { + for (String role : getListRoles()) { + MetaDataRoleAuthorizationStrategy.authorize(selectedEventsPanel, RENDER, role); + } + } + + private void authorizeChanges() { + for (String role : getChangeRoles()) { + MetaDataRoleAuthorizationStrategy.authorize(categoryContainer, RENDER, role); + MetaDataRoleAuthorizationStrategy.authorize(eventsContainer, RENDER, role); + } + } + + private void updateEventsContainer(final AjaxRequestTarget target) { + setEvents(); + + eventsContainer.addOrReplace(new EventSelectionPanel("eventsPanel", eventCategoryTO, model) { + + private static final long serialVersionUID = 3513194801190026082L; + + @Override + public void onEventAction(final IEvent<?> event) { + LoggerCategoryPanel.this.onEventAction(event); + } + }); + target.add(eventsContainer); + } + + protected abstract String[] getListRoles(); + + protected abstract String[] getChangeRoles(); +}
http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java new file mode 100644 index 0000000..fb00dcf --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java @@ -0,0 +1,256 @@ +/* + * 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.panels; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.swing.tree.DefaultMutableTreeNode; +import org.apache.syncope.client.console.commons.Mode; +import org.apache.syncope.client.console.commons.RoleTreeBuilder; +import org.apache.syncope.client.console.commons.RoleUtils; +import org.apache.syncope.client.console.commons.status.StatusUtils; +import org.apache.syncope.client.console.pages.MembershipModalPage; +import org.apache.syncope.client.console.pages.UserModalPage; +import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink; +import org.apache.syncope.client.console.wicket.ajax.markup.html.IndicatingOnConfirmAjaxLink; +import org.apache.syncope.client.console.wicket.markup.html.tree.DefaultMutableTreeNodeExpansion; +import org.apache.syncope.client.console.wicket.markup.html.tree.DefaultMutableTreeNodeExpansionModel; +import org.apache.syncope.client.console.wicket.markup.html.tree.TreeRoleProvider; +import org.apache.syncope.common.lib.to.MembershipTO; +import org.apache.syncope.common.lib.to.RoleTO; +import org.apache.syncope.common.lib.to.UserTO; +import org.apache.wicket.Component; +import org.apache.wicket.Page; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.AjaxLink; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +import org.apache.wicket.extensions.markup.html.repeater.tree.DefaultNestedTree; +import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider; +import org.apache.wicket.extensions.markup.html.repeater.tree.NestedTree; +import org.apache.wicket.extensions.markup.html.repeater.tree.content.Folder; +import org.apache.wicket.extensions.markup.html.repeater.tree.theme.WindowsTheme; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; + +public class MembershipsPanel extends Panel { + + private static final long serialVersionUID = -2559791301973107191L; + + @SpringBean + private RoleTreeBuilder roleTreeBuilder; + + private final ListView<MembershipTO> membView; + + private final UserTO userTO; + + private final StatusPanel statusPanel; + + private final NestedTree<DefaultMutableTreeNode> tree; + + public MembershipsPanel(final String id, final UserTO userTO, final Mode mode, + final StatusPanel statusPanel, final PageReference pageRef) { + + super(id); + this.userTO = userTO; + this.statusPanel = statusPanel; + + final WebMarkupContainer membershipsContainer = new WebMarkupContainer("membershipsContainer"); + membershipsContainer.setOutputMarkupId(true); + add(membershipsContainer); + + final ModalWindow membWin = new ModalWindow("membershipWin"); + membWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY); + membWin.setCookieName("create-membership-modal"); + add(membWin); + + final ITreeProvider<DefaultMutableTreeNode> treeProvider = new TreeRoleProvider(roleTreeBuilder, true); + final DefaultMutableTreeNodeExpansionModel treeModel = new DefaultMutableTreeNodeExpansionModel(); + + tree = new DefaultNestedTree<DefaultMutableTreeNode>("treeTable", treeProvider, treeModel) { + + private static final long serialVersionUID = 7137658050662575546L; + + @Override + protected Component newContentComponent(final String id, final IModel<DefaultMutableTreeNode> node) { + final DefaultMutableTreeNode treeNode = node.getObject(); + final RoleTO roleTO = (RoleTO) treeNode.getUserObject(); + + return new Folder<DefaultMutableTreeNode>(id, MembershipsPanel.this.tree, node) { + + private static final long serialVersionUID = 9046323319920426493L; + + @Override + protected boolean isClickable() { + return true; + } + + @Override + protected IModel<?> newLabelModel(final IModel<DefaultMutableTreeNode> model) { + return new Model<String>(roleTO.getDisplayName()); + } + + @Override + protected void onClick(final AjaxRequestTarget target) { + if (roleTO.getKey() > 0) { + membWin.setPageCreator(new ModalWindow.PageCreator() { + + private static final long serialVersionUID = 7661763358801821185L; + + @Override + public Page createPage() { + PageReference pageRef = getPage().getPageReference(); + + for (MembershipTO membTO : membView.getList()) { + if (membTO.getRoleId() == roleTO.getKey()) { + return new MembershipModalPage(pageRef, membWin, membTO, mode); + } + } + MembershipTO membTO = new MembershipTO(); + membTO.setRoleId(roleTO.getKey()); + membTO.setRoleName(roleTO.getName()); + + return new MembershipModalPage(pageRef, membWin, membTO, mode); + } + }); + membWin.show(target); + } + } + }; + } + }; + tree.add(new WindowsTheme()); + tree.setOutputMarkupId(true); + + DefaultMutableTreeNodeExpansion.get().expandAll(); + + this.add(tree); + + membView = new ListView<MembershipTO>("memberships", + new PropertyModel<List<? extends MembershipTO>>(userTO, "memberships")) { + + private static final long serialVersionUID = 9101744072914090143L; + + @Override + protected void populateItem(final ListItem<MembershipTO> item) { + final MembershipTO membershipTO = (MembershipTO) item.getDefaultModelObject(); + + item.add(new Label("roleId", new Model<Long>(membershipTO.getRoleId()))); + item.add(new Label("roleName", new Model<String>(membershipTO.getRoleName()))); + + AjaxLink editLink = new ClearIndicatingAjaxLink("editLink", pageRef) { + + private static final long serialVersionUID = -7978723352517770644L; + + @Override + protected void onClickInternal(final AjaxRequestTarget target) { + membWin.setPageCreator(new ModalWindow.PageCreator() { + + private static final long serialVersionUID = -7834632442532690940L; + + @Override + public Page createPage() { + return new MembershipModalPage(getPage().getPageReference(), membWin, + membershipTO, mode); + + } + }); + membWin.show(target); + } + }; + item.add(editLink); + + AjaxLink deleteLink = new IndicatingOnConfirmAjaxLink("deleteLink", pageRef) { + + private static final long serialVersionUID = -7978723352517770644L; + + @Override + protected void onClickInternal(final AjaxRequestTarget target) { + userTO.getMemberships().remove(membershipTO); + ((UserModalPage) getPage()).getUserTO().getMemberships().remove(membershipTO); + target.add(membershipsContainer); + + RoleTO roleTO = RoleUtils.findRole(roleTreeBuilder, membershipTO.getRoleId()); + Set<String> resourcesToRemove = roleTO == null + ? Collections.<String>emptySet() : roleTO.getResources(); + if (!resourcesToRemove.isEmpty()) { + Set<String> resourcesAssignedViaMembership = new HashSet<String>(); + for (MembershipTO membTO : userTO.getMemberships()) { + roleTO = RoleUtils.findRole(roleTreeBuilder, membTO.getRoleId()); + if (roleTO != null) { + resourcesAssignedViaMembership.addAll(roleTO.getResources()); + } + } + resourcesToRemove.removeAll(resourcesAssignedViaMembership); + resourcesToRemove.removeAll(userTO.getResources()); + } + + StatusUtils.update( + userTO, statusPanel, target, Collections.<String>emptySet(), resourcesToRemove); + } + }; + item.add(deleteLink); + } + }; + + membershipsContainer.add(membView); + + setWindowClosedCallback(membWin, membershipsContainer); + } + + private void setWindowClosedCallback(final ModalWindow window, final WebMarkupContainer container) { + window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() { + + private static final long serialVersionUID = 8804221891699487139L; + + @Override + public void onClose(final AjaxRequestTarget target) { + final UserTO updatedUserTO = ((UserModalPage) getPage()).getUserTO(); + if (!userTO.equals(updatedUserTO)) { + if (updatedUserTO.getMemberships().size() > userTO.getMemberships().size()) { + Set<Long> diff = new HashSet<Long>(updatedUserTO.getMembershipMap().keySet()); + diff.removeAll(userTO.getMembershipMap().keySet()); + + Set<String> resourcesToAdd = new HashSet<String>(); + for (Long diffMembId : diff) { + long roleId = updatedUserTO.getMembershipMap().get(diffMembId).getRoleId(); + RoleTO roleTO = RoleUtils.findRole(roleTreeBuilder, roleId); + resourcesToAdd.addAll(roleTO.getResources()); + StatusUtils.update( + userTO, statusPanel, target, resourcesToAdd, Collections.<String>emptySet()); + } + } + + MembershipsPanel.this.userTO.getMemberships().clear(); + MembershipsPanel.this.userTO.getMemberships().addAll(updatedUserTO.getMemberships()); + target.add(container); + } + } + }); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationPanel.java new file mode 100644 index 0000000..8624d26 --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationPanel.java @@ -0,0 +1,119 @@ +/* + * 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.panels; + +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.console.commons.Constants; +import org.apache.wicket.AttributeModifier; +import org.apache.wicket.ajax.AjaxEventBehavior; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.feedback.FeedbackMessage; +import org.apache.wicket.feedback.IFeedbackMessageFilter; +import org.apache.wicket.markup.html.panel.FeedbackPanel; +import org.apache.wicket.model.Model; + +public class NotificationPanel extends FeedbackPanel { + + private static final long serialVersionUID = 5895940553202128621L; + + private static final String CSS_CLASS = "notificationpanel"; + + private static final String DEFAULT_ADDITIONAL_CSS_CLASS = "notificationpanel_top_right"; + + private final String additionalCSSClass; + + public NotificationPanel(final String id) { + this(id, null, null); + } + + public NotificationPanel(final String id, final String additionalCSSClass, + final IFeedbackMessageFilter feedbackMessageFilter) { + + super(id, feedbackMessageFilter); + + this.add(new AjaxEventBehavior(Constants.ON_CLICK) { + + private static final long serialVersionUID = -7133385027739964990L; + + @Override + protected void onEvent(final AjaxRequestTarget target) { + target.appendJavaScript( + "setTimeout(\"$('div#" + getMarkupId() + "').fadeOut('normal')\", 0);"); + } + }); + + this.additionalCSSClass = StringUtils.isBlank(additionalCSSClass) + ? DEFAULT_ADDITIONAL_CSS_CLASS + : additionalCSSClass; + + // set custom markup id and ouput it, to find the component later on in the js function + setMarkupId(id); + setOutputMarkupId(true); + + // Add the additional cssClass and hide the element by default + add(new AttributeModifier("class", new Model<String>(CSS_CLASS + " " + this.additionalCSSClass))); + add(new AttributeModifier("style", new Model<String>("opacity: 0;"))); + } + + /** + * Method to refresh the notification panel. + * + * If there are any feedback messages for the user, find the gravest level, format the notification panel + * accordingly and show it. + * + * @param target AjaxRequestTarget to add panel and the calling javascript function + */ + public void refresh(final AjaxRequestTarget target) { + // any feedback at all in the current form? + if (anyMessage()) { + int highestFeedbackLevel = FeedbackMessage.INFO; + + // any feedback with the given level? + if (anyMessage(FeedbackMessage.WARNING)) { + highestFeedbackLevel = FeedbackMessage.WARNING; + } + if (anyMessage(FeedbackMessage.ERROR)) { + highestFeedbackLevel = FeedbackMessage.ERROR; + } + + // add the css classes to the notification panel, + // including the border css which represents the highest level of feedback + add(new AttributeModifier("class", + new Model<String>(CSS_CLASS + + " " + additionalCSSClass + + " notificationpanel_border_" + highestFeedbackLevel))); + + // refresh the panel and call the js function with the panel markup id + // and the total count of messages + target.add(this); + if (anyMessage(FeedbackMessage.ERROR)) { + target.appendJavaScript( + "$('div#" + getMarkupId() + "').fadeTo('normal', 1.0);"); + } else { + target.appendJavaScript( + "showNotification('" + getMarkupId() + "', " + getCurrentMessages().size() + ");"); + } + } + } + + @Override + protected String getCSSClass(final FeedbackMessage message) { + return "notificationpanel_row_" + message.getLevelAsString(); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java new file mode 100644 index 0000000..d7f52e1 --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java @@ -0,0 +1,254 @@ +/* + * 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.panels; + +import java.util.ArrayList; +import java.util.List; +import org.apache.syncope.client.console.commons.Constants; +import org.apache.syncope.client.console.pages.NotificationTaskModalPage; +import org.apache.syncope.client.console.pages.Tasks; +import org.apache.syncope.client.console.pages.Tasks.TasksProvider; +import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn; +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel; +import org.apache.syncope.common.lib.SyncopeClientException; +import org.apache.syncope.common.lib.to.AbstractTaskTO; +import org.apache.syncope.common.lib.to.NotificationTaskTO; +import org.apache.wicket.Component; +import org.apache.wicket.Page; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; +import org.apache.wicket.event.IEvent; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +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.html.WebMarkupContainer; +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.request.http.WebResponse; + +public class NotificationTasks extends AbstractTasks { + + private static final long serialVersionUID = 4984337552918213290L; + + private int paginatorRows; + + private WebMarkupContainer container; + + private boolean operationResult = false; + + private ModalWindow window; + + private AjaxDataTablePanel<AbstractTaskTO, String> table; + + public NotificationTasks(final String id, final PageReference pageRef) { + super(id, pageRef); + + container = new WebMarkupContainer("container"); + container.setOutputMarkupId(true); + add(container); + + add(window = new ModalWindow("taskWin")); + + paginatorRows = prefMan.getPaginatorRows(getWebRequest(), Constants.PREF_NOTIFICATION_TASKS_PAGINATOR_ROWS); + + table = Tasks.updateTaskTable( + getColumns(), + new TasksProvider<NotificationTaskTO>(restClient, paginatorRows, getId(), NotificationTaskTO.class), + container, + 0, + pageRef, + restClient); + + container.add(table); + + window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() { + + private static final long serialVersionUID = 8804221891699487139L; + + @Override + public void onClose(final AjaxRequestTarget target) { + target.add(container); + if (operationResult) { + info(getString(Constants.OPERATION_SUCCEEDED)); + target.add(getPage().get(Constants.FEEDBACK)); + operationResult = false; + } + } + }); + + window.setCssClassName(ModalWindow.CSS_CLASS_GRAY); + window.setInitialHeight(WIN_HEIGHT); + window.setInitialWidth(WIN_WIDTH); + window.setCookieName(VIEW_TASK_WIN_COOKIE_NAME); + + @SuppressWarnings("rawtypes") + final Form paginatorForm = new Form("PaginatorForm"); + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final DropDownChoice rowsChooser = new DropDownChoice("rowsChooser", new PropertyModel(this, "paginatorRows"), + prefMan.getPaginatorChoices()); + + rowsChooser.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -1107858522700306810L; + + @Override + protected void onUpdate(final AjaxRequestTarget target) { + prefMan.set(getWebRequest(), (WebResponse) getResponse(), + Constants.PREF_NOTIFICATION_TASKS_PAGINATOR_ROWS, String.valueOf(paginatorRows)); + + table = Tasks.updateTaskTable( + getColumns(), + new TasksProvider<NotificationTaskTO>(restClient, paginatorRows, getId(), + NotificationTaskTO.class), + container, + table == null ? 0 : (int) table.getCurrentPage(), + pageRef, + restClient); + + target.add(container); + } + }); + + paginatorForm.add(rowsChooser); + add(paginatorForm); + } + + private List<IColumn<AbstractTaskTO, String>> getColumns() { + final List<IColumn<AbstractTaskTO, String>> columns = new ArrayList<>(); + + columns.add(new PropertyColumn<AbstractTaskTO, String>( + new StringResourceModel("key", this, null), "key", "key")); + columns.add(new PropertyColumn<AbstractTaskTO, String>( + new StringResourceModel("sender", this, null), "sender", "sender")); + columns.add(new PropertyColumn<AbstractTaskTO, String>( + new StringResourceModel("recipients", this, null), "recipients", "recipients")); + columns.add(new PropertyColumn<AbstractTaskTO, String>( + new StringResourceModel("subject", this, null), "subject", "subject")); + columns.add(new PropertyColumn<AbstractTaskTO, String>( + new StringResourceModel("traceLevel", this, null), "traceLevel", "traceLevel")); + columns.add(new PropertyColumn<AbstractTaskTO, String>( + new StringResourceModel("latestExecStatus", this, null), "latestExecStatus", "latestExecStatus")); + + columns.add(new ActionColumn<AbstractTaskTO, String>(new StringResourceModel("actions", this, null, "")) { + + private static final long serialVersionUID = 2054811145491901166L; + + @Override + public ActionLinksPanel getActions(final String componentId, final IModel<AbstractTaskTO> model) { + + final AbstractTaskTO taskTO = model.getObject(); + + final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, pageRef); + + panel.add(new ActionLink() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target) { + + window.setPageCreator(new ModalWindow.PageCreator() { + + private static final long serialVersionUID = -7834632442532690940L; + + @Override + public Page createPage() { + return new NotificationTaskModalPage(taskTO); + } + }); + + window.show(target); + } + }, ActionLink.ActionType.EDIT, TASKS); + + panel.add(new ActionLink() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target) { + try { + restClient.startExecution(taskTO.getKey(), false); + getSession().info(getString(Constants.OPERATION_SUCCEEDED)); + } catch (SyncopeClientException scce) { + error(scce.getMessage()); + } + + ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target); + target.add(container); + } + }, ActionLink.ActionType.EXECUTE, TASKS); + + panel.add(new ActionLink() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target) { + try { + restClient.delete(taskTO.getKey(), NotificationTaskTO.class); + info(getString(Constants.OPERATION_SUCCEEDED)); + } catch (SyncopeClientException scce) { + error(scce.getMessage()); + } + target.add(container); + ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target); + } + }, ActionLink.ActionType.DELETE, TASKS); + + return panel; + } + + @Override + public Component getHeader(String componentId) { + final ActionLinksPanel panel = new ActionLinksPanel(componentId, new Model(), pageRef); + + panel.add(new ActionLink() { + + private static final long serialVersionUID = -7978723352517770644L; + + @Override + public void onClick(final AjaxRequestTarget target) { + if (target != null) { + target.add(table); + } + } + }, ActionLink.ActionType.RELOAD, TASKS, "list"); + + return panel; + } + }); + + return columns; + } + + @Override + public void onEvent(final IEvent<?> event) { + if (event.getPayload() instanceof AbstractSearchResultPanel.EventDataWrapper) { + ((AbstractSearchResultPanel.EventDataWrapper) event.getPayload()).getTarget().add(container); + } + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/PlainAttrsPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/PlainAttrsPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/PlainAttrsPanel.java new file mode 100644 index 0000000..8e42318 --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/PlainAttrsPanel.java @@ -0,0 +1,395 @@ +/* + * 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.panels; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.console.commons.AttrLayoutType; +import org.apache.syncope.client.console.commons.JexlHelpUtil; +import org.apache.syncope.client.console.commons.Mode; +import org.apache.syncope.client.console.panels.AttrTemplatesPanel.RoleAttrTemplatesChange; +import org.apache.syncope.client.console.rest.ConfigurationRestClient; +import org.apache.syncope.client.console.rest.RoleRestClient; +import org.apache.syncope.client.console.rest.SchemaRestClient; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.BinaryFieldPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.DateTextFieldPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.DateTimeFieldPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.FieldPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.SpinnerFieldPanel; +import org.apache.syncope.client.console.wicket.markup.html.list.AltListView; +import org.apache.syncope.common.lib.SyncopeConstants; +import org.apache.syncope.common.lib.to.AbstractAttributableTO; +import org.apache.syncope.common.lib.to.AttrTO; +import org.apache.syncope.common.lib.to.ConfTO; +import org.apache.syncope.common.lib.to.MembershipTO; +import org.apache.syncope.common.lib.to.PlainSchemaTO; +import org.apache.syncope.common.lib.to.RoleTO; +import org.apache.syncope.common.lib.to.UserTO; +import org.apache.syncope.common.lib.types.AttrSchemaType; +import org.apache.syncope.common.lib.types.AttributableType; +import org.apache.wicket.ajax.markup.html.AjaxLink; +import org.apache.wicket.event.IEvent; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.IChoiceRenderer; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; + +public class PlainAttrsPanel extends Panel { + + private static final long serialVersionUID = 552437609667518888L; + + @SpringBean + private SchemaRestClient schemaRestClient; + + @SpringBean + private ConfigurationRestClient confRestClient; + + @SpringBean + private RoleRestClient roleRestClient; + + private final AbstractAttributableTO entityTO; + + private final Mode mode; + + private final AttrTemplatesPanel attrTemplates; + + private Map<String, PlainSchemaTO> schemas = new LinkedHashMap<>(); + + public <T extends AbstractAttributableTO> PlainAttrsPanel(final String id, final T entityTO, + final Form<?> form, final Mode mode) { + + this(id, entityTO, form, mode, null); + } + + public <T extends AbstractAttributableTO> PlainAttrsPanel(final String id, final T entityTO, + final Form<?> form, final Mode mode, final AttrTemplatesPanel attrTemplates) { + + super(id); + this.entityTO = entityTO; + this.mode = mode; + this.attrTemplates = attrTemplates; + this.setOutputMarkupId(true); + + setSchemas(); + setAttrs(); + + add(new AltListView<AttrTO>("schemas", new PropertyModel<List<? extends AttrTO>>(entityTO, "attrs")) { + + private static final long serialVersionUID = 9101744072914090143L; + + @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected void populateItem(final ListItem<AttrTO> item) { + final AttrTO attributeTO = (AttrTO) item.getDefaultModelObject(); + + final WebMarkupContainer jexlHelp = JexlHelpUtil.getJexlHelpWebContainer("jexlHelp"); + + final AjaxLink<Void> questionMarkJexlHelp = JexlHelpUtil.getAjaxLink(jexlHelp, "questionMarkJexlHelp"); + item.add(questionMarkJexlHelp); + questionMarkJexlHelp.add(jexlHelp); + + if (mode != Mode.TEMPLATE) { + questionMarkJexlHelp.setVisible(false); + } + + item.add(new Label("name", attributeTO.getSchema())); + + final FieldPanel panel = getFieldPanel(schemas.get(attributeTO.getSchema()), form, attributeTO); + + if (mode == Mode.TEMPLATE || !schemas.get(attributeTO.getSchema()).isMultivalue()) { + item.add(panel); + } else { + item.add(new MultiFieldPanel<String>( + "panel", new PropertyModel<List<String>>(attributeTO, "values"), panel)); + } + } + } + ); + } + + private void setSchemas() { + AttrTO attrLayout = null; + List<PlainSchemaTO> schemaTOs; + + if (entityTO instanceof RoleTO) { + final RoleTO roleTO = (RoleTO) entityTO; + + attrLayout = confRestClient.readAttrLayout(AttrLayoutType.valueOf(mode, AttributableType.ROLE)); + schemaTOs = schemaRestClient.getSchemas(AttributableType.ROLE); + Set<String> allowed; + if (attrTemplates == null) { + allowed = new HashSet<>(roleTO.getRPlainAttrTemplates()); + } else { + allowed = new HashSet<>(attrTemplates.getSelected(AttrTemplatesPanel.Type.rPlainAttrTemplates)); + if (roleTO.isInheritTemplates() && roleTO.getParent() != 0) { + allowed.addAll(roleRestClient.read(roleTO.getParent()).getRPlainAttrTemplates()); + } + } + schemaRestClient.filter(schemaTOs, allowed, true); + } else if (entityTO instanceof UserTO) { + attrLayout = confRestClient.readAttrLayout(AttrLayoutType.valueOf(mode, AttributableType.USER)); + schemaTOs = schemaRestClient.getSchemas(AttributableType.USER); + } else if (entityTO instanceof MembershipTO) { + attrLayout = confRestClient.readAttrLayout(AttrLayoutType.valueOf(mode, AttributableType.MEMBERSHIP)); + schemaTOs = schemaRestClient.getSchemas(AttributableType.MEMBERSHIP); + Set<String> allowed = new HashSet<>( + roleRestClient.read(((MembershipTO) entityTO).getRoleId()).getMPlainAttrTemplates()); + schemaRestClient.filter(schemaTOs, allowed, true); + } else { + schemas = new TreeMap<>(); + schemaTOs = schemaRestClient.getSchemas(AttributableType.CONFIGURATION); + for (Iterator<PlainSchemaTO> it = schemaTOs.iterator(); it.hasNext();) { + PlainSchemaTO schemaTO = it.next(); + for (AttrLayoutType type : AttrLayoutType.values()) { + if (type.getConfKey().equals(schemaTO.getKey())) { + it.remove(); + } + } + } + } + + schemas.clear(); + + if (attrLayout != null && mode != Mode.TEMPLATE && !(entityTO instanceof ConfTO)) { + // 1. remove attributes not selected for display + schemaRestClient.filter(schemaTOs, attrLayout.getValues(), true); + // 2. sort remainig attributes according to configuration, e.g. attrLayout + final Map<String, Integer> attrLayoutMap = new HashMap<>(attrLayout.getValues().size()); + for (int i = 0; i < attrLayout.getValues().size(); i++) { + attrLayoutMap.put(attrLayout.getValues().get(i), i); + } + Collections.sort(schemaTOs, new Comparator<PlainSchemaTO>() { + + @Override + public int compare(final PlainSchemaTO schema1, final PlainSchemaTO schema2) { + int value = 0; + + if (attrLayoutMap.get(schema1.getKey()) > attrLayoutMap.get(schema2.getKey())) { + value = 1; + } else if (attrLayoutMap.get(schema1.getKey()) < attrLayoutMap.get(schema2.getKey())) { + value = -1; + } + + return value; + } + }); + } + for (PlainSchemaTO schemaTO : schemaTOs) { + schemas.put(schemaTO.getKey(), schemaTO); + } + } + + private void setAttrs() { + final List<AttrTO> entityData = new ArrayList<>(); + + final Map<String, AttrTO> attrMap = entityTO.getPlainAttrMap(); + + for (PlainSchemaTO schema : schemas.values()) { + final AttrTO attributeTO = new AttrTO(); + attributeTO.setSchema(schema.getKey()); + + if (attrMap.get(schema.getKey()) == null || attrMap.get(schema.getKey()).getValues().isEmpty()) { + attributeTO.getValues().add(""); + + // is important to set readonly only after values setting + attributeTO.setReadonly(schema.isReadonly()); + } else { + attributeTO.getValues().addAll(attrMap.get(schema.getKey()).getValues()); + } + entityData.add(attributeTO); + } + + entityTO.getPlainAttrs().clear(); + entityTO.getPlainAttrs().addAll(entityData); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private FieldPanel getFieldPanel(final PlainSchemaTO schemaTO, final Form form, final AttrTO attributeTO) { + final boolean required = mode == Mode.TEMPLATE + ? false + : schemaTO.getMandatoryCondition().equalsIgnoreCase("true"); + + final boolean readOnly = mode == Mode.TEMPLATE ? false : schemaTO.isReadonly(); + + final AttrSchemaType type = mode == Mode.TEMPLATE ? AttrSchemaType.String : schemaTO.getType(); + + final FieldPanel panel; + switch (type) { + case Boolean: + panel = new AjaxCheckBoxPanel("panel", schemaTO.getKey(), new Model<Boolean>()); + panel.setRequired(required); + break; + + case Date: + final String dataPattern = schemaTO.getConversionPattern() == null + ? SyncopeConstants.DEFAULT_DATE_PATTERN + : schemaTO.getConversionPattern(); + + if (dataPattern.contains("H")) { + panel = new DateTimeFieldPanel("panel", schemaTO.getKey(), new Model<Date>(), dataPattern); + + if (required) { + panel.addRequiredLabel(); + ((DateTimeFieldPanel) panel).setFormValidator(form); + } + panel.setStyleSheet("ui-widget-content ui-corner-all"); + } else { + panel = new DateTextFieldPanel("panel", schemaTO.getKey(), new Model<Date>(), dataPattern); + + if (required) { + panel.addRequiredLabel(); + } + } + break; + + case Enum: + panel = new AjaxDropDownChoicePanel<String>("panel", schemaTO.getKey(), new Model<String>()); + ((AjaxDropDownChoicePanel<String>) panel).setChoices(getEnumeratedValues(schemaTO)); + + if (StringUtils.isNotBlank(schemaTO.getEnumerationKeys())) { + ((AjaxDropDownChoicePanel) panel).setChoiceRenderer(new IChoiceRenderer<String>() { + + private static final long serialVersionUID = -3724971416312135885L; + + private final Map<String, String> valueMap = getEnumeratedKeyValues(schemaTO); + + @Override + public String getDisplayValue(final String value) { + return valueMap.get(value) == null ? value : valueMap.get(value); + } + + @Override + public String getIdValue(final String value, final int i) { + return value; + } + }); + } + + if (required) { + panel.addRequiredLabel(); + } + break; + + case Long: + panel = new SpinnerFieldPanel<Long>("panel", schemaTO.getKey(), + Long.class, new Model<Long>(), null, null); + + if (required) { + panel.addRequiredLabel(); + } + break; + + case Double: + panel = new SpinnerFieldPanel<Double>("panel", schemaTO.getKey(), + Double.class, new Model<Double>(), null, null); + + if (required) { + panel.addRequiredLabel(); + } + break; + + case Binary: + panel = new BinaryFieldPanel("panel", schemaTO.getKey(), new Model<String>(), + schemas.containsKey(schemaTO.getKey()) + ? schemas.get(schemaTO.getKey()).getMimeType() + : null); + + if (required) { + panel.addRequiredLabel(); + } + break; + + default: + panel = new AjaxTextFieldPanel("panel", schemaTO.getKey(), new Model<String>()); + + if (required) { + panel.addRequiredLabel(); + } + } + + panel.setReadOnly(readOnly); + panel.setNewModel(attributeTO.getValues()); + + return panel; + } + + private Map<String, String> getEnumeratedKeyValues(final PlainSchemaTO schemaTO) { + final Map<String, String> res = new HashMap<>(); + + final String[] values = StringUtils.isBlank(schemaTO.getEnumerationValues()) + ? new String[0] + : schemaTO.getEnumerationValues().split(SyncopeConstants.ENUM_VALUES_SEPARATOR); + + final String[] keys = StringUtils.isBlank(schemaTO.getEnumerationKeys()) + ? new String[0] + : schemaTO.getEnumerationKeys().split(SyncopeConstants.ENUM_VALUES_SEPARATOR); + + for (int i = 0; i < values.length; i++) { + res.put(values[i].trim(), keys.length > i ? keys[i].trim() : null); + } + + return res; + } + + private List<String> getEnumeratedValues(final PlainSchemaTO schemaTO) { + final List<String> res = new ArrayList<>(); + + final String[] values = StringUtils.isBlank(schemaTO.getEnumerationValues()) + ? new String[0] + : schemaTO.getEnumerationValues().split(SyncopeConstants.ENUM_VALUES_SEPARATOR); + + for (String value : values) { + res.add(value.trim()); + } + + return res; + } + + @Override + public void onEvent(final IEvent<?> event) { + if ((event.getPayload() instanceof RoleAttrTemplatesChange)) { + final RoleAttrTemplatesChange update = (RoleAttrTemplatesChange) event.getPayload(); + if (attrTemplates != null && update.getType() == AttrTemplatesPanel.Type.rPlainAttrTemplates) { + setSchemas(); + setAttrs(); + update.getTarget().add(this); + } + } + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/PoliciesPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/PoliciesPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/PoliciesPanel.java new file mode 100644 index 0000000..4d66eda --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/PoliciesPanel.java @@ -0,0 +1,343 @@ +/* + * 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.panels; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import org.apache.syncope.client.console.commons.Constants; +import org.apache.syncope.client.console.commons.PreferenceManager; +import org.apache.syncope.client.console.commons.SortableDataProviderComparator; +import org.apache.syncope.client.console.commons.XMLRolesReader; +import org.apache.syncope.client.console.pages.BasePage; +import org.apache.syncope.client.console.pages.PolicyModalPage; +import org.apache.syncope.client.console.rest.PolicyRestClient; +import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink; +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel; +import org.apache.syncope.common.lib.SyncopeClientException; +import org.apache.syncope.common.lib.to.AbstractPolicyTO; +import org.apache.syncope.common.lib.to.AccountPolicyTO; +import org.apache.syncope.common.lib.to.PasswordPolicyTO; +import org.apache.syncope.common.lib.to.SyncPolicyTO; +import org.apache.syncope.common.lib.types.PolicyType; +import org.apache.wicket.Page; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; +import org.apache.wicket.ajax.markup.html.AjaxLink; +import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable; +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; +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.extensions.markup.html.repeater.util.SortableDataProvider; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.CompoundPropertyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.request.http.WebResponse; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PoliciesPanel extends Panel { + + /** + * Logger. + */ + private static final Logger LOG = LoggerFactory.getLogger(PoliciesPanel.class); + + private static final int MODAL_WIN_HEIGHT = 400; + + private static final int MODAL_WIN_WIDTH = 1000; + + private static final long serialVersionUID = -6804066913177804275L; + + @SpringBean + private PolicyRestClient policyRestClient; + + @SpringBean + protected XMLRolesReader xmlRolesReader; + + @SpringBean + private PreferenceManager prefMan; + + private final PageReference pageRef; + + private final int paginatorRows = prefMan.getPaginatorRows(getWebRequest(), Constants.PREF_POLICY_PAGINATOR_ROWS); + + protected boolean modalResult = false; + + private final PolicyType policyType; + + public PoliciesPanel(final String id, final PageReference pageRef, final PolicyType policyType) { + super(id); + this.pageRef = pageRef; + this.policyType = policyType; + + // Modal window for editing user attributes + final ModalWindow mwindow = new ModalWindow("editModalWin"); + mwindow.setCssClassName(ModalWindow.CSS_CLASS_GRAY); + mwindow.setInitialHeight(MODAL_WIN_HEIGHT); + mwindow.setInitialWidth(MODAL_WIN_WIDTH); + mwindow.setCookieName("policy-modal"); + add(mwindow); + + // Container for user list + final WebMarkupContainer container = new WebMarkupContainer("container"); + container.setOutputMarkupId(true); + add(container); + + setWindowClosedCallback(mwindow, container); + + final List<IColumn<AbstractPolicyTO, String>> columns = new ArrayList<>(); + + columns.add(new PropertyColumn<AbstractPolicyTO, String>(new ResourceModel("key"), "key", "key")); + + columns.add(new PropertyColumn<AbstractPolicyTO, String>( + new ResourceModel("description"), "description", "description")); + + columns.add(new AbstractColumn<AbstractPolicyTO, String>(new ResourceModel("type")) { + + private static final long serialVersionUID = 8263694778917279290L; + + @Override + public void populateItem(final Item<ICellPopulator<AbstractPolicyTO>> cellItem, final String componentId, + final IModel<AbstractPolicyTO> model) { + + cellItem.add(new Label(componentId, getString(model.getObject().getType().name()))); + } + }); + + columns.add(new AbstractColumn<AbstractPolicyTO, String>(new ResourceModel("actions", "")) { + + private static final long serialVersionUID = 2054811145491901166L; + + @Override + public String getCssClass() { + return "action"; + } + + @Override + public void populateItem(final Item<ICellPopulator<AbstractPolicyTO>> cellItem, final String componentId, + final IModel<AbstractPolicyTO> model) { + + final AbstractPolicyTO policyTO = model.getObject(); + + final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, pageRef); + + panel.add(new ActionLink() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target) { + + mwindow.setPageCreator(new ModalWindow.PageCreator() { + + private static final long serialVersionUID = -7834632442532690940L; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Page createPage() { + return new PolicyModalPage(pageRef, mwindow, policyTO); + } + }); + + mwindow.show(target); + } + }, ActionLink.ActionType.EDIT, "Policies"); + + panel.add(new ActionLink() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target) { + try { + policyRestClient.delete(policyTO.getKey(), policyTO.getClass()); + info(getString(Constants.OPERATION_SUCCEEDED)); + } catch (SyncopeClientException e) { + error(getString(Constants.OPERATION_ERROR)); + + LOG.error("While deleting policy {}({})", + policyTO.getKey(), policyTO.getDescription(), e); + } + + target.add(container); + ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target); + } + }, ActionLink.ActionType.DELETE, "Policies"); + + cellItem.add(panel); + } + }); + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final AjaxFallbackDefaultDataTable table = new AjaxFallbackDefaultDataTable("datatable", columns, + new PolicyDataProvider(), paginatorRows); + + container.add(table); + + final AjaxLink<Void> createButton = new ClearIndicatingAjaxLink<Void>("createLink", pageRef) { + + private static final long serialVersionUID = -7978723352517770644L; + + @Override + protected void onClickInternal(final AjaxRequestTarget target) { + mwindow.setPageCreator(new ModalWindow.PageCreator() { + + private static final long serialVersionUID = -7834632442532690940L; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Page createPage() { + return new PolicyModalPage(pageRef, mwindow, getPolicyTOInstance(policyType)); + } + }); + + mwindow.show(target); + } + }; + + add(createButton); + + MetaDataRoleAuthorizationStrategy.authorize( + createButton, ENABLE, xmlRolesReader.getEntitlement("Policies", "create")); + + @SuppressWarnings("rawtypes") + final Form paginatorForm = new Form("PaginatorForm"); + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final DropDownChoice rowsChooser = new DropDownChoice("rowsChooser", new PropertyModel(this, "paginatorRows"), + prefMan.getPaginatorChoices()); + + rowsChooser.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -1107858522700306810L; + + @Override + protected void onUpdate(final AjaxRequestTarget target) { + prefMan.set(getWebRequest(), (WebResponse) getResponse(), Constants.PREF_POLICY_PAGINATOR_ROWS, String + .valueOf(paginatorRows)); + table.setItemsPerPage(paginatorRows); + + target.add(container); + } + }); + + paginatorForm.add(rowsChooser); + add(paginatorForm); + } + + private void setWindowClosedCallback(final ModalWindow window, final WebMarkupContainer container) { + window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() { + + private static final long serialVersionUID = 8804221891699487139L; + + @Override + public void onClose(final AjaxRequestTarget target) { + target.add(container); + BasePage configuration = ((BasePage) pageRef.getPage()); + if (configuration.isModalResult()) { + info(getString(Constants.OPERATION_SUCCEEDED)); + configuration.getFeedbackPanel().refresh(target); + configuration.setModalResult(false); + } + } + }); + } + + private class PolicyDataProvider extends SortableDataProvider<AbstractPolicyTO, String> { + + private static final long serialVersionUID = -6976327453925166730L; + + private final SortableDataProviderComparator<AbstractPolicyTO> comparator; + + public PolicyDataProvider() { + super(); + + //Default sorting + setSort("description", SortOrder.ASCENDING); + + comparator = new SortableDataProviderComparator<AbstractPolicyTO>(this); + } + + @Override + public long size() { + return policyRestClient.getPolicies(policyType, true).size(); + } + + @Override + public Iterator<AbstractPolicyTO> iterator(final long first, final long count) { + final List<AbstractPolicyTO> policies = policyRestClient.getPolicies(policyType, true); + + Collections.sort(policies, comparator); + + return policies.subList((int) first, (int) first + (int) count).iterator(); + } + + @Override + public IModel<AbstractPolicyTO> model(final AbstractPolicyTO object) { + return new CompoundPropertyModel<AbstractPolicyTO>(object); + } + } + + private AbstractPolicyTO getPolicyTOInstance(final PolicyType policyType) { + AbstractPolicyTO policyTO; + switch (policyType) { + case GLOBAL_ACCOUNT: + policyTO = new AccountPolicyTO(true); + break; + + case ACCOUNT: + policyTO = new AccountPolicyTO(); + break; + + case GLOBAL_PASSWORD: + policyTO = new PasswordPolicyTO(true); + break; + + case PASSWORD: + policyTO = new PasswordPolicyTO(); + break; + + case GLOBAL_SYNC: + policyTO = new SyncPolicyTO(true); + break; + + case SYNC: + default: + policyTO = new SyncPolicyTO(); + } + + return policyTO; + } +}
