From dd17f1fa12c0f03dee668982684691833e7417dd Mon Sep 17 00:00:00 2001 From: jensp Date: Wed, 14 Jun 2017 12:47:28 +0000 Subject: [PATCH] CccNG/ccm-core: Some files for the Vaadin prototype git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4781 8810af33-2d31-482b-a856-94f89814c4df --- .../ui/usersgroupsroles/GroupDetails.java | 302 ++++++++++++++++++ .../GroupMembersController.java | 96 ++++++ .../GroupMembersTableDataProvider.java | 143 +++++++++ .../ui/usersgroupsroles/RoleDetails.java | 33 ++ .../usersgroupsroles/UserSelectionAction.java | 34 ++ .../ui/usersgroupsroles/UserSelector.java | 134 ++++++++ .../UserSelectorDataProvider.java | 121 +++++++ 7 files changed, 863 insertions(+) create mode 100644 ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupDetails.java create mode 100644 ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupMembersController.java create mode 100644 ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupMembersTableDataProvider.java create mode 100644 ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/RoleDetails.java create mode 100644 ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelectionAction.java create mode 100644 ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelector.java create mode 100644 ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelectorDataProvider.java diff --git a/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupDetails.java b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupDetails.java new file mode 100644 index 000000000..ba342ce02 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupDetails.java @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.admin.ui.usersgroupsroles; + +import com.arsdigita.ui.admin.AdminUiConstants; + +import com.vaadin.data.HasValue; +import com.vaadin.icons.VaadinIcons; +import com.vaadin.server.Page; +import com.vaadin.server.UserError; +import com.vaadin.ui.Button; +import com.vaadin.ui.FormLayout; +import com.vaadin.ui.Grid; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Panel; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.TextField; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.Window; +import com.vaadin.ui.components.grid.HeaderCell; +import com.vaadin.ui.components.grid.HeaderRow; +import com.vaadin.ui.renderers.ButtonRenderer; +import com.vaadin.ui.themes.ValoTheme; +import org.libreccm.admin.ui.ConfirmDiscardDialog; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.security.Group; +import org.libreccm.security.GroupManager; +import org.libreccm.security.GroupRepository; +import org.libreccm.security.User; +import org.libreccm.security.UserRepository; + +import java.util.ArrayList; +import java.util.List; +import java.util.ResourceBundle; +import java.util.stream.Collectors; + +/** + * + * @author Jens Pelzetter + */ +public class GroupDetails extends Window { + + private static final long serialVersionUID = 4252189590984878037L; + + private static final String COL_USER_NAME = "username"; + private static final String COL_GIVEN_NAME = "given_name"; + private static final String COL_FAMILY_NAME = "family_name"; + private static final String COL_EMAIL = "email"; + private static final String COL_REMOVE = "remove"; + + private final UsersGroupsRoles usersGroupsRoles; + private final Group group; + private final GroupRepository groupRepo; + private final GroupManager groupManager; + + private boolean dataHasChanged = false; + + private Label groupNameDisplay; + private TextField groupNameField; + private Button editButton; + private HorizontalLayout saveCancelButtons; + + public GroupDetails(final Group group, + final UsersGroupsRoles usersGroupsRoles, + final GroupRepository groupRepo, + final GroupManager groupManager) { + + super(String.format("Edit group %s", group.getName())); + + this.group = group; + this.usersGroupsRoles = usersGroupsRoles; + this.groupRepo = groupRepo; + this.groupManager = groupManager; + + addWidgets(); + } + + private void addWidgets() { + + final ResourceBundle bundle = ResourceBundle + .getBundle(AdminUiConstants.ADMIN_BUNDLE, + UI.getCurrent().getLocale()); + + final GroupDetails.DataHasChangedListener dataHasChangedListener + = new GroupDetails.DataHasChangedListener(); + + groupNameDisplay = new Label(); + groupNameDisplay.setCaption(bundle + .getString("ui.admin.group_edit.groupname.label")); + + groupNameField = new TextField(bundle + .getString("ui.admin.group_edit.groupname.label")); + groupNameField.setRequiredIndicatorVisible(true); + + editButton = new Button("ui.admin.group.edit"); + editButton.addClickListener(event -> { + groupNameDisplay.setVisible(false); + groupNameField.setVisible(true); + editButton.setVisible(false); + saveCancelButtons.setVisible(true); + }); + + final Button submit = new Button(); + submit.setCaption(bundle.getString("ui.admin.save")); + submit.addClickListener(event -> saveGroup()); + + final Button cancel = new Button(bundle.getString("ui.admin.cancel")); + cancel.addClickListener(event -> { + groupNameField.setValue(group.getName()); + groupNameField.setVisible(false); + saveCancelButtons.setVisible(false); + editButton.setVisible(true); + groupNameDisplay.setVisible(true); + }); + + saveCancelButtons = new HorizontalLayout(submit, cancel); + + final FormLayout formLayout = new FormLayout(groupNameDisplay, + groupNameField); + groupNameField.setVisible(false); + + groupNameField.addValueChangeListener(dataHasChangedListener); + + final VerticalLayout layout = new VerticalLayout(formLayout, + editButton, + saveCancelButtons); + saveCancelButtons.setVisible(false); + + final Panel propertiesPanel = new Panel(layout); + propertiesPanel.setCaption(bundle + .getString("ui.admin.group_details.edit")); + + groupNameDisplay.setValue(group.getName()); + groupNameField.setValue(group.getName()); + + dataHasChanged = false; + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final GroupMembersController controller = cdiUtil + .findBean(GroupMembersController.class); + + final Grid membersGrid = new Grid<>(); + membersGrid.addColumn(User::getName) + .setId(COL_USER_NAME) + .setCaption("User Name"); + membersGrid.addColumn(User::getGivenName) + .setId(COL_GIVEN_NAME) + .setCaption("Given name"); + membersGrid.addColumn(User::getFamilyName) + .setId(COL_FAMILY_NAME) + .setCaption("Family name"); + membersGrid + .addColumn(user -> user.getPrimaryEmailAddress().getAddress()) + .setId(COL_EMAIL) + .setCaption("E-Mail"); + membersGrid.addColumn(user -> bundle.getString( + "ui.groups.members.remove"), + new ButtonRenderer<>(event -> { + controller + .removeMemberFromGroup(event.getItem(), + group); + membersGrid.getDataProvider().refreshAll(); + })) + .setId(COL_REMOVE); + + membersGrid.setWidth("100%"); + + final UserRepository userRepo = cdiUtil.findBean(UserRepository.class); + + final HeaderRow membersGridHeader = membersGrid.prependHeaderRow(); + final Button addMemberButton = new Button("Add member"); + addMemberButton.setIcon(VaadinIcons.PLUS); + addMemberButton.setStyleName(ValoTheme.BUTTON_TINY); + addMemberButton.addClickListener(event -> { + final UserSelector userSelector = new UserSelector( + "Select users to add to group", + "Add selected users to group", + usersGroupsRoles, + userRepo.findByGroup(group), + (selectedUsers -> { + selectedUsers.forEach(user -> { + controller.addMembersToGroup(selectedUsers, group); + membersGrid.getDataProvider().refreshAll(); + }); + })); + userSelector.center(); + UI.getCurrent().addWindow(userSelector); + }); + final HeaderCell membersGridHeaderCell = membersGridHeader + .join(COL_USER_NAME, + COL_GIVEN_NAME, + COL_FAMILY_NAME, + COL_EMAIL, + COL_REMOVE); + membersGridHeaderCell + .setComponent(new HorizontalLayout(addMemberButton)); + + final GroupMembersTableDataProvider dataProvider = cdiUtil + .findBean(GroupMembersTableDataProvider.class); + dataProvider.setGroup(group); + membersGrid.setDataProvider(dataProvider); + + final TabSheet tabs = new TabSheet(); + tabs.addTab(membersGrid, "Members"); + tabs.addTab(new Label("Roles Placeholder"), "Roles"); + +// final Panel membersPanel = new Panel("Members"); +// membersPanel.setContent(membersGrid); +// final VerticalLayout windowLayout = new VerticalLayout(propertiesPanel, +// membersPanel); + final VerticalLayout windowLayout = new VerticalLayout(propertiesPanel, + tabs); + + setContent(windowLayout); + } + + @Override + public void close() { + + if (dataHasChanged) { + final ResourceBundle bundle = ResourceBundle + .getBundle(AdminUiConstants.ADMIN_BUNDLE, + UI.getCurrent().getLocale()); + + final ConfirmDiscardDialog dialog = new ConfirmDiscardDialog( + this, + bundle.getString("ui.admin.group_edit.discard_confirm")); + dialog.setModal(true); + UI.getCurrent().addWindow(dialog); + } else { + super.close(); + } + } + + protected void saveGroup() { + + final ResourceBundle bundle = ResourceBundle + .getBundle(AdminUiConstants.ADMIN_BUNDLE, + UI.getCurrent().getLocale()); + + boolean valid = true; + + if (groupNameField.getValue() == null + || groupNameField.getValue().trim().isEmpty()) { + + groupNameField.setComponentError(new UserError( + bundle.getString("ui.admin.group_edit.groupname.error.notempty"))); + valid = false; + } + + if (!valid) { + return; + } + + final String notificationText; + group.setName(groupNameField.getValue()); + notificationText = String.format("Saved changes to group %s", + group.getName()); + + groupRepo.save(group); + + dataHasChanged = false; + if (usersGroupsRoles != null) { + usersGroupsRoles.refreshGroups(); + } + close(); + new Notification(notificationText, Notification.Type.TRAY_NOTIFICATION) + .show(Page.getCurrent()); + } + + private class DataHasChangedListener + implements HasValue.ValueChangeListener { + + private static final long serialVersionUID = -1410903365203533072L; + + @Override + public void valueChange(final HasValue.ValueChangeEvent event) { + dataHasChanged = true; + } + + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupMembersController.java b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupMembersController.java new file mode 100644 index 000000000..02040f310 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupMembersController.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.admin.ui.usersgroupsroles; + +import org.libreccm.security.Group; +import org.libreccm.security.GroupManager; +import org.libreccm.security.GroupRepository; +import org.libreccm.security.User; +import org.libreccm.security.UserRepository; + +import java.util.Set; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.transaction.Transactional; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +class GroupMembersController { + + @Inject + private UserRepository userRepo; + + @Inject + private GroupRepository groupRepo; + + @Inject + private GroupManager groupManager; + + @Transactional(Transactional.TxType.REQUIRED) + public void addMembersToGroup(final Set users, final Group group) { + + users.forEach(user -> addMemberToGroup(user, group)); + } + + @Transactional(Transactional.TxType.REQUIRED) + public void addMemberToGroup(final User user, final Group group) { + + final User theUser = userRepo + .findById(user.getPartyId()) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No user with id %d in the database. " + + "Where did that ID come from?", + user.getPartyId()))); + + final Group theGroup = groupRepo + .findById(group.getPartyId()) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No group with id %d in the database. " + + "Where did that ID come from?", + group.getPartyId()))); + + groupManager.addMemberToGroup(theUser, theGroup); + } + + @Transactional(Transactional.TxType.REQUIRED) + public void removeMemberFromGroup(final User member, final Group group) { + + final User theMember = userRepo + .findById(member.getPartyId()) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No user with id %d in the database. " + + "Where did that ID come from?", + member.getPartyId()))); + + final Group theGroup = groupRepo + .findById(group.getPartyId()) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No group with id %d in the database. " + + "Where did that ID come from?", + group.getPartyId()))); + + groupManager.removeMemberFromGroup(theMember, theGroup); + } + + +} diff --git a/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupMembersTableDataProvider.java b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupMembersTableDataProvider.java new file mode 100644 index 000000000..62311fc09 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/GroupMembersTableDataProvider.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.admin.ui.usersgroupsroles; + +import com.vaadin.cdi.ViewScoped; +import com.vaadin.data.provider.AbstractDataProvider; +import com.vaadin.data.provider.Query; +import org.libreccm.security.Group; +import org.libreccm.security.GroupMembership; +import org.libreccm.security.User; + +import java.util.Objects; +import java.util.stream.Stream; + +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; +import javax.transaction.Transactional; + +/** + * + * @author Jens Pelzetter + */ +@ViewScoped +public class GroupMembersTableDataProvider + extends AbstractDataProvider { + + private static final long serialVersionUID = -1924910843845830008L; + + @Inject + private EntityManager entityManager; + + private Group group; + + @Override + public boolean isInMemory() { + return false; + } + + @Override + public int size(Query query) { + + Objects.requireNonNull(group, + "This data provider needs to be initalized " + + "by calling setGroup(Group) before calling " + + "the count method."); + + final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = builder.createQuery(Long.class); +// final Root from = criteriaQuery.from(User.class); +// final Join memberships = from.join("groups"); +// +// criteriaQuery = criteriaQuery.select(builder.count(from)); +// +// criteriaQuery.where(builder.equal(memberships.get("group"), +// group)); +// criteriaQuery +// .where(builder +// .equal(builder.treat(from.get("groups"), +// GroupMembership.class).get("group"), +// group)); + + final Root from = criteriaQuery + .from(GroupMembership.class); + + criteriaQuery = criteriaQuery.select(builder.count(from)); + criteriaQuery.where(builder.equal(from.get("group"), group)); + + return entityManager + .createQuery(criteriaQuery) + .getSingleResult() + .intValue(); + } + + @Transactional(Transactional.TxType.REQUIRED) + @Override + public Stream fetch(final Query query) { + + Objects.requireNonNull(group, + "This data provider needs to be initalized " + + "by calling setGroup(Group) before calling " + + "the fetch method."); + + final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); +// final CriteriaQuery criteriaQuery = builder +// .createQuery(User.class); +// final Root from = criteriaQuery.from(User.class); +// final Join memberships = from +// .join("memberships"); +// +// criteriaQuery.where(builder.equal(memberships.get("group"), +// group)); +// +// return entityManager +// .createQuery(criteriaQuery) +// .setMaxResults(query.getLimit()) +// .setFirstResult(query.getOffset()) +// .getResultList() +// .stream(); + + final CriteriaQuery criteriaQuery = builder + .createQuery(GroupMembership.class); + final Root from = criteriaQuery + .from(GroupMembership.class); + final Join join = from.join("member"); + criteriaQuery + .where(builder.equal(from.get("group"), group)) + .orderBy(builder.asc(join.get("name"))); + + return entityManager + .createQuery(criteriaQuery) + .setMaxResults(query.getLimit()) + .setFirstResult(query.getOffset()) + .getResultList() + .stream() + .map(membership -> membership.getMember()); + } + + public void setGroup(final Group group) { + Objects.requireNonNull(group); + this.group = group; + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/RoleDetails.java b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/RoleDetails.java new file mode 100644 index 000000000..f962c0718 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/RoleDetails.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.admin.ui.usersgroupsroles; + +import com.vaadin.ui.Window; + +/** + * + * @author Jens Pelzetter + */ +public class RoleDetails extends Window { + + private static final long serialVersionUID = 8109931561947913438L; + + + +} diff --git a/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelectionAction.java b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelectionAction.java new file mode 100644 index 000000000..126975e9e --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelectionAction.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.admin.ui.usersgroupsroles; + +import org.libreccm.security.User; + +import java.util.Set; + +/** + * + * @author Jens Pelzetter + */ +@FunctionalInterface +public interface UserSelectionAction { + + void action(Set selectedUsers); + +} diff --git a/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelector.java b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelector.java new file mode 100644 index 000000000..7c1def8e0 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelector.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.admin.ui.usersgroupsroles; + +import com.arsdigita.ui.admin.AdminUiConstants; + +import com.vaadin.icons.VaadinIcons; +import com.vaadin.ui.Button; +import com.vaadin.ui.Grid; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.UI; +import com.vaadin.ui.Window; +import com.vaadin.ui.components.grid.HeaderCell; +import com.vaadin.ui.components.grid.HeaderRow; +import com.vaadin.ui.themes.ValoTheme; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.security.User; +import org.libreccm.security.UserRepository; + +import java.util.List; +import java.util.ResourceBundle; + +/** + * + * @author Jens Pelzetter + */ +public class UserSelector extends Window { + + private static final long serialVersionUID = -6227551833159691370L; + + private static final String COL_USER_NAME = "username"; + private static final String COL_GIVEN_NAME = "given_name"; + private static final String COL_FAMILY_NAME = "family_name"; + private static final String COL_EMAIL = "email"; + + private final UserRepository userRepo; + + private final UserSelectionAction groupSelectionAction; + + public UserSelector(final String caption, + final String actionLabel, + final UsersGroupsRoles usersGroupsRoles, + final List excludedUsers, + final UserSelectionAction action) { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + userRepo = cdiUtil.findBean(UserRepository.class); + this.groupSelectionAction = action; + + addWidgets(caption, actionLabel, excludedUsers, action); + } + + private void addWidgets(final String caption, + final String actionLabel, + final List excludedUsers, + final UserSelectionAction action) { + + setCaption(caption); + + final ResourceBundle bundle = ResourceBundle + .getBundle(AdminUiConstants.ADMIN_BUNDLE, + UI.getCurrent().getLocale()); + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + + final Grid usersGrid = new Grid<>(); + usersGrid.addColumn(User::getName) + .setId(COL_USER_NAME) + .setCaption("User Name"); + usersGrid.addColumn(User::getGivenName) + .setId(COL_GIVEN_NAME) + .setCaption("Given name"); + usersGrid.addColumn(User::getFamilyName) + .setId(COL_FAMILY_NAME) + .setCaption("Family name"); + usersGrid + .addColumn(user -> user.getPrimaryEmailAddress().getAddress()) + .setId(COL_EMAIL) + .setCaption("E-Mail"); + + usersGrid.setSelectionMode(Grid.SelectionMode.MULTI); + usersGrid.setWidth("100%"); + + final Button actionButton = new Button(actionLabel); + actionButton.addClickListener(event -> { + action.action(usersGrid.getSelectedItems()); + close(); + }); + actionButton.setIcon(VaadinIcons.PLUS_CIRCLE_O); + actionButton.setStyleName(ValoTheme.BUTTON_TINY); + + final Button clearButton = new Button("Clear selection"); + clearButton.addClickListener(event -> { + usersGrid.getSelectionModel().deselectAll(); + }); + clearButton.setIcon(VaadinIcons.BACKSPACE); + clearButton.setStyleName(ValoTheme.BUTTON_TINY); + + final HeaderRow actions = usersGrid.prependHeaderRow(); + final HeaderCell actionsCell = actions.join(COL_USER_NAME, + COL_GIVEN_NAME, + COL_FAMILY_NAME, + COL_EMAIL); + actionsCell.setComponent(new HorizontalLayout(actionButton, + clearButton)); + + final UserSelectorDataProvider dataProvider = cdiUtil + .findBean(UserSelectorDataProvider.class); + + dataProvider.setExcludedUsers(excludedUsers); + + usersGrid.setDataProvider(dataProvider); + + setContent(usersGrid); + + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelectorDataProvider.java b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelectorDataProvider.java new file mode 100644 index 000000000..550789e40 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/admin/ui/usersgroupsroles/UserSelectorDataProvider.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.admin.ui.usersgroupsroles; + +import com.vaadin.cdi.ViewScoped; +import com.vaadin.data.provider.AbstractDataProvider; +import com.vaadin.data.provider.Query; +import org.libreccm.security.User; + +import java.util.List; +import java.util.stream.Stream; + +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Root; +import javax.transaction.Transactional; + +/** + * + * @author Jens Pelzetter + */ +@ViewScoped +public class UserSelectorDataProvider extends AbstractDataProvider { + + private static final long serialVersionUID = -9019928941945017145L; + + @Inject + private EntityManager entityManager; + + private String userNameFilter; + + private List excludedUsers; + + @Override + public boolean isInMemory() { + return false; + } + + @Transactional(Transactional.TxType.REQUIRED) + @Override + public int size(final Query query) { + final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = builder.createQuery(Long.class); + final Root from = criteriaQuery.from(User.class); + + criteriaQuery = criteriaQuery.select(builder.count(from)); + + if (userNameFilter != null && !userNameFilter.trim().isEmpty()) { + criteriaQuery + .where(builder.like(builder.lower(from.get("name")), + String.format("%s%%", userNameFilter))); + } + + if (excludedUsers != null && !excludedUsers.isEmpty()) { + criteriaQuery.where(builder.not(from.in(excludedUsers))); + } + + return entityManager + .createQuery(criteriaQuery) + .getSingleResult() + .intValue(); + } + + @Transactional + @Override + public Stream fetch(final Query query) { + final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + final CriteriaQuery criteriaQuery = builder + .createQuery(User.class); + final Root from = criteriaQuery.from(User.class); + + if (userNameFilter != null && !userNameFilter.trim().isEmpty()) { + criteriaQuery + .where(builder.like(builder.lower(from.get("name")), + String.format("%s%%", userNameFilter))); + } + + if (excludedUsers != null && !excludedUsers.isEmpty()) { + criteriaQuery.where(builder.not(from.in(excludedUsers))); + } + + criteriaQuery.orderBy(builder.asc(from.get("name"))); + + return entityManager + .createQuery(criteriaQuery) + .setMaxResults(query.getLimit()) + .setFirstResult(query.getOffset()) + .getResultList() + .stream(); + } + + public void setUserNameFilter(final String userNameFilter) { + this.userNameFilter = userNameFilter; + refreshAll(); + } + + public void setExcludedUsers(final List excludedUsers) { + this.excludedUsers = excludedUsers; + refreshAll(); + } + +}