http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/pages/Todo.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/Todo.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/Todo.java new file mode 100644 index 0000000..1329fe4 --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/Todo.java @@ -0,0 +1,245 @@ +/* + * 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.pages; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import org.apache.syncope.client.console.SyncopeSession; +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.rest.ApprovalRestClient; +import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn; +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.WorkflowFormTO; +import org.apache.wicket.Page; +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.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.form.DropDownChoice; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; + +public class Todo extends BasePage { + + private static final long serialVersionUID = -7122136682275797903L; + + @SpringBean + private ApprovalRestClient restClient; + + @SpringBean + private PreferenceManager prefMan; + + private final ModalWindow window; + + private static final int WIN_HEIGHT = 400; + + private static final int WIN_WIDTH = 600; + + private WebMarkupContainer container; + + private int paginatorRows; + + public Todo(final PageParameters parameters) { + super(parameters); + + add(window = new ModalWindow("editApprovalWin")); + + container = new WebMarkupContainer("approvalContainer"); + + MetaDataRoleAuthorizationStrategy.authorize( + container, RENDER, xmlRolesReader.getEntitlement("Approval", "list")); + + paginatorRows = prefMan.getPaginatorRows(getRequest(), Constants.PREF_TODO_PAGINATOR_ROWS); + + List<IColumn<WorkflowFormTO, String>> columns = new ArrayList<IColumn<WorkflowFormTO, String>>(); + columns.add(new PropertyColumn<WorkflowFormTO, String>( + new ResourceModel("taskId"), "taskId", "taskId")); + columns.add(new PropertyColumn<WorkflowFormTO, String>( + new ResourceModel("key"), "key", "key")); + columns.add(new PropertyColumn<WorkflowFormTO, String>( + new ResourceModel("description"), "description", "description")); + columns.add(new DatePropertyColumn<WorkflowFormTO>( + new ResourceModel("createTime"), "createTime", "createTime")); + columns.add(new DatePropertyColumn<WorkflowFormTO>( + new ResourceModel("dueDate"), "dueDate", "dueDate")); + columns.add(new PropertyColumn<WorkflowFormTO, String>(new ResourceModel("owner"), "owner", "owner")); + columns.add(new AbstractColumn<WorkflowFormTO, String>(new ResourceModel("actions", "")) { + + private static final long serialVersionUID = 2054811145491901166L; + + @Override + public String getCssClass() { + return "action"; + } + + @Override + public void populateItem(final Item<ICellPopulator<WorkflowFormTO>> cellItem, final String componentId, + final IModel<WorkflowFormTO> model) { + + final WorkflowFormTO formTO = model.getObject(); + + final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, getPageReference()); + + panel.add(new ActionLink() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target) { + try { + restClient.claimForm(formTO.getTaskId()); + info(getString(Constants.OPERATION_SUCCEEDED)); + } catch (SyncopeClientException scee) { + error(getString(Constants.ERROR) + ": " + scee.getMessage()); + } + feedbackPanel.refresh(target); + target.add(container); + } + }, ActionLink.ActionType.CLAIM, "Approval"); + + 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 ApprovalModalPage(Todo.this.getPageReference(), window, formTO); + } + }); + + window.show(target); + } + }, ActionLink.ActionType.EDIT, "Approval", + SyncopeSession.get().getUsername().equals(formTO.getOwner())); + + cellItem.add(panel); + } + }); + + final AjaxFallbackDefaultDataTable<WorkflowFormTO, String> approvalTable = + new AjaxFallbackDefaultDataTable<WorkflowFormTO, String>( + "approvalTable", columns, new ApprovalProvider(), paginatorRows); + container.add(approvalTable); + + container.setOutputMarkupId(true); + add(container); + + @SuppressWarnings("rawtypes") + Form approvalPaginatorForm = new Form("paginatorForm"); + + MetaDataRoleAuthorizationStrategy.authorize(approvalPaginatorForm, RENDER, + xmlRolesReader.getEntitlement("Approval", "list")); + + @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(getRequest(), getResponse(), Constants.PREF_TODO_PAGINATOR_ROWS, + String.valueOf(paginatorRows)); + approvalTable.setItemsPerPage(paginatorRows); + + target.add(container); + } + }); + + approvalPaginatorForm.add(rowsChooser); + add(approvalPaginatorForm); + + window.setCssClassName(ModalWindow.CSS_CLASS_GRAY); + window.setInitialHeight(WIN_HEIGHT); + window.setInitialWidth(WIN_WIDTH); + window.setCookieName("edit-approval-modal"); + + setWindowClosedCallback(window, container); + } + + private class ApprovalProvider extends SortableDataProvider<WorkflowFormTO, String> { + + private static final long serialVersionUID = -2311716167583335852L; + + private final SortableDataProviderComparator<WorkflowFormTO> comparator; + + public ApprovalProvider() { + super(); + //Default sorting + setSort("key", SortOrder.ASCENDING); + comparator = new SortableDataProviderComparator<WorkflowFormTO>(this); + } + + @Override + public Iterator<WorkflowFormTO> iterator(final long first, final long count) { + final List<WorkflowFormTO> list = restClient.getForms(); + + Collections.sort(list, comparator); + + return list.subList((int) first, (int) first + (int) count).iterator(); + } + + @Override + public long size() { + return restClient.getForms().size(); + } + + @Override + public IModel<WorkflowFormTO> model(final WorkflowFormTO configuration) { + return new AbstractReadOnlyModel<WorkflowFormTO>() { + + private static final long serialVersionUID = -2566070996511906708L; + + @Override + public WorkflowFormTO getObject() { + return configuration; + } + }; + } + } + +}
http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/pages/UserModalPage.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/UserModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/UserModalPage.java new file mode 100644 index 0000000..0215538 --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/UserModalPage.java @@ -0,0 +1,229 @@ +/* + * 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.pages; + +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.console.commons.Constants; +import org.apache.syncope.client.console.commons.Mode; +import org.apache.syncope.client.console.panels.DerAttrsPanel; +import org.apache.syncope.client.console.panels.MembershipsPanel; +import org.apache.syncope.client.console.panels.PlainAttrsPanel; +import org.apache.syncope.client.console.panels.ResourcesPanel; +import org.apache.syncope.client.console.panels.SecurityQuestionPanel; +import org.apache.syncope.client.console.panels.UserDetailsPanel; +import org.apache.syncope.client.console.panels.VirAttrsPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel; +import org.apache.syncope.common.lib.to.UserTO; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.form.AjaxButton; +import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; +import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.panel.Fragment; +import org.apache.wicket.model.CompoundPropertyModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.ResourceModel; + +/** + * Modal window with User form. + */ +public abstract class UserModalPage extends BaseModalPage { + + private static final long serialVersionUID = 5002005009737457667L; + + protected final PageReference pageRef; + + protected final ModalWindow window; + + protected UserTO userTO; + + protected final Mode mode; + + private Fragment fragment = null; + + private final boolean resetPassword; + + protected final AjaxCheckBoxPanel storePassword; + + public UserModalPage(final PageReference callerPageRef, final ModalWindow window, final UserTO userTO, + final Mode mode, final boolean resetPassword) { + + super(); + + this.pageRef = callerPageRef; + this.window = window; + this.userTO = userTO; + this.mode = mode; + this.resetPassword = resetPassword; + + fragment = new Fragment("userModalFrag", "userModalEditFrag", this); + fragment.setOutputMarkupId(true); + add(fragment); + + storePassword = new AjaxCheckBoxPanel("storePassword", "storePassword", + new Model<Boolean>(Boolean.TRUE)); + } + + public UserTO getUserTO() { + return userTO; + } + + public void setUserTO(final UserTO userTO) { + this.userTO = userTO; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected Form setupEditPanel() { + fragment.add(new Label("id", userTO.getKey() == 0 + ? StringUtils.EMPTY + : userTO.getUsername())); + + fragment.add(new Label("new", userTO.getKey() == 0 + ? new ResourceModel("new") + : new Model(StringUtils.EMPTY))); + + final Form form = new Form("UserForm"); + form.setModel(new CompoundPropertyModel(userTO)); + + //-------------------------------- + // User details + //-------------------------------- + form.add(new UserDetailsPanel("details", userTO, form, resetPassword, mode == Mode.TEMPLATE)); + + form.add(new Label("statuspanel", "")); + + form.add(new Label("pwdChangeInfo", "")); + + form.add(new Label("securityQuestion", "")); + form.addOrReplace(new SecurityQuestionPanel("securityQuestion", userTO)); + + form.add(new Label("accountinformation", "")); + //-------------------------------- + + //-------------------------------- + // Store password internally checkbox + //-------------------------------- + final Fragment storePwdFragment = new Fragment("storePwdFrag", "storePwdCheck", form); + storePwdFragment.setOutputMarkupId(true); + final Label storePasswordLabel = new Label("storePasswordLabel", new ResourceModel("storePassword")); + storePwdFragment.add(storePasswordLabel); + storePwdFragment.add(storePassword); + form.add(userTO.getKey() == 0 && mode != Mode.TEMPLATE + ? storePwdFragment : new Fragment("storePwdFrag", "emptyFragment", form)); + //-------------------------------- + + //-------------------------------- + // Attributes panel + //-------------------------------- + form.add(new PlainAttrsPanel("plainAttrs", userTO, form, mode)); + //-------------------------------- + + //-------------------------------- + // Derived attributes panel + //-------------------------------- + form.add(new DerAttrsPanel("derAttrs", userTO)); + //-------------------------------- + + //-------------------------------- + // Virtual attributes panel + //-------------------------------- + form.add(new VirAttrsPanel("virAttrs", userTO, mode == Mode.TEMPLATE)); + //-------------------------------- + + //-------------------------------- + // Resources panel + //-------------------------------- + form.add(new ResourcesPanel.Builder("resources").attributableTO(userTO).build()); + //-------------------------------- + + //-------------------------------- + // Roles panel + //-------------------------------- + form.add(new MembershipsPanel("memberships", userTO, mode, null, getPageReference())); + //-------------------------------- + + final AjaxButton submit = getOnSubmit(); + + if (mode == Mode.ADMIN) { + String allowedRoles = userTO.getKey() == 0 + ? xmlRolesReader.getEntitlement("Users", "create") + : xmlRolesReader.getEntitlement("Users", "update"); + MetaDataRoleAuthorizationStrategy.authorize(submit, RENDER, allowedRoles); + } + + fragment.add(form); + form.add(submit); + form.setDefaultButton(submit); + + final AjaxButton cancel = new AjaxButton(CANCEL, new ResourceModel(CANCEL)) { + + private static final long serialVersionUID = 530608535790823587L; + + @Override + protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) { + window.close(target); + } + + @Override + protected void onError(final AjaxRequestTarget target, final Form<?> form) { + } + }; + + cancel.setDefaultFormProcessing(false); + form.add(cancel); + + return form; + } + + protected AjaxButton getOnSubmit() { + return new IndicatingAjaxButton(APPLY, new ResourceModel(SUBMIT)) { + + private static final long serialVersionUID = -958724007591692537L; + + @Override + protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) { + try { + submitAction(target, form); + + if (pageRef.getPage() instanceof BasePage) { + ((BasePage) pageRef.getPage()).setModalResult(true); + } + + closeAction(target, form); + } catch (Exception e) { + LOG.error("While creating or updating user", e); + error(getString(Constants.ERROR) + ": " + e.getMessage()); + feedbackPanel.refresh(target); + } + } + + @Override + protected void onError(final AjaxRequestTarget target, final Form<?> form) { + feedbackPanel.refresh(target); + } + }; + } + + protected abstract void submitAction(AjaxRequestTarget target, Form<?> form); + + protected abstract void closeAction(AjaxRequestTarget target, Form<?> form); +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/pages/UserOwnerSelectModalPage.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/UserOwnerSelectModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/UserOwnerSelectModalPage.java new file mode 100644 index 0000000..ae8a5da --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/UserOwnerSelectModalPage.java @@ -0,0 +1,81 @@ +/* + * 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.pages; + +import org.apache.syncope.client.console.commons.Constants; +import org.apache.syncope.client.console.panels.AbstractSearchResultPanel; +import org.apache.syncope.client.console.panels.SelectOnlyUserSearchResultPanel; +import org.apache.syncope.client.console.panels.UserSearchPanel; +import org.apache.wicket.PageReference; +import org.apache.wicket.Session; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.ResourceModel; + +public class UserOwnerSelectModalPage extends BaseModalPage { + + private static final long serialVersionUID = 2106489458494696439L; + + public UserOwnerSelectModalPage(final PageReference pageRef, final ModalWindow window) { + super(); + + final SelectOnlyUserSearchResultPanel searchResult = + new SelectOnlyUserSearchResultPanel("searchResult", true, null, pageRef, window, userRestClient); + add(searchResult); + + final Form<?> searchForm = new Form("searchForm"); + add(searchForm); + + final UserSearchPanel searchPanel = new UserSearchPanel.Builder("searchPanel").build(); + searchForm.add(searchPanel); + + searchForm.add(new IndicatingAjaxButton("search", new ResourceModel("search")) { + + private static final long serialVersionUID = -958724007591692537L; + + @Override + protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) { + final String searchCond = searchPanel.buildFIQL(); + doSearch(target, searchCond, searchResult); + + Session.get().getFeedbackMessages().clear(); + searchPanel.getSearchFeedback().refresh(target); + } + + @Override + protected void onError(final AjaxRequestTarget target, final Form<?> form) { + searchPanel.getSearchFeedback().refresh(target); + } + }); + + } + + private void doSearch(final AjaxRequestTarget target, final String fiql, + final AbstractSearchResultPanel resultsetPanel) { + + if (fiql == null) { + error(getString(Constants.SEARCH_ERROR)); + return; + } + + resultsetPanel.search(fiql, target); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/pages/UserSelfModalPage.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/UserSelfModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/UserSelfModalPage.java new file mode 100644 index 0000000..087bd69 --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/UserSelfModalPage.java @@ -0,0 +1,72 @@ +/* + * 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.pages; + +import org.apache.commons.lang3.SerializationUtils; +import org.apache.syncope.client.console.commons.Mode; +import org.apache.syncope.client.console.rest.UserSelfRestClient; +import org.apache.syncope.common.lib.AttributableOperations; +import org.apache.syncope.common.lib.mod.UserMod; +import org.apache.syncope.common.lib.to.UserTO; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.spring.injection.annot.SpringBean; + +/** + * Modal window with User form. + */ +public class UserSelfModalPage extends UserModalPage { + + private static final long serialVersionUID = 603212869211672852L; + + @SpringBean + private UserSelfRestClient restClient; + + private final UserTO initialUserTO; + + public UserSelfModalPage(final PageReference callerPageRef, final ModalWindow window, final UserTO userTO) { + super(callerPageRef, window, userTO, Mode.SELF, userTO.getKey() != 0); + + this.initialUserTO = SerializationUtils.clone(userTO); + setupEditPanel(); + } + + @Override + protected void submitAction(final AjaxRequestTarget target, final Form<?> form) { + final UserTO updatedUserTO = (UserTO) form.getModelObject(); + + if (updatedUserTO.getKey() == 0) { + restClient.create(updatedUserTO, storePassword.getModelObject()); + } else { + final UserMod userMod = AttributableOperations.diff(updatedUserTO, initialUserTO); + + // update user only if it has changed + if (!userMod.isEmpty()) { + restClient.update(userMod); + } + } + } + + @Override + protected void closeAction(final AjaxRequestTarget target, final Form<?> form) { + setResponsePage(new ResultStatusModalPage.Builder(window, userTO).mode(mode).build()); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/pages/UserTemplateModalPage.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/UserTemplateModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/UserTemplateModalPage.java new file mode 100644 index 0000000..2b04035 --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/UserTemplateModalPage.java @@ -0,0 +1,60 @@ +/* + * 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.pages; + +import org.apache.syncope.client.console.commons.Mode; +import org.apache.syncope.common.lib.to.SyncTaskTO; +import org.apache.syncope.common.lib.to.UserTO; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +import org.apache.wicket.markup.html.form.Form; + +/** + * Modal window with User form. + */ +public class UserTemplateModalPage extends UserModalPage { + + private static final long serialVersionUID = 511003221213581368L; + + private final SyncTaskTO syncTaskTO; + + public UserTemplateModalPage(final PageReference callerPageRef, final ModalWindow window, + final SyncTaskTO syncTaskTO) { + + super(callerPageRef, window, syncTaskTO.getUserTemplate() == null + ? new UserTO() + : syncTaskTO.getUserTemplate(), Mode.TEMPLATE, true); + + this.syncTaskTO = syncTaskTO; + + setupEditPanel(); + } + + @Override + protected void submitAction(final AjaxRequestTarget target, final Form form) { + syncTaskTO.setUserTemplate((UserTO) form.getModelObject()); + taskRestClient.updateSyncTask(syncTaskTO); + } + + @Override + protected void closeAction(final AjaxRequestTarget target, final Form form) { + window.close(target); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/pages/Users.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/Users.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/Users.java new file mode 100644 index 0000000..98f93bf --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/Users.java @@ -0,0 +1,166 @@ +/* + * 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.pages; + +import org.apache.syncope.client.console.commons.Constants; +import org.apache.syncope.client.console.panels.AbstractSearchResultPanel; +import org.apache.syncope.client.console.panels.AbstractSearchResultPanel.EventDataWrapper; +import org.apache.syncope.client.console.panels.UserSearchPanel; +import org.apache.syncope.client.console.panels.UserSearchResultPanel; +import org.apache.syncope.client.console.rest.UserRestClient; +import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxButton; +import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink; +import org.apache.syncope.common.lib.to.UserTO; +import org.apache.wicket.Page; +import org.apache.wicket.Session; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.AjaxLink; +import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; +import org.apache.wicket.event.Broadcast; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; + +public class Users extends BasePage { + + private static final long serialVersionUID = 134681165644474568L; + + private final static int EDIT_MODAL_WIN_HEIGHT = 550; + + private final static int EDIT_MODAL_WIN_WIDTH = 800; + + @SpringBean + private UserRestClient restClient; + + public Users(final PageParameters parameters) { + super(parameters); + + // Modal window for editing user attributes + final ModalWindow editModalWin = new ModalWindow("editModal"); + editModalWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY); + editModalWin.setInitialHeight(EDIT_MODAL_WIN_HEIGHT); + editModalWin.setInitialWidth(EDIT_MODAL_WIN_WIDTH); + editModalWin.setCookieName("edit-modal"); + add(editModalWin); + + final AbstractSearchResultPanel searchResult = + new UserSearchResultPanel("searchResult", true, null, getPageReference(), restClient); + add(searchResult); + + final AbstractSearchResultPanel listResult = + new UserSearchResultPanel("listResult", false, null, getPageReference(), restClient); + add(listResult); + + // create new user + final AjaxLink<Void> createLink = new ClearIndicatingAjaxLink<Void>("createLink", getPageReference()) { + + private static final long serialVersionUID = -7978723352517770644L; + + @Override + protected void onClickInternal(final AjaxRequestTarget target) { + editModalWin.setPageCreator(new ModalWindow.PageCreator() { + + private static final long serialVersionUID = -7834632442532690940L; + + @Override + public Page createPage() { + return new EditUserModalPage(Users.this.getPageReference(), editModalWin, new UserTO()); + } + }); + + editModalWin.show(target); + } + }; + MetaDataRoleAuthorizationStrategy.authorize( + createLink, ENABLE, xmlRolesReader.getEntitlement("Users", "create")); + add(createLink); + + setWindowClosedReloadCallback(editModalWin); + + final Form<?> searchForm = new Form<>("searchForm"); + add(searchForm); + + final UserSearchPanel searchPanel = new UserSearchPanel.Builder("searchPanel").build(); + searchForm.add(searchPanel); + + final ClearIndicatingAjaxButton searchButton = + new ClearIndicatingAjaxButton("search", new ResourceModel("search"), getPageReference()) { + + private static final long serialVersionUID = -958724007591692537L; + + @Override + protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) { + final String fiql = searchPanel.buildFIQL(); + LOG.debug("FIQL: " + fiql); + + doSearch(target, fiql, searchResult); + + Session.get().getFeedbackMessages().clear(); + searchPanel.getSearchFeedback().refresh(target); + } + + @Override + protected void onError(final AjaxRequestTarget target, final Form<?> form) { + + searchPanel.getSearchFeedback().refresh(target); + } + }; + + searchForm.add(searchButton); + searchForm.setDefaultButton(searchButton); + } + + private void doSearch(final AjaxRequestTarget target, final String fiql, + final AbstractSearchResultPanel resultsetPanel) { + + if (fiql == null) { + error(getString(Constants.SEARCH_ERROR)); + return; + } + + resultsetPanel.search(fiql, target); + } + + private void setWindowClosedReloadCallback(final ModalWindow window) { + window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() { + + private static final long serialVersionUID = 8804221891699487139L; + + @Override + public void onClose(final AjaxRequestTarget target) { + final EventDataWrapper data = new EventDataWrapper(); + data.setTarget(target); + data.setCreate(true); + + send(getPage(), Broadcast.BREADTH, data); + + if (isModalResult()) { + // reset modal result + setModalResult(false); + // set operation succeeded + getSession().info(getString(Constants.OPERATION_SUCCEEDED)); + // refresh feedback panel + feedbackPanel.refresh(target); + } + } + }); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/pages/ViewUserModalPage.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/ViewUserModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/ViewUserModalPage.java new file mode 100644 index 0000000..d47e07f --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/ViewUserModalPage.java @@ -0,0 +1,49 @@ +/* + * 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.pages; + +import org.apache.syncope.common.lib.to.UserTO; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.form.AjaxButton; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +import org.apache.wicket.markup.html.form.Form; + +public class ViewUserModalPage extends EditUserModalPage { + + private static final long serialVersionUID = -8715255026876951611L; + + public ViewUserModalPage(final PageReference callerPageRef, final ModalWindow window, final UserTO userTO) { + super(callerPageRef, window, userTO); + form.setEnabled(false); + form.get(CANCEL).setVisible(false); + } + + @Override + protected AjaxButton getOnSubmit() { + AjaxButton submit = super.getOnSubmit(); + submit.setVisible(false); + return submit; + } + + @Override + protected void submitAction(final AjaxRequestTarget target, final Form form) { + // No submit allowed, read-only form + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/pages/VirSchemaModalPage.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/VirSchemaModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/VirSchemaModalPage.java new file mode 100644 index 0000000..425b9cb --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/VirSchemaModalPage.java @@ -0,0 +1,126 @@ +/* + * 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.pages; + +import org.apache.syncope.client.console.commons.Constants; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel; +import org.apache.syncope.common.lib.SyncopeClientException; +import org.apache.syncope.common.lib.to.VirSchemaTO; +import org.apache.syncope.common.lib.types.AttributableType; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.form.AjaxButton; +import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; +import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.CompoundPropertyModel; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.ResourceModel; + +/** + * Modal window with Schema form. + */ +public class VirSchemaModalPage extends AbstractSchemaModalPage<VirSchemaTO> { + + private static final long serialVersionUID = 5979623248182851337L; + + public VirSchemaModalPage(final AttributableType kind) { + super(kind); + } + + @Override + public void setSchemaModalPage(final PageReference pageRef, final ModalWindow window, + VirSchemaTO schema, final boolean createFlag) { + + if (schema == null) { + schema = new VirSchemaTO(); + } + + final Form<VirSchemaTO> schemaForm = new Form<>(FORM); + + schemaForm.setModel(new CompoundPropertyModel<>(schema)); + + final AjaxTextFieldPanel name = + new AjaxTextFieldPanel("key", getString("key"), new PropertyModel<String>(schema, "key")); + name.addRequiredLabel(); + + name.setEnabled(createFlag); + + final AjaxCheckBoxPanel readonly = new AjaxCheckBoxPanel("readonly", getString("readonly"), + new PropertyModel<Boolean>(schema, "readonly")); + + final AjaxButton submit = new IndicatingAjaxButton(APPLY, new ResourceModel(SUBMIT)) { + + private static final long serialVersionUID = -958724007591692537L; + + @Override + protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) { + VirSchemaTO schemaTO = (VirSchemaTO) form.getDefaultModelObject(); + try { + if (createFlag) { + schemaRestClient.createVirSchema(kind, schemaTO); + } else { + schemaRestClient.updateVirSchema(kind, schemaTO); + } + if (pageRef.getPage() instanceof BasePage) { + ((BasePage) pageRef.getPage()).setModalResult(true); + } + + window.close(target); + } catch (SyncopeClientException e) { + error(getString(Constants.ERROR) + ": " + e.getMessage()); + feedbackPanel.refresh(target); + } + } + + @Override + protected void onError(final AjaxRequestTarget target, final Form<?> form) { + feedbackPanel.refresh(target); + } + }; + + final AjaxButton cancel = new IndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL)) { + + private static final long serialVersionUID = -958724007591692537L; + + @Override + protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) { + window.close(target); + } + }; + + cancel.setDefaultFormProcessing(false); + + String allowedRoles = createFlag + ? xmlRolesReader.getEntitlement("Schema", "create") + : xmlRolesReader.getEntitlement("Schema", "update"); + + MetaDataRoleAuthorizationStrategy.authorize(submit, ENABLE, allowedRoles); + + schemaForm.add(name); + schemaForm.add(readonly); + + schemaForm.add(submit); + schemaForm.add(cancel); + + add(schemaForm); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/pages/WelcomePage.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/WelcomePage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/WelcomePage.java new file mode 100644 index 0000000..d9f884d --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/WelcomePage.java @@ -0,0 +1,55 @@ +/* + * 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.pages; + +import org.apache.syncope.client.console.SyncopeApplication; +import org.apache.syncope.client.console.commons.XMLRolesReader; +import org.apache.syncope.client.console.rest.UserSelfRestClient; +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; + +/** + * Welcome page to display after successful login. + */ +public class WelcomePage extends WebPage { + + private static final long serialVersionUID = 8851399358753120581L; + + @SpringBean + private XMLRolesReader xmlRolesReader; + + @SpringBean + private UserSelfRestClient userSelfRestClient; + + public WelcomePage(final PageParameters parameters) { + super(parameters); + setupNavigationPanel(); + setupEditProfileModal(); + } + + //To prevent warning: "leaking this in constructor java" + private void setupNavigationPanel() { + ((SyncopeApplication) getApplication()).setupNavigationPanel(this, xmlRolesReader, false); + } + + private void setupEditProfileModal() { + ((SyncopeApplication) getApplication()).setupEditProfileModal(this, userSelfRestClient); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/pages/XMLEditorPopupPage.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/XMLEditorPopupPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/XMLEditorPopupPage.java new file mode 100644 index 0000000..b5a8d10 --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/XMLEditorPopupPage.java @@ -0,0 +1,90 @@ +/* + * 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.pages; + +import java.io.IOException; +import javax.ws.rs.core.MediaType; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.console.commons.Constants; +import org.apache.syncope.client.console.rest.WorkflowRestClient; +import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxButton; +import org.apache.syncope.common.lib.SyncopeClientException; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.form.AjaxButton; +import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; +import org.apache.wicket.markup.html.form.Button; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.TextArea; +import org.apache.wicket.model.Model; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.apache.wicket.util.io.IOUtils; + +public class XMLEditorPopupPage extends BasePopupPage { + + private static final long serialVersionUID = 5816041644635271734L; + + @SpringBean + private WorkflowRestClient wfRestClient; + + public XMLEditorPopupPage() { + Form wfForm = new Form("workflowDefForm"); + + String definition; + try { + definition = IOUtils.toString(wfRestClient.getDefinition(MediaType.APPLICATION_XML_TYPE)); + } catch (IOException e) { + LOG.error("Could not get workflow definition", e); + definition = StringUtils.EMPTY; + } + final TextArea<String> workflowDefArea = new TextArea<String>("workflowDefArea", new Model<String>(definition)); + wfForm.add(workflowDefArea); + + AjaxButton submit = + new ClearIndicatingAjaxButton(APPLY, new Model<String>(getString(SUBMIT)), getPageReference()) { + + private static final long serialVersionUID = -958724007591692537L; + + @Override + protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) { + try { + wfRestClient.updateDefinition( + MediaType.APPLICATION_XML_TYPE, workflowDefArea.getModelObject()); + info(getString(Constants.OPERATION_SUCCEEDED)); + } catch (SyncopeClientException scee) { + error(getString(Constants.ERROR) + ": " + scee.getMessage()); + } + feedbackPanel.refresh(target); + } + + @Override + protected void onError(final AjaxRequestTarget target, final Form<?> form) { + feedbackPanel.refresh(target); + } + }; + + final Button close = new Button("closePage", new Model<String>(getString(CANCEL))); + + MetaDataRoleAuthorizationStrategy.authorize( + submit, ENABLE, xmlRolesReader.getEntitlement("Configuration", "workflowDefUpdate")); + wfForm.add(submit); + wfForm.add(close); + this.add(wfForm); + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractExtensionPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractExtensionPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractExtensionPanel.java new file mode 100644 index 0000000..a785e9f --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractExtensionPanel.java @@ -0,0 +1,39 @@ +/* + * 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.syncope.client.console.commons.XMLRolesReader; +import org.apache.wicket.PageReference; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.spring.injection.annot.SpringBean; + +public abstract class AbstractExtensionPanel extends Panel { + + private static final long serialVersionUID = 4627828052717627159L; + + @SpringBean + protected XMLRolesReader xmlRolesReader; + + protected PageReference pageref; + + public AbstractExtensionPanel(final String id, final PageReference pageref) { + super(id); + this.pageref = pageref; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractProvisioningTasksPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractProvisioningTasksPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractProvisioningTasksPanel.java new file mode 100644 index 0000000..e066aac --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractProvisioningTasksPanel.java @@ -0,0 +1,160 @@ +/* + * 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.List; +import org.apache.syncope.client.console.commons.Constants; +import org.apache.syncope.client.console.pages.PushTaskModalPage; +import org.apache.syncope.client.console.pages.SyncTaskModalPage; +import org.apache.syncope.client.console.pages.Tasks; +import org.apache.syncope.client.console.pages.Tasks.TasksProvider; +import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink; +import org.apache.syncope.common.lib.to.AbstractProvisioningTaskTO; +import org.apache.syncope.common.lib.to.AbstractTaskTO; +import org.apache.syncope.common.lib.to.PushTaskTO; +import org.apache.syncope.common.lib.to.SyncTaskTO; +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.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.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.request.http.WebResponse; + +public abstract class AbstractProvisioningTasksPanel<T extends AbstractProvisioningTaskTO> extends AbstractTasks { + + private static final long serialVersionUID = -8674781241465369244L; + + private final int paginatorRows; + + protected WebMarkupContainer container; + + protected ModalWindow window; + + protected AjaxDataTablePanel<AbstractTaskTO, String> table; + + private final Class<T> reference; + + public AbstractProvisioningTasksPanel(final String id, final PageReference pageRef, final Class<T> reference) { + super(id, pageRef); + + this.reference = reference; + + container = new WebMarkupContainer("container"); + container.setOutputMarkupId(true); + add(container); + + window = new ModalWindow("taskWin"); + window.setCssClassName(ModalWindow.CSS_CLASS_GRAY); + window.setInitialHeight(WIN_HEIGHT); + window.setInitialWidth(WIN_WIDTH); + window.setCookieName(VIEW_TASK_WIN_COOKIE_NAME); + add(window); + + ((Tasks) pageRef.getPage()).setWindowClosedCallback(window, container); + + paginatorRows = prefMan.getPaginatorRows(getWebRequest(), Constants.PREF_SYNC_TASKS_PAGINATOR_ROWS); + } + + @Override + public void onEvent(final IEvent<?> event) { + if (event.getPayload() instanceof AbstractSearchResultPanel.EventDataWrapper) { + ((AbstractSearchResultPanel.EventDataWrapper) event.getPayload()).getTarget().add(container); + } + } + + protected void initTasksTable() { + + table = Tasks.updateTaskTable( + getColumns(), + new TasksProvider<T>(restClient, paginatorRows, getId(), this.reference), + container, + 0, + this.pageRef, + restClient); + + 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_SYNC_TASKS_PAGINATOR_ROWS, + String.valueOf(paginatorRows)); + + table = Tasks.updateTaskTable( + getColumns(), + new TasksProvider<T>(restClient, paginatorRows, getId(), reference), + container, + table == null ? 0 : (int) table.getCurrentPage(), + pageRef, + restClient); + + target.add(container); + } + }); + + paginatorForm.add(rowsChooser); + container.add(paginatorForm); + + // create new task + AjaxLink<Void> createLink = new ClearIndicatingAjaxLink<Void>("createLink", pageRef) { + + private static final long serialVersionUID = -7978723352517770644L; + + @Override + protected void onClickInternal(final AjaxRequestTarget target) { + window.setPageCreator(new ModalWindow.PageCreator() { + + private static final long serialVersionUID = -7834632442532690940L; + + @Override + public Page createPage() { + return reference.equals(SyncTaskTO.class) + ? new SyncTaskModalPage(window, new SyncTaskTO(), pageRef) + : new PushTaskModalPage(window, new PushTaskTO(), pageRef); + } + }); + + window.show(target); + } + }; + + MetaDataRoleAuthorizationStrategy.authorize( + createLink, RENDER, xmlRolesReader.getEntitlement(TASKS, "create")); + + add(createLink); + + } + + protected abstract List<IColumn<AbstractTaskTO, String>> getColumns(); +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchPanel.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchPanel.java new file mode 100644 index 0000000..d610739 --- /dev/null +++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchPanel.java @@ -0,0 +1,401 @@ +/* + * 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.List; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.cxf.jaxrs.ext.search.ConditionType; +import org.apache.cxf.jaxrs.ext.search.SearchBean; +import org.apache.cxf.jaxrs.ext.search.SearchCondition; +import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition; +import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser; +import org.apache.syncope.client.console.rest.AuthRestClient; +import org.apache.syncope.client.console.rest.ResourceRestClient; +import org.apache.syncope.client.console.rest.SchemaRestClient; +import org.apache.syncope.common.lib.search.RoleFiqlSearchConditionBuilder; +import org.apache.syncope.common.lib.search.SearchableFields; +import org.apache.syncope.common.lib.search.SpecialAttr; +import org.apache.syncope.common.lib.search.SyncopeFiqlSearchConditionBuilder; +import org.apache.syncope.common.lib.search.SyncopeProperty; +import org.apache.syncope.common.lib.search.UserFiqlSearchConditionBuilder; +import org.apache.syncope.common.lib.to.ResourceTO; +import org.apache.syncope.common.lib.types.AttributableType; +import org.apache.syncope.common.lib.types.SubjectType; +import org.apache.wicket.feedback.FeedbackMessage; +import org.apache.wicket.feedback.IFeedbackMessageFilter; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.LoadableDetachableModel; +import org.apache.wicket.spring.injection.annot.SpringBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractSearchPanel extends Panel { + + private static final long serialVersionUID = 5922413053568696414L; + + /** + * Logger. + */ + protected static final Logger LOG = LoggerFactory.getLogger(AbstractSearchPanel.class); + + @SpringBean + protected SchemaRestClient schemaRestClient; + + @SpringBean + protected ResourceRestClient resourceRestClient; + + @SpringBean + protected AuthRestClient authRestClient; + + protected IModel<List<String>> dnames; + + protected IModel<List<String>> anames; + + protected IModel<List<String>> resourceNames; + + protected IModel<List<String>> entitlements; + + protected IModel<List<SearchClause.Type>> types; + + protected IModel<List<String>> roleNames; + + protected NotificationPanel searchFeedback; + + protected List<SearchClause> searchClauses; + + protected WebMarkupContainer searchFormContainer; + + protected AttributableType attributableType; + + protected boolean required; + + protected AbstractSearchPanel(final String id, final AttributableType attributableType) { + this(id, attributableType, null, true); + } + + protected AbstractSearchPanel(final String id, final AttributableType attributableType, + final String fiql, final boolean required) { + + super(id); + populate(); + + this.attributableType = attributableType; + this.required = required; + + setOutputMarkupId(true); + + searchFormContainer = new WebMarkupContainer("searchFormContainer"); + searchFormContainer.setOutputMarkupId(true); + + searchFeedback = new NotificationPanel("searchFeedback", "notificationpanel_top_right", + new IFeedbackMessageFilter() { + + private static final long serialVersionUID = 6895024863321391672L; + + @Override + public boolean accept(final FeedbackMessage message) { + boolean result; + + // messages reported on the session have a null reporter + if (message.getReporter() == null) { + result = false; + } else { + // only accept messages coming from the children of the search form container + result = searchFormContainer.contains(message.getReporter(), true); + } + + return result; + } + }); + searchFeedback.setOutputMarkupId(true); + add(searchFeedback); + + this.searchClauses = new ArrayList<>(); + this.searchClauses.add(new SearchClause()); + if (StringUtils.isNotBlank(fiql)) { + try { + FiqlParser<SearchBean> fiqlParser = new FiqlParser<>( + SearchBean.class, SyncopeFiqlSearchConditionBuilder.CONTEXTUAL_PROPERTIES); + List<SearchClause> parsed = getSearchClauses(fiqlParser.parse(fiql)); + + this.searchClauses.clear(); + this.searchClauses.addAll(parsed); + } catch (Exception e) { + LOG.error("Unparseable FIQL expression '{}'", fiql, e); + } + } + + searchFormContainer.add(new SearchView("searchView", searchClauses, searchFormContainer, required, + types, anames, dnames, roleNames, resourceNames, entitlements)); + add(searchFormContainer); + } + + protected void populate() { + dnames = new LoadableDetachableModel<List<String>>() { + + private static final long serialVersionUID = 5275935387613157437L; + + @Override + protected List<String> load() { + return SearchableFields.get( + attributableType == AttributableType.USER ? SubjectType.USER : SubjectType.ROLE); + } + }; + + anames = new LoadableDetachableModel<List<String>>() { + + private static final long serialVersionUID = 5275935387613157437L; + + @Override + protected List<String> load() { + return schemaRestClient.getPlainSchemaNames(attributableType); + } + }; + + resourceNames = new LoadableDetachableModel<List<String>>() { + + private static final long serialVersionUID = 5275935387613157437L; + + @Override + protected List<String> load() { + List<ResourceTO> resourceTOs = resourceRestClient.getAll(); + + List<String> result = new ArrayList<>(resourceTOs.size()); + + for (ResourceTO resource : resourceTOs) { + result.add(resource.getKey()); + } + + return result; + } + }; + + entitlements = new LoadableDetachableModel<List<String>>() { + + private static final long serialVersionUID = 5275935387613157437L; + + @Override + protected List<String> load() { + List<String> result = authRestClient.getOwnedEntitlements(); + Collections.sort(result); + return result; + } + }; + } + + public NotificationPanel getSearchFeedback() { + return searchFeedback; + } + + private SearchClause getPrimitiveSearchClause(final SearchCondition<SearchBean> sc) { + SearchClause searchClause = new SearchClause(); + + String property = sc.getCondition().getKeySet().iterator().next(); + searchClause.setProperty(property); + String value = sc.getCondition().get(property); + searchClause.setValue(value); + + if (SpecialAttr.ROLES.toString().equals(property)) { + searchClause.setType(SearchClause.Type.MEMBERSHIP); + for (String label : roleNames.getObject()) { + if (value.equals(label.substring(0, label.indexOf(' ')))) { + searchClause.setProperty(label); + } + } + } else if (SpecialAttr.RESOURCES.toString().equals(property)) { + searchClause.setType(SearchClause.Type.RESOURCE); + } else if (SpecialAttr.ENTITLEMENTS.toString().equals(property)) { + searchClause.setType(SearchClause.Type.ENTITLEMENT); + } else { + searchClause.setType(SearchClause.Type.ATTRIBUTE); + } + + switch (sc.getConditionType()) { + case EQUALS: + searchClause.setComparator(SpecialAttr.NULL.toString().equals(value) + ? SearchClause.Comparator.IS_NULL : SearchClause.Comparator.EQUALS); + break; + + case NOT_EQUALS: + searchClause.setComparator(SpecialAttr.NULL.toString().equals(value) + ? SearchClause.Comparator.IS_NOT_NULL : SearchClause.Comparator.NOT_EQUALS); + break; + + case GREATER_OR_EQUALS: + searchClause.setComparator(SearchClause.Comparator.GREATER_OR_EQUALS); + break; + + case GREATER_THAN: + searchClause.setComparator(SearchClause.Comparator.GREATER_THAN); + break; + + case LESS_OR_EQUALS: + searchClause.setComparator(SearchClause.Comparator.LESS_OR_EQUALS); + break; + + case LESS_THAN: + searchClause.setComparator(SearchClause.Comparator.LESS_THAN); + break; + + default: + break; + } + + return searchClause; + } + + private List<SearchClause> getCompoundSearchClause(final SearchCondition<SearchBean> sc) { + List<SearchClause> clauses = new ArrayList<SearchClause>(); + + for (SearchCondition<SearchBean> searchCondition : sc.getSearchConditions()) { + if (searchCondition.getStatement() == null) { + clauses.addAll(getCompoundSearchClause(searchCondition)); + } else { + SearchClause clause = getPrimitiveSearchClause(searchCondition); + if (sc.getConditionType() == ConditionType.AND) { + clause.setOperator(SearchClause.Operator.AND); + } + if (sc.getConditionType() == ConditionType.OR) { + clause.setOperator(SearchClause.Operator.OR); + } + clauses.add(clause); + } + } + + return clauses; + } + + private List<SearchClause> getSearchClauses(final SearchCondition<SearchBean> sc) { + List<SearchClause> clauses = new ArrayList<SearchClause>(); + + if (sc.getStatement() == null) { + clauses.addAll(getCompoundSearchClause(sc)); + } else { + clauses.add(getPrimitiveSearchClause(sc)); + } + + return clauses; + } + + protected abstract SyncopeFiqlSearchConditionBuilder getSearchConditionBuilder(); + + public String buildFIQL() { + LOG.debug("Generating FIQL from List<SearchClause>: {}", searchClauses); + + if (searchClauses.isEmpty() || searchClauses.get(0).getType() == null) { + return StringUtils.EMPTY; + } + + SyncopeFiqlSearchConditionBuilder builder = getSearchConditionBuilder(); + + CompleteCondition prevCondition; + CompleteCondition condition = null; + for (int i = 0; i < searchClauses.size(); i++) { + prevCondition = condition; + + switch (searchClauses.get(i).getType()) { + case ENTITLEMENT: + condition = searchClauses.get(i).getComparator() == SearchClause.Comparator.EQUALS + ? ((RoleFiqlSearchConditionBuilder) builder). + hasEntitlements(searchClauses.get(i).getProperty()) + : ((RoleFiqlSearchConditionBuilder) builder). + hasNotEntitlements(searchClauses.get(i).getProperty()); + break; + + case MEMBERSHIP: + Long roleId = NumberUtils.toLong(searchClauses.get(i).getProperty().split(" ")[0]); + condition = searchClauses.get(i).getComparator() == SearchClause.Comparator.EQUALS + ? ((UserFiqlSearchConditionBuilder) builder).hasRoles(roleId) + : ((UserFiqlSearchConditionBuilder) builder).hasNotRoles(roleId); + break; + + case RESOURCE: + condition = searchClauses.get(i).getComparator() == SearchClause.Comparator.EQUALS + ? builder.hasResources(searchClauses.get(i).getProperty()) + : builder.hasNotResources(searchClauses.get(i).getProperty()); + break; + + case ATTRIBUTE: + SyncopeProperty property = builder.is(searchClauses.get(i).getProperty()); + switch (searchClauses.get(i).getComparator()) { + case IS_NULL: + condition = builder.isNull(searchClauses.get(i).getProperty()); + break; + + case IS_NOT_NULL: + condition = builder.isNotNull(searchClauses.get(i).getProperty()); + break; + + case LESS_THAN: + condition = StringUtils.isNumeric(searchClauses.get(i).getProperty()) + ? property.lessThan(NumberUtils.toDouble(searchClauses.get(i).getValue())) + : property.lexicalBefore(searchClauses.get(i).getValue()); + break; + + case LESS_OR_EQUALS: + condition = StringUtils.isNumeric(searchClauses.get(i).getProperty()) + ? property.lessOrEqualTo(NumberUtils.toDouble(searchClauses.get(i).getValue())) + : property.lexicalNotAfter(searchClauses.get(i).getValue()); + break; + + case GREATER_THAN: + condition = StringUtils.isNumeric(searchClauses.get(i).getProperty()) + ? property.greaterThan(NumberUtils.toDouble(searchClauses.get(i).getValue())) + : property.lexicalAfter(searchClauses.get(i).getValue()); + break; + + case GREATER_OR_EQUALS: + condition = StringUtils.isNumeric(searchClauses.get(i).getProperty()) + ? property.greaterOrEqualTo(NumberUtils.toDouble(searchClauses.get(i).getValue())) + : property.lexicalNotBefore(searchClauses.get(i).getValue()); + break; + + case NOT_EQUALS: + condition = property.notEqualTo(searchClauses.get(i).getValue()); + break; + + case EQUALS: + default: + condition = property.equalTo(searchClauses.get(i).getValue()); + break; + } + default: + break; + } + + if (i > 0) { + if (searchClauses.get(i).getOperator() == SearchClause.Operator.AND) { + condition = builder.and(prevCondition, condition); + } + if (searchClauses.get(i).getOperator() == SearchClause.Operator.OR) { + condition = builder.or(prevCondition, condition); + } + } + } + + String fiql = condition == null ? StringUtils.EMPTY : condition.query(); + LOG.debug("Generated FIQL: {}", fiql); + return fiql; + } +}
