package org.sigmah.client.ui.presenter.admin.users;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.sigmah.client.dispatch.CommandResultHandler;
import org.sigmah.client.event.UpdateEvent;
import org.sigmah.client.event.handler.UpdateHandler;
import org.sigmah.client.i18n.I18N;
import org.sigmah.client.inject.Injector;
import org.sigmah.client.page.Page;
import org.sigmah.client.page.PageRequest;
import org.sigmah.client.page.RequestParameter;
import org.sigmah.client.ui.notif.ConfirmCallback;
import org.sigmah.client.ui.notif.N10N;
import org.sigmah.client.ui.presenter.admin.AbstractAdminPresenter;
import org.sigmah.client.ui.view.admin.users.UsersAdminView;
import org.sigmah.client.ui.widget.Loadable;
import org.sigmah.client.ui.widget.button.Button;
import org.sigmah.client.util.ClientUtils;
import org.sigmah.shared.command.DeactivateUsers;
import org.sigmah.shared.command.DeletePrivacyGroups;
import org.sigmah.shared.command.DeleteProfiles;
import org.sigmah.shared.command.GetContacts;
import org.sigmah.shared.command.GetPrivacyGroups;
import org.sigmah.shared.command.GetProfilesWithDetails;
import org.sigmah.shared.command.GetUsersWithProfiles;
import org.sigmah.shared.command.result.DeleteResult;
import org.sigmah.shared.command.result.DeleteResult.DeleteErrorCause;
import org.sigmah.shared.command.result.ListResult;
import org.sigmah.shared.command.result.VoidResult;
import org.sigmah.shared.dto.ContactDTO;
import org.sigmah.shared.dto.UserDTO;
import org.sigmah.shared.dto.base.EntityDTO;
import org.sigmah.shared.dto.profile.PrivacyGroupDTO;
import org.sigmah.shared.dto.profile.ProfileDTO;
import org.sigmah.shared.dto.referential.ContactModelType;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
* Admin Users Presenter which manages {@link UsersAdminView}.
*
* @author Maxime Lombard (mlombard@ideia.fr) (v1.3)
* @author Mehdi Benabdeslam (mehdi.benabdeslam@netapsys.fr) (v2.0)
* @author Denis Colliot (dcolliot@ideia.fr) (v2.0)
*/
@Singleton
public class UsersAdminPresenter extends AbstractAdminPresenter<UsersAdminPresenter.View> {
/**
* Description of the view managed by this presenter.
*/
@ImplementedBy(UsersAdminView.class)
public static interface View extends AbstractAdminPresenter.View {
/**
* Text values separator.
*/
static final String TEXT_VALUES_SEPARATOR = ", ";
// Panels types.
static final int USERS = 1;
static final int PROFILES = 2;
static final int PRIVACY_GROUPS = 3;
// --
// Users Panel.
// --
List<UserDTO> getUsersSelection();
ListStore<UserDTO> getUsersStore();
Button getUsersAddButton();
Button getUsersAddByEmailButton();
Button getUsersActiveButton();
Button getUsersRefreshButton();
Loadable[] getUsersLoadable();
void buildAddUserByEmailWindow(List<ContactDTO> availableContacts, AddUserByEmailHandler handler);
/**
* Clear the store filters as well as the search field.
*/
void clearFilters();
// --
// Privacy Groups Panel.
// --
Button getPrivacyGroupsAddButton();
Button getPrivacyGroupsDeleteButton();
ListStore<PrivacyGroupDTO> getPrivacyGroupsStore();
List<PrivacyGroupDTO> getPrivacyGroupsSelection();
Loadable[] getPrivacyGroupsLoadable();
// --
// Profiles Panel.
// --
Button getProfilesAddButton();
Button getProfilesDeleteButton();
Button getProfilesRefreshButton();
List<ProfileDTO> getProfilesSelection();
ListStore<ProfileDTO> getProfilesStore();
Loadable[] getProfilesLoadable();
// --
// Other utility methods.
// --
void setGridEditHandler(GridEditHandler handler);
}
public interface AddUserByEmailHandler {
void handleSubmit(ContactDTO contactDTO);
}
/**
* Grid edit button handler.
*/
public static interface GridEditHandler {
/**
* Callback executed on grid edit button event.
*
* @param entityDTO
* The source button corresponding row entity (user, profile or privacy group).
*/
void onEditAction(final EntityDTO<?> entityDTO);
}
/**
* Loading error message display flag.
*/
private static boolean alert;
/**
* Presenters's initialization.
*
* @param view
* Presenter's view interface.
* @param injector
* Injected client injector.
*/
@Inject
protected UsersAdminPresenter(View view, Injector injector) {
super(view, injector);
}
/**
* {@inheritDoc}
*/
@Override
public Page getPage() {
return Page.ADMIN_USERS;
}
/**
* {@inheritDoc}
*/
@Override
public void onBind() {
// --
// ALL GRIDS : edit button.
// --
view.setGridEditHandler(new GridEditHandler() {
@Override
public void onEditAction(final EntityDTO<?> entityDTO) {
if (entityDTO instanceof UserDTO) {
eventBus.navigateRequest(Page.ADMIN_USER_EDIT.request().addData(RequestParameter.DTO, entityDTO));
} else if (entityDTO instanceof ProfileDTO) {
eventBus.navigateRequest(Page.ADMIN_PROFILE_EDIT.request().addData(RequestParameter.DTO, entityDTO));
} else if (entityDTO instanceof PrivacyGroupDTO) {
eventBus.navigateRequest(Page.ADMIN_PRIVACY_GROUP_EDIT.request().addData(RequestParameter.DTO, entityDTO));
}
}
});
// --
// USERS : add button handler.
// --
view.getUsersAddButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(final ButtonEvent be) {
eventBus.navigate(Page.ADMIN_USER_EDIT);
}
});
view.getUsersAddByEmailButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
dispatch.execute(new GetContacts(ContactModelType.INDIVIDUAL, true, true), new CommandResultHandler<ListResult<ContactDTO>>() {
@Override
protected void onCommandSuccess(ListResult<ContactDTO> result) {
view.buildAddUserByEmailWindow(result.getList(), new AddUserByEmailHandler() {
@Override
public void handleSubmit(ContactDTO contactDTO) {
eventBus.navigateRequest(Page.ADMIN_USER_EDIT.requestWith(RequestParameter.CONTACT_ID, contactDTO.getId()));
}
});
}
});
}
});
// --
// USERS : active button handler.
// --
view.getUsersActiveButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(final ButtonEvent be) {
confirmDeleteSelected(new ConfirmCallback() {
@Override
public void onAction() {
onUserActivationUpdate(view.getUsersSelection());
}
}, View.USERS);
}
});
// --
// USERS : refresh button handler.
// --
view.getUsersRefreshButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(final ButtonEvent be) {
refreshUsersPanel();
}
});
// --
// PROFILES : add button handler.
// --
view.getProfilesAddButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(final ButtonEvent be) {
eventBus.navigate(Page.ADMIN_PROFILE_EDIT);
}
});
// --
// PROFILES : refresh button handler.
// --
view.getProfilesRefreshButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(final ButtonEvent be) {
refreshProfilesPanel();
}
});
// --
// PROFILES : delete button handler.
// --
view.getProfilesDeleteButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(final ButtonEvent be) {
confirmDeleteSelected(new ConfirmCallback() {
@Override
public void onAction() {
onProfileDelete(view.getProfilesSelection());
}
}, View.PROFILES);
}
});
// --
// PRIVACY GROUPS : add button handler.
// --
view.getPrivacyGroupsAddButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(final ButtonEvent be) {
eventBus.navigate(Page.ADMIN_PRIVACY_GROUP_EDIT);
}
});
// --
// PRIVACY GROUPS : delete button handler.
// --
view.getPrivacyGroupsDeleteButton().addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(final ButtonEvent be) {
confirmDeleteSelected(new ConfirmCallback() {
@Override
public void onAction() {
onPrivacyGroupDelete(view.getPrivacyGroupsSelection());
}
}, View.PRIVACY_GROUPS);
}
});
// --
// ALL GRIDS : Update events handler.
// --
registerHandler(eventBus.addHandler(UpdateEvent.getType(), new UpdateHandler() {
@Override
public void onUpdate(final UpdateEvent event) {
if (event.concern(UpdateEvent.PRIVACY_GROUP_UPDATE)) {
refreshPrivacyGroupsPanel();
} else if (event.concern(UpdateEvent.PROFILE_UPDATE)) {
refreshProfilesPanel();
} else if (event.concern(UpdateEvent.USER_UPDATE)) {
refreshUsersPanel();
}
}
}));
}
/**
* {@inheritDoc}
*/
@Override
public void onPageRequest(PageRequest request) {
alert = false;
// Getting Users
refreshUsersPanel();
// Getting profiles
refreshProfilesPanel();
// Getting privacy groups
refreshPrivacyGroupsPanel();
}
// ----------------------------------------------------------------------------------------------------
//
// UTILITY METHODS.
//
// ----------------------------------------------------------------------------------------------------
/**
* Loads the users and populates the corresponding grid store.
*/
public void refreshUsersPanel() {
view.getUsersStore().removeAll();
view.clearFilters();
dispatch.execute(new GetUsersWithProfiles(), new CommandResultHandler<ListResult<UserDTO>>() {
@Override
public void onCommandFailure(final Throwable caught) {
showLoadingErrorMessage();
}
@Override
public void onCommandSuccess(final ListResult<UserDTO> result) {
view.getUsersStore().add(result.getList());
view.getUsersStore().commitChanges();
}
}, view.getUsersLoadable());
}
/**
* Loads the profiles and populates the corresponding grid store.
*/
public void refreshProfilesPanel() {
view.getProfilesStore().removeAll();
dispatch.execute(new GetProfilesWithDetails(null), new CommandResultHandler<ListResult<ProfileDTO>>() {
@Override
public void onCommandFailure(final Throwable caught) {
showLoadingErrorMessage();
}
@Override
public void onCommandSuccess(final ListResult<ProfileDTO> result) {
view.getProfilesStore().add(result.getList());
view.getProfilesStore().commitChanges();
}
}, view.getProfilesLoadable());
}
/**
* Loads the privacy groups and populates the corresponding grid store.
*/
public void refreshPrivacyGroupsPanel() {
view.getPrivacyGroupsStore().removeAll();
dispatch.execute(new GetPrivacyGroups(), new CommandResultHandler<ListResult<PrivacyGroupDTO>>() {
@Override
public void onCommandFailure(final Throwable caught) {
showLoadingErrorMessage();
}
@Override
public void onCommandSuccess(final ListResult<PrivacyGroupDTO> result) {
view.getPrivacyGroupsStore().add(result.getList());
view.getPrivacyGroupsStore().commitChanges();
}
}, view.getPrivacyGroupsLoadable());
}
/**
* Shows failed loading error message.<br>
* Uses the {@link #alert} flag to show this message only once, even if multiple loading actions fail.
*/
private static void showLoadingErrorMessage() {
if (alert) {
return;
}
alert = true;
N10N.error(I18N.CONSTANTS.adminUsers(), I18N.CONSTANTS.adminProblemLoading());
}
/**
* Deletes the selected Privacy Group(s).
*
* @param selection
* The selected privacy group(s).
*/
private void onPrivacyGroupDelete(final List<PrivacyGroupDTO> selection) {
dispatch.execute(new DeletePrivacyGroups(selection), new CommandResultHandler<DeleteResult<PrivacyGroupDTO>>() {
/**
* On command error.
*/
@Override
public void onCommandFailure(final Throwable caught) {
final Map<String, List<String>> errorMessage = new HashMap<String, List<String>>();
final List<String> items = new ArrayList<String>();
for (final PrivacyGroupDTO privacyGroup : selection) {
items.add(privacyGroup.getTitle());
}
errorMessage.put(I18N.CONSTANTS.admin_deleteItems_error_header(), items);
errorMessage.put(I18N.CONSTANTS.admin_deleteItems_error_footer(), null);
N10N.error(errorMessage);
}
/**
* On command success (but some privacy group(s) may have not been deleted).
*/
@Override
public void onCommandSuccess(final DeleteResult<PrivacyGroupDTO> result) {
if (result.hasDeletedEntities()) {
// Some (maybe all) entities have been deleted.
final List<String> privacyGroupNames = new ArrayList<String>();
for (final PrivacyGroupDTO privacyGroup : result.getDeletedEntities()) {
privacyGroupNames.add(privacyGroup.getTitle());
view.getPrivacyGroupsStore().remove(privacyGroup);
}
N10N.infoNotif(I18N.CONSTANTS.infoConfirmation(), I18N.CONSTANTS.adminPrivacyGroupsDeleteSuccess(), privacyGroupNames);
view.getPrivacyGroupsStore().commitChanges();
}
if (result.hasErrors()) {
// Some error(s) have been detected.
final Map<PrivacyGroupDTO, List<DeleteErrorCause>> errors = result.getErrors();
final Map<String, List<String>> errorMessage = new HashMap<String, List<String>>();
for (final Entry<PrivacyGroupDTO, List<DeleteErrorCause>> error : errors.entrySet()) {
final PrivacyGroupDTO privacyGroup = error.getKey();
final List<String> errorMessageItems = new ArrayList<String>();
final StringBuilder builder = new StringBuilder();
for (final DeleteErrorCause arguments : error.getValue()) {
builder.setLength(0);
if (arguments.isFlexibleElementError()) {
builder.append(I18N.MESSAGES.admin_privacyGroups_delete_ko_field(arguments.isDefaultFlexibleElement() ? I18N.CONSTANTS.flexibleElementDefault() : arguments
.getCauseLabel()));
builder.append(" (").append(I18N.MESSAGES.admin_privacyGroups_delete_ko_model(arguments.getModelName())).append(')');
} else {
builder.append(I18N.MESSAGES.admin_privacyGroups_delete_ko_profile(arguments.getCauseLabel()));
}
errorMessageItems.add(builder.toString());
}
errorMessage.put(I18N.MESSAGES.admin_privacyGroups_delete_ko(privacyGroup.getTitle()), errorMessageItems);
}
N10N.warn(errorMessage);
}
}
}, view.getPrivacyGroupsLoadable());
}
/**
* Controls if the given selected profiles can be deleted and deletes them.
*
* @param selection
* The selected profile(s).
*/
public void onProfileDelete(final List<ProfileDTO> selection) {
dispatch.execute(new DeleteProfiles(selection), new CommandResultHandler<DeleteResult<ProfileDTO>>() {
/**
* On command failure.
*/
@Override
public void onCommandFailure(final Throwable caught) {
final Map<String, List<String>> errorMessage = new HashMap<String, List<String>>();
final List<String> items = new ArrayList<String>();
for (final ProfileDTO profile : selection) {
items.add(profile.getName());
}
errorMessage.put(I18N.CONSTANTS.admin_deleteItems_error_header(), items);
errorMessage.put(I18N.CONSTANTS.admin_deleteItems_error_footer(), null);
N10N.error(errorMessage);
}
/**
* On command success (but some profile(s) may have not been deleted).
*/
@Override
public void onCommandSuccess(final DeleteResult<ProfileDTO> result) {
if (result.hasDeletedEntities()) {
// Some (maybe all) entities have been deleted.
final List<String> profileNames = new ArrayList<String>();
for (final ProfileDTO profile : result.getDeletedEntities()) {
profileNames.add(profile.getName());
view.getProfilesStore().remove(profile);
}
N10N.infoNotif(I18N.CONSTANTS.infoConfirmation(), I18N.CONSTANTS.adminProfilesDeleteSuccess(), profileNames);
view.getProfilesStore().commitChanges();
}
if (result.hasErrors()) {
// Some error(s) have been detected.
final Map<ProfileDTO, List<DeleteErrorCause>> errors = result.getErrors();
final Map<String, List<String>> errorMessage = new HashMap<String, List<String>>();
for (final Entry<ProfileDTO, List<DeleteErrorCause>> error : errors.entrySet()) {
final ProfileDTO profile = error.getKey();
final List<String> errorMessageItems = new ArrayList<String>();
for (final DeleteErrorCause arguments : error.getValue()) {
errorMessageItems.add(arguments.getCauseLabel());
}
errorMessage.put(I18N.MESSAGES.admin_profiles_delete_ko(profile.getName()), errorMessageItems);
}
N10N.warn(errorMessage);
}
}
}, view.getProfilesLoadable());
}
/**
* Activates or deactivates the given selected users.
*
* @param selection
* The selected user(s).
*/
private void onUserActivationUpdate(final List<UserDTO> selection) {
dispatch.execute(new DeactivateUsers(selection), new CommandResultHandler<VoidResult>() {
@Override
public void onCommandFailure(final Throwable caught) {
final Map<String, List<String>> errorMessage = new HashMap<String, List<String>>();
final List<String> items = new ArrayList<String>();
for (final UserDTO user : selection) {
items.add(user.getName());
}
errorMessage.put(I18N.CONSTANTS.admin_deleteItems_error_header(), items);
errorMessage.put(I18N.CONSTANTS.admin_deleteItems_error_footer(), null);
N10N.error(errorMessage);
}
@Override
public void onCommandSuccess(final VoidResult result) {
for (final UserDTO user : selection) {
user.setActive(!user.getActive());
view.getUsersStore().update(user);
}
}
});
}
/**
* Displays the appropriate confirm message and executes the given {@code confirmCallback}.
*
* @param confirmCallback
* The confirmation callback action.
* @param type
* The context type (users, profiles or privacy groups).
*/
private void confirmDeleteSelected(final ConfirmCallback confirmCallback, final int type) {
switch (type) {
case View.USERS:
// Not a 'delete' action.
confirmCallback.onAction();
return;
case View.PROFILES:
if (ClientUtils.isEmpty(view.getProfilesSelection())) {
N10N.warn(I18N.CONSTANTS.delete(), I18N.CONSTANTS.admin_profiles_delete_noSelection());
return;
}
final List<String> profilesNames = new ArrayList<String>();
for (final ProfileDTO profile : view.getProfilesSelection()) {
profilesNames.add(profile.getName());
}
N10N.confirmation(I18N.CONSTANTS.delete(), I18N.CONSTANTS.admin_profiles_delete_confirmation(), profilesNames, confirmCallback);
break;
case View.PRIVACY_GROUPS:
if (ClientUtils.isEmpty(view.getPrivacyGroupsSelection())) {
N10N.warn(I18N.CONSTANTS.delete(), I18N.CONSTANTS.admin_privayGroups_delete_noSelection());
return;
}
final List<String> privacyGroupsNames = new ArrayList<String>();
for (final PrivacyGroupDTO privacyGroup : view.getPrivacyGroupsSelection()) {
privacyGroupsNames.add(privacyGroup.getTitle());
}
N10N.confirmation(I18N.CONSTANTS.delete(), I18N.CONSTANTS.admin_privacyGroups_delete_confirmation(), privacyGroupsNames, confirmCallback);
break;
default:
break;
}
}
}