UsersPresenter.java
/*
** Module : UsersPresenter.java
** Abstract : UsersPresenter implements common business methods to manage user accounts.
**
** Copyright (c) 2017-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- ----------------Description----------------------
** 001 SBI 20170601 Created initial version.
** 002 EVL 20170926 Javadoc fixes.
** 003 GBB 20230825 Javadoc fixes.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero 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 Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.admin.client.application.home.accounts.users;
import java.io.Serializable;
import java.util.*;
import java.util.logging.Level;
import javax.inject.Named;
import com.goldencode.p2j.admin.client.*;
import com.goldencode.p2j.admin.client.application.Alarm;
import com.goldencode.p2j.admin.client.application.PrintingContext;
import com.goldencode.p2j.admin.client.application.home.HomePresenter;
import com.goldencode.p2j.admin.client.application.home.ViewStateMachine;
import com.goldencode.p2j.admin.client.application.home.accounts.AccountsPresenter;
import com.goldencode.p2j.admin.client.application.home.acl.*;
import com.goldencode.p2j.admin.client.widget.dialog.InputDialog;
import com.goldencode.p2j.admin.client.widget.dialog.MessageType;
import com.goldencode.p2j.admin.client.widget.dialog.ModalDialogs;
import com.goldencode.p2j.admin.shared.AdminServiceAsync;
import com.goldencode.p2j.admin.TaggedName;
import com.goldencode.p2j.admin.UserDef;
import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.web.bindery.event.shared.EventBus;
import com.gwtplatform.mvp.client.HasUiHandlers;
import com.gwtplatform.mvp.client.View;
import com.gwtplatform.mvp.client.annotations.NameToken;
import com.gwtplatform.mvp.client.annotations.ProxyStandard;
import com.gwtplatform.mvp.client.presenter.slots.NestedSlot;
import com.gwtplatform.mvp.client.proxy.PlaceManager;
import com.gwtplatform.mvp.client.proxy.ProxyPlace;
import com.gwtplatform.mvp.shared.proxy.PlaceRequest;
/**
* UsersPresenter implements common business methods to manage user accounts.
*/
public class UsersPresenter
extends AccountsPresenter<UsersPresenter.MyView, UsersPresenter.MyProxy>
implements UsersUIHandlers
{
/**
* Defines user accounts view states.
*/
public static enum UsersViewStates
implements ViewStateMachine.TransitionState
{
/** Users list has been refreshed. */
USERS_LIST_REFRESHED(MASK_WEST_CENTER, STATE_INITIAL_EMPTY),
/** The user account has been added currently. */
ADD_USER_ACCOUNT(MASK_WEST_CENTER, STATE_USER_ADD),
/** The user account has been edited currently. */
EDIT_USER_ACCOUNT(MASK_WEST_CENTER, STATE_USER_EDIT),
/** The single user has been selected currently. */
SINGLE_USER_SELECTED(MASK_WEST_CENTER, STATE_USERS_SINGLE),
/** The multiple users have been selected currently. */
MULTI_USERS_SELECTED(MASK_WEST_CENTER, STATE_USERS_MULTI),
/**
* The group accounts to which a selected user belongs have been cleared due to the user
* accounts selection has been cleared currently. */
USER_GROUP_CLEARED(MASK_CENTER, STATE_INITIAL_EMPTY),
/**
* The user account and the group to which the selected user belongs have been
* selected currently.
*/
USER_GROUP_SELECTED(MASK_CENTER, STATE_USERS_SINGLE_GROUP_SELECTED),
/** The all groups table has been filled recently */
ALL_GROUPS_POPULATED(MASK_EAST, STATE_ALL_GROUPS);
/** The current components states to be enabled or disabled */
private final boolean[] state;
/** The current mask that defines components to which the current state is applied */
private final boolean[] mask;
/**
* Creates a target view state.
*
* @param mask
* The current mask
* @param state
* The current state
*/
private UsersViewStates(boolean[] mask, boolean[] state)
{
this.mask = mask;
this.state = state;
}
/**
* Gets the current state that defines the affected components states.
*
* @return The current state
*/
@Override
public boolean[] getState()
{
return this.state;
}
/**
* Gets the current mask that defines the set of affected components (widgets).
*
* @return The current mask
*/
@Override
public boolean[] getMask()
{
return mask;
}
}
/** state definition - initial empty */
private static final boolean[] STATE_INITIAL_EMPTY =
{
/* refresh */ true,
/* addUserAccount */ true,
/* deleteUserAccount */ false,
/* cloneUserAccount */ false,
/* editUserAccount */ false,
/* disableUserAccount */ false,
/* findUser */ true,
/* switchTOACLs */ false,
/* newGroup, */ false,
/* assignNewGroup */ false,
/* deleteGroup */ false,
/* populateGroups */ true,
/* addSelected, */ false,
/* filterSelector */ false,
/* filterGroups */ false
};
/** state definition - group definition creation */
private static final boolean[] STATE_USER_ADD =
{
/* refresh */ false,
/* addUserAccount */ false,
/* deleteUserAccount */ false,
/* cloneUserAccount */ false,
/* editUserAccount */ false,
/* disableUserAccount */ false,
/* findUser */ false,
/* switchTOACLs */ false,
/* newGroup, */ false,
/* assignNewGroup */ false,
/* deleteGroup */ false,
/* populateGroups */ false,
/* addSelected, */ false,
/* filterSelector */ false,
/* filterGroups */ false
};
/** state definition - group definition editing */
private static final boolean[] STATE_USER_EDIT =
{
/* refresh */ false,
/* addUserAccount */ false,
/* deleteUserAccount */ false,
/* cloneUserAccount */ false,
/* editUserAccount */ false,
/* disableUserAccount */ false,
/* findUser */ false,
/* switchTOACLs */ false,
/* newGroup, */ false,
/* assignNewGroup */ false,
/* deleteGroup */ false,
/* populateGroups */ false,
/* addSelected, */ false,
/* filterSelector */ false,
/* filterGroups */ false
};
/** state definition - single selection in users list */
private static final boolean[] STATE_USERS_SINGLE =
{
/* refresh */ true,
/* addUserAccount */ true,
/* deleteUserAccount */ true,
/* cloneUserAccount */ true,
/* editUserAccount */ true,
/* disableUserAccount */ true,
/* findUser */ true,
/* switchTOACLs */ true,
/* newGroup, */ true,
/* assignNewGroup */ true,
/* deleteGroup */ false,
/* populateGroups */ true,
/* addSelected, */ false,
/* filterSelector */ false,
/* filterGroups */ false
};
/** state definition - single selection in groups list */
private static final boolean[] STATE_USERS_SINGLE_GROUP_SELECTED =
{
/* refresh */ true,
/* addUserAccount */ true,
/* deleteUserAccount */ true,
/* cloneUserAccount */ true,
/* editUserAccount */ true,
/* disableUserAccount */ true,
/* findUser */ true,
/* switchTOACLs */ true,
/* newGroup, */ true,
/* assignNewGroup */ true,
/* deleteGroup */ true,
/* populateGroups */ true,
/* addSelected, */ false,
/* filterSelector */ false,
/* filterGroups */ false
};
/** state definition - multiple selection in users list */
private static final boolean[] STATE_USERS_MULTI =
{
/* refresh */ true,
/* addUserAccount */ true,
/* deleteUserAccount */ true,
/* cloneUserAccount */ false,
/* editUserAccount */ false,
/* disableUserAccount */ false,
/* findUser */ true,
/* switchTOACLs */ false,
/* newGroup, */ false,
/* assignNewGroup */ false,
/* deleteGroup */ false,
/* populateGroups */ true,
/* addSelected, */ false,
/* filterSelector */ false,
/* filterGroups */ false
};
/** state definition - all groups list populated */
private static final boolean[] STATE_ALL_GROUPS =
{
/* refresh */ true,
/* addUserAccount */ true,
/* deleteUserAccount */ false,
/* cloneUserAccount */ false,
/* editUserAccount */ false,
/* disableUserAccount */ false,
/* findUser */ true,
/* switchTOACLs */ false,
/* newGroup, */ false,
/* assignNewGroup */ false,
/* deleteGroup */ false,
/* populateGroups */ true,
/* addSelected, */ false,
/* filterSelector */ true,
/* filterGroups */ true
};
/** mask definition - west-center */
private static final boolean[] MASK_WEST_CENTER =
{
/* refresh */ true,
/* addUserAccount */ true,
/* deleteUserAccount */ true,
/* cloneUserAccount */ true,
/* editUserAccount */ true,
/* disableUserAccount */ true,
/* findUser */ true,
/* switchTOACLs */ true,
/* newGroup, */ true,
/* assignNewGroup */ true,
/* deleteGroup */ true,
/* populateGroups */ false,
/* addSelected, */ false,
/* filterSelector */ false,
/* filterGroups */ false
};
/** mask definition - center */
private static final boolean[] MASK_CENTER =
{
/* refresh */ false,
/* addUserAccount */ false,
/* deleteUserAccount */ false,
/* cloneUserAccount */ false,
/* editUserAccount */ false,
/* disableUserAccount */ false,
/* findUser */ false,
/* switchTOACLs */ false,
/* newGroup, */ true,
/* assignNewGroup */ true,
/* deleteGroup */ true,
/* populateGroups */ false,
/* addSelected, */ false,
/* filterSelector */ false,
/* filterGroups */ false
};
/** mask definition - east */
private static final boolean[] MASK_EAST =
{
/* refresh */ false,
/* addUserAccount */ false,
/* deleteUserAccount */ false,
/* cloneUserAccount */ false,
/* editUserAccount */ false,
/* disableUserAccount */ false,
/* findUser */ false,
/* switchTOACLs */ false,
/* newGroup, */ false,
/* assignNewGroup */ false,
/* deleteGroup */ false,
/* populateGroups */ true,
/* addSelected, */ true,
/* filterSelector */ true,
/* filterGroups */ true
};
/** The attachment point for modal dialogs on this view*/
public static final NestedSlot MODAL_CONTENT = new NestedSlot();
/** Administration server interface */
private final AdminServiceAsync adminService;
/** The common modal dialogs manager */
private final ModalDialogs modalDialogsManager;
/** The server alarms manager */
private final Alarm serverAlarmsManager;
/** The currently selected user */
private UserDef selectedUser;
/** The set of selected users */
private final Set<UserDef> selectedUsers;
/** The user account definition provider */
private final Provider<UserAccountDefinition> uadProvider;
/** The common input dialogs provider */
private final Provider<InputDialog> inputDialogProvider;
/** The Find User Account manager */
private final FindUserAccount findUserAccountManager;
/**
* This view interface that must be implemented by the concrete view according to GWTP
* framework. Defines the exposed business methods.
*/
public interface MyView
extends View, HasUiHandlers<UsersUIHandlers>, Provider<HasEnabled[]>, PrintingContext
{
/**
* Sets the all users table's model with users accounts data given by tagged names
*
* @param users
* The array of users accounts given by tagged names
*/
void setUsers(TaggedName[] users);
/**
* Sets the user's groups table's model with all assigned groups for the single selected
* user from the all users table view.
*
* @param groups
* The array of assigned groups given by tagged names
*/
void setAssignedGroups(TaggedName[] groups);
/**
* Sets the all groups accounts table's model with all existing groups accounts.
*
* @param allGroups
* The array of all existing groups accounts
* @param filter
* The regular expression to select groups with accounts names according to this
* filter criteria
*/
void setAllGroups(TaggedName[] allGroups, RegExp filter);
/**
* Tests if this group has been selected from the user's assigned groups table.
*
* @param group
* The target group account given by its tagged name
*
* @return True iff the target group has been selected, otherwise false.
*/
boolean isSelectedFromUserGroups(TaggedName group);
/**
* Tests if these tested groups have been selected from the user's assigned groups table.
*
* @param groups
* The array of tested groups given by tagged names
*
* @return True iff the tested groups have been selected, otherwise false.
*/
boolean isSelectedFromUserGroups(TaggedName[] groups);
/**
* Tests if these tested groups have been selected from the all groups table.
*
* @param groups
* The array of tested groups given by tagged names
*
* @return True iff the tested groups have been selected, otherwise false.
*/
boolean isSelectedFromAllGroups(TaggedName[] groups);
/**
* Tests if these tested users have been selected from the all users table.
*
* @param users
* The array of tested user accounts given by tagged names
*
* @return True if all tested users have been selected, otherwise false.
*/
boolean isSelectedFromUsers(TaggedName[] users);
/**
* Tests if the tested user has been selected from the all users table.
*
* @param user
* The tested user account given by its tagged name
*
* @return True if the tested user has been selected, otherwise false.
*/
boolean isSelectedFromUsers(TaggedName user);
/**
* Selects the user's data row from the all users table by a given user's tagged name.
*
* @param user
* The user account given by its tagged name
*/
void selectUser(TaggedName user);
/**
* Selects the user's data row from the all users table by a given user's account name.
*
* @param name
* The account name.
*/
void selectUserByName(String name);
/**
* Changes the Populate button's label from "Populate" to "Refresh"
*
* @param populated
* The flag which true value means to change the Populate label to Refresh one
*/
void togglePopulateGroupsButton(boolean populated);
/**
* Toggles the Disable/Enable User button's label.
*
* @param enabled
* Indicates the user's enabled state. The true value switches this button's label
* from "Enable User" to "Disable User" and vice versa the false value switches
* from "Disable User" to "Enable User".
*/
void toggleDisableUserButton(boolean enabled);
/**
* Gets a reference to the Deleting Users Alert.
*
* @return The Deleting Users Alert
*/
DeletingUsersAlert getDeletingUsersAlert();
/**
* Gets a reference to the Clone User Account View.
*
* @return The Clone User Account View
*/
CloneUserAccountView getCloneUserAccountView();
/**
* Gets a reference to the Removing Groups Alert.
*
* @return The Removing Groups Alert
*/
RemovingGroupsAlert getRemovingGroupsAlert();
/**
* Returns the parent container where the Add/Edit User Definition View will be revealed in.
*
* @return The parent container for the Add/Edit User Definition View.
*/
HasWidgets getUserDefModalParent();
}
/**
* Defines the proxy place for GWTP framework. Binds /accounts/users url to this presenter.
*/
@ProxyStandard
@NameToken(NameTokens.USERS)
public interface MyProxy
extends ProxyPlace<UsersPresenter>
{}
/**
* Defines the Users presenter.
*
* @param eventBus
* The event bus
* @param view
* The associated view
* @param proxy
* The proxy place
* @param placeManager
* The place manager
* @param viewStateMachine
* The view state machine
* @param adminService
* The administration service
* @param modalDialogsManager
* The common modal dialogs manager
* @param serverAlarmsManager
* The server alarms
* @param uadProvider
* The user account definition provider
* @param inputDialogProvider
* InputDialog provider
* @param acctExtensionHolder
* The account extension holder
* @param aclPopupPresenterProvider
* The ACL popup presenter provider
*/
@Inject
public UsersPresenter(EventBus eventBus,
MyView view,
MyProxy proxy,
PlaceManager placeManager,
@Named("UsersViewStateMachine") ViewStateMachine viewStateMachine,
AdminServiceAsync adminService,
ModalDialogs modalDialogsManager,
Alarm serverAlarmsManager,
Provider<UserAccountDefinition> uadProvider,
Provider<InputDialog> inputDialogProvider,
AccountExtensionHolder acctExtensionHolder,
ACLPopupPresenter aclPopupPresenterProvider)
{
super(eventBus,
view,
proxy,
HomePresenter.SLOT_CONTENT,
placeManager,
viewStateMachine,
aclPopupPresenterProvider);
this.adminService = adminService;
this.modalDialogsManager = modalDialogsManager;
this.serverAlarmsManager = serverAlarmsManager;
this.uadProvider = uadProvider;
this.inputDialogProvider = inputDialogProvider;
this.findUserAccountManager = new FindUserAccount(acctExtensionHolder);
this.selectedUsers = new HashSet<UserDef>();
getView().setUiHandlers(this);
}
/**
* Lifecycle method called on all visible presenters whenever a
* presenter is revealed anywhere in the presenter hierarchy.
* <p>
* <b>Important:</b> Make sure you call your superclass {@link #onReset()} if
* you override. Also, do not call directly, fire a
* {@link com.gwtplatform.mvp.client.proxy.ResetPresentersEvent} to perform a reset manually.
* See {@link com.gwtplatform.mvp.client.PresenterWidget} for more details on lifecycle
* methods.
* <p>
* This is one of the most frequently used lifecycle method. This is usually a good
* place to refresh any information displayed by your presenter.
* <p>
* Note that {@link #onReset()} is not called only when using
* {@link #addToSlot(Object, PresenterWidget)}, {@link #addToPopupSlot(PresenterWidget)}
* or {@link #setInSlot(Object, PresenterWidget, boolean)} with {@code false} as the third
* parameter.
* <p>
* In a presenter hierarchy, this method is called top-down: first on the
* parent presenters, then on the children.
*/
@Override
protected void onReset()
{
super.onReset();
updateUsersList();
setState(UsersViewStates.USERS_LIST_REFRESHED);
}
/**
* Triggers an action to refresh the all users table.
*/
@Override
public void onRefresh()
{
updateUsersList();
changeState(UsersViewStates.USERS_LIST_REFRESHED);
}
/**
* Retrieves the user list and fills the all users table model.
*/
private void updateUsersList()
{
updateUsersList(()->{});
}
/**
* Retrieves the user list and fills the all users table model and executes a given command on
* getting the user list.
*
* @param callback
* The given command to execute on getting the data
*/
private void updateUsersList(Runnable callback)
{
this.adminService.listUsers(new AsyncCallback<TaggedName[]>()
{
@Override
public void onSuccess(TaggedName[] result)
{
getView().setUsers(result);
callback.run();
}
@Override
public void onFailure(Throwable caught)
{
//TODO notify an admin user
logger.log(Level.INFO, "Can't get all USERS");
callback.run();
}
});
}
/**
* Retrieves all assigned groups for a given user account and fills the user's group table
* model.
*
* @param user
* The user account given by its tagged name
*/
private void updateAssignedGroups(TaggedName user)
{
final String name = user.getName();
this.adminService.listUserGroups(name, new AsyncCallback<TaggedName[]>()
{
@Override
public void onSuccess(TaggedName[] result)
{
getView().setAssignedGroups(result);
}
@Override
public void onFailure(Throwable caught)
{
//TODO notify an admin user
logger.log(Level.INFO, "Can't get USERS for GROUP " + name);
}
});
}
/**
* Fills and/or updates the all groups accounts table.
*/
@Override
public void populateAndRefreshAllGroups()
{
this.adminService.listGroups(new AsyncCallback<TaggedName[]>()
{
@Override
public void onSuccess(TaggedName[] result)
{
getView().setAllGroups(result, filterExp);
getView().togglePopulateGroupsButton(true);
if (result != null && result.length > 0)
{
changeState(UsersViewStates.ALL_GROUPS_POPULATED);
}
}
@Override
public void onFailure(Throwable caught)
{
//TODO notify an admin user
logger.log(Level.INFO, "Can't get all Groups");
}
});
}
/**
* Shows the Add User Account Dialog.
*/
@Override
public void showAddUserAccountDialog()
{
logger.log(Level.INFO, "showAddUserAccountDialog");
UserAccountDefinition uad = uadProvider.get();
uad.build(null, r ->
{
if (!r)
{
return;
}
uad.show(getView().getUserDefModalParent(), new UserDef(), udata ->
{
if (udata == null)
{
return;
}
addUser(udata.userDef, udata.extDef);
updateUsersList();
});
});
}
/**
* Setups the Deleting Users Alert.
*
* @param users
* The array of users accounts given by tagged names
*/
@Override
public void setupDeletingUsersAlert(TaggedName[] users)
{
logger.log(Level.INFO, "setupDeletingUsersAlert");
getView().getDeletingUsersAlert().setAlert(users);
}
/**
* Setups the Clone User Account Dialog.
*
* @param clonedUserAccount
* The cloned user account given by its tagged name
*/
@Override
public void setupCloneUserAccountDialog(TaggedName clonedUserAccount)
{
logger.log(Level.INFO, "setupCloneUserAccountDialog");
getView().getCloneUserAccountView().setupCloneUserAccountView(clonedUserAccount);
}
/**
* Shows the Edit User Account Dialog to edit the target user account.
*
* @param updatedUserAccount
* The target user account given by its tagged name
*/
@Override
public void showEditUserAccountDialog(TaggedName updatedUserAccount)
{
logger.log(Level.INFO, "showEditUserAccountDialog");
UserAccountDefinition uad = uadProvider.get();
uad.build(selectedUser, r ->
{
if (!r)
{
return;
}
uad.show(getView().getUserDefModalParent(), selectedUser, udata ->
{
if (udata == null)
{
return;
}
updateUser(udata.userDef, udata.extDef);
updateUsersList();
});
});
}
/**
* Cancels the Add User Account Dialog and rolls back any related changes.
*/
@Override
public void cancelAddUserAccountDialog()
{
logger.log(Level.INFO, "cancelAddUserAccountDialog");
restoreState();
}
/**
* Cancels the Deleting Users Alert and rolls back any related changes.
*/
@Override
public void cancelDeletingUsersAlert()
{
logger.log(Level.INFO, "cancelDeletingUsersAlert");
}
/**
* Cancels the Clone User Account Dialog and rolls back any related changes.
*/
@Override
public void cancelCloneUserAccountDialog()
{
logger.log(Level.INFO, "cancelCloneUserAccountDialog");
}
/**
* Cancels the Edit User Account Dialog and rolls back any related changes.
*/
@Override
public void cancelEditUserAccountDialog()
{
logger.log(Level.INFO, "cancelEditUserAccountDialog");
restoreState();
}
/**
* Deletes the given selected users accounts.
*
* @param users
* The array of users accounts given by tagged names
*/
@Override
public void deleteSelectedUsers(TaggedName[] users)
{
if (!getView().isSelectedFromUsers(users))
{
return;
}
MultiCallback mc = new MultiCallback(adminService, serverAlarmsManager);
LinkedHashMap<TaggedName, AdminCallback<Boolean>> callbacks = new LinkedHashMap<TaggedName, AdminCallback<Boolean>>();
for(TaggedName user : users)
{
AdminCallback<Boolean> callback = mc.newCallback();
callbacks.put(user, callback);
logger.info("user account to delete " + user.getName());
};
// the admin service must be called only after all callbacks have been created otherwise
// the onDone method is called unpredictably multiple times
for (Map.Entry<TaggedName, AdminCallback<Boolean>> e : callbacks.entrySet())
{
this.adminService.deleteUser(e.getKey().getName(), e.getValue());
}
mc.onDone(() ->
{
if (!mc.isSuccess())
{
// this branch is executed when one or more callbacks !isSuccess()
for (Map.Entry<TaggedName, AdminCallback<Boolean>> e : callbacks.entrySet())
{
if (e.getValue().getResult() == null || !e.getValue().getResult())
{
logger.info("failed to delete user account " + e.getKey().getName());
}
}
}
updateUsersList(()->{changeState(UsersViewStates.USERS_LIST_REFRESHED);});
});
}
/**
* Setups the Removing Groups Alert for deleting a given user account from selected
* groups accounts.
*
* @param user
* The given user account
* @param groups
* The selected groups accounts from which the given user is about to be deleted
*/
@Override
public void setupRemovingGroupsAlert(TaggedName user, TaggedName[] groups)
{
getView().getRemovingGroupsAlert().setAlert(user, groups);
}
/**
* Clones the target user account with its ACL if it is required preserving the same password
* for a new created account.
*
* @param nameFrom
* The cloned user account name
* @param nameTo
* The new user account name
* @param acls
* True indicates that the ACL of the cloned user will be copied too, otherwise
* the ACL of the new created user account will be empty.
*/
@Override
public void cloneUserAccount(final String nameFrom, String nameTo, boolean acls)
{
// TODO security issue: remove cloneUserAccount from UsersUIHandlers
this.adminService.cloneUser(nameFrom, nameTo, acls, new AsyncCallback<Boolean>()
{
@Override
public void onSuccess(Boolean result)
{
logger.log(Level.INFO, "cloneUser " + nameFrom + ", " + result);
updateUsersList(()->{changeState(UsersViewStates.USERS_LIST_REFRESHED);});
}
@Override
public void onFailure(Throwable caught)
{
updateUsersList(()->{changeState(UsersViewStates.USERS_LIST_REFRESHED);});
}
});
}
/**
* Clones the target user account with its ACL if it is required and having new password.
*
* @param nameFrom
* The cloned user account name
* @param nameTo
* The new user account name
* @param acls
* True indicates that the ACL of the cloned user will be copied too, otherwise
* the ACL of the new created user account will be empty.
* @param newPassword
* The password for the new created account
*/
@Override
public void cloneUserAccount(final String nameFrom, String nameTo, boolean acls, String newPassword)
{
// TODO security issue: remove cloneUserAccount from UsersUIHandlers
this.adminService.cloneUser(nameFrom, nameTo, acls, newPassword, new AsyncCallback<Boolean>()
{
@Override
public void onSuccess(Boolean result)
{
logger.log(Level.INFO, "cloneUser " + nameFrom + ", " + result);
updateUsersList(()->{changeState(UsersViewStates.USERS_LIST_REFRESHED);});
}
@Override
public void onFailure(Throwable caught)
{
updateUsersList(()->{changeState(UsersViewStates.USERS_LIST_REFRESHED);});
}
});
}
/**
* Triggers the users selection changed event.
*
* @param users
* The selected users accounts
*/
@Override
public void onUserSelected(Set<TaggedName> users)
{
if (users == null)
{
logger.info("Users selection is cleared.");
changeState(UsersViewStates.USERS_LIST_REFRESHED);
return;
}
MultiCallback mc = new MultiCallback(adminService, serverAlarmsManager);
LinkedHashMap<TaggedName, AdminCallback<UserDef>> callbacks = new LinkedHashMap<TaggedName, AdminCallback<UserDef>>();
users.forEach(user ->
{
AdminCallback<UserDef> cb = mc.newCallback();
callbacks.put(user, cb);
logger.info("get user " + user.getName());
});
for (Map.Entry<TaggedName, AdminCallback<UserDef>> e : callbacks.entrySet())
{
this.adminService.getUser(e.getKey().getName(), e.getValue());
}
mc.onDone(() ->
{
if (mc.isSuccess())
{
selectedUsers.clear();
for (Map.Entry<TaggedName, AdminCallback<UserDef>> e : callbacks.entrySet())
{
UserDef userDef = e.getValue().getResult();
logger.info("selected user " + userDef);
selectedUsers.add(userDef);
selectedUser = userDef;
}
if (selectedUsers.size() > 1)
{
changeState(UsersViewStates.MULTI_USERS_SELECTED);
}
else if (selectedUsers.size() == 1)
{
changeState(UsersViewStates.SINGLE_USER_SELECTED);
getView().toggleDisableUserButton(selectedUser.enabled);
}
else
{
changeState(UsersViewStates.USERS_LIST_REFRESHED);
}
}
else
{
for (Map.Entry<TaggedName, AdminCallback<UserDef>> e : callbacks.entrySet())
{
if (e.getValue().getResult() == null)
{
logger.info("failed to get user definition for " + e.getKey().getName());
}
}
changeState(UsersViewStates.USERS_LIST_REFRESHED);
}
});
if (callbacks.size() == 1)
{
TaggedName selectedUser = callbacks.keySet().toArray(new TaggedName [1])[0];
updateAssignedGroups(selectedUser);
}
else
{
getView().setAssignedGroups(null);
}
}
/**
* Triggers the groups selection changed event.
*
* @param selectedGroups
* The selected groups accounts
*/
@Override
public void onGroupSelected(Set<TaggedName> selectedGroups)
{
logger.info("onGroupSelected");
if (selectedGroups == null || selectedGroups.isEmpty())
{
changeState(UsersViewStates.USER_GROUP_CLEARED);
}
else
{
changeState(UsersViewStates.USER_GROUP_SELECTED);
}
}
/**
* Cancels the Removing Groups Alert and rolls back any related changes.
*/
@Override
public void cancelRemovingGroupsAlert()
{
}
/**
* Makes a given user account to be a member of a given group account.
*
* @param user
* The target user account given by its tagged name
* @param groupName
* The target group account name
*/
@Override
public void addUserInNewGroup(TaggedName user, String groupName)
{
if (!getView().isSelectedFromUsers(user))
{
//TODO
return;
}
this.adminService.checkGroup(groupName, new AsyncCallback<TaggedName>()
{
@Override
public void onFailure(Throwable caught)
{
// TODO Auto-generated method stub
}
@Override
public void onSuccess(TaggedName result)
{
adminService.changeGroupUsers(groupName, new String[] {user.getName()}, new String[0],
new AsyncCallback<Boolean>()
{
@Override
public void onSuccess(Boolean result)
{
updateUsersList(()-> {getView().selectUser(user);});
}
@Override
public void onFailure(Throwable caught)
{
updateUsersList(()-> {getView().selectUser(user);});
}
});
}
});
}
/**
* Displays only groups accounts that satisfy the given search criteria.
*
* @param value
* The given search criteria
*/
@Override
public void setGroupsFilter(String value)
{
setFilter(value);
populateAndRefreshAllGroups();
}
/**
* Adds a new user.
*
* @param newUser
* The new user definition
* @param ext
* The extended account data.
*/
@Override
public void addUser(UserDef newUser, Serializable ext)
{
this.adminService.addUser(newUser, ext, new AsyncCallback<Boolean>()
{
@Override
public void onSuccess(Boolean result)
{
logger.log(Level.INFO, "addUser " + newUser.subjectId + ", Is added?" + result);
updateUsersList(()->{restoreState();});
if (result == null || !result)
{
serverAlarmsManager.ring("Couldn't add user account " + newUser.subjectId);
}
}
@Override
public void onFailure(Throwable caught)
{
updateUsersList(()->{restoreState();});
}
});
}
/**
* Updates a given user account.
*
* @param user
* The given user definition
* @param ext
* The given extended account data
*/
@Override
public void updateUser(UserDef user, Serializable ext)
{
this.adminService.setUser(user, ext, new AsyncCallback<Boolean>()
{
@Override
public void onSuccess(Boolean result)
{
logger.log(Level.INFO, "updateUser " + user.subjectId + ", Is updated?" + result);
updateUsersList(()->{getView().selectUserByName(user.subjectId); restoreState();});
}
@Override
public void onFailure(Throwable caught)
{
updateUsersList(()->{getView().selectUserByName(user.subjectId); restoreState();});
}
});
}
/**
* Cancels the Find User Account Dialog and rolls back any related changes.
*/
@Override
public void cancelFindUserAccountDialog()
{
}
/**
* Setups the Find User Account Dialog.
*/
@Override
public void setupFindUserAccountDialog()
{
InputDialog dialog = inputDialogProvider.get();
IFindAccountScreen findAccount = new IFindAccountScreen()
{
@Override
public void findAccountByName(String name)
{
adminService.checkUser(
name,
new AsyncCallback<TaggedName>()
{
@Override
public void onFailure(Throwable caught)
{
serverAlarmsManager.ring();
modalDialogsManager.showInfo("Can't find user " + name + ".");
}
@Override
public void onSuccess(TaggedName result)
{
if (result != null)
{
getView().selectUser(result);
dialog.dismiss();
}
else
{
modalDialogsManager.showInfo("Can't find user " + name + ".");
}
}
});
}
};
findUserAccountManager.show(getView().getUserDefModalParent(), dialog, findAccount);
}
/**
* Disables the target user account.
*
* @param user
* The target user account given by its tagged name
*/
@Override
public void disableUserAccount(TaggedName user)
{
if (selectedUser == null || selectedUser.subjectId == null ||
!selectedUser.subjectId.equals(user.getName()))
{
return;
}
boolean enable = !selectedUser.enabled;
String title = enable ? "Enable User" : "Disable User";
String message = (enable ? "Enable user " : "Disable user ") + user.getName() + "?";
modalDialogsManager.showYesNo(title, message, MessageType.QUESTION, button -> {
if (button == 0)
{
selectedUser.enabled = enable;
adminService.setUser(selectedUser, new AsyncCallback<Boolean>()
{
@Override
public void onFailure(Throwable caught)
{
updateUsersList(() -> {getView().selectUser(user);});
logger.log(Level.WARNING, "setUser " + user.getName() + " got " + caught);
modalDialogsManager.showError("Can't " + (enable ? "enable" : "disable") +
user.getName() + " user account.");
}
@Override
public void onSuccess(Boolean result)
{
updateUsersList(() -> {getView().selectUser(user);});
if (!result)
{
modalDialogsManager.showError("Can't update to " +
(enable ? "enable" : "disable") + user.getName() + " user account.");
}
}
});
}
});
}
/**
* Removes a given user account from given groups accounts.
*
* @param user
* The target user account given by its tagged name
* @param groups
* The array of target groups accounts given by tagged names
*/
@Override
public void removeUserFromGroups(TaggedName user, TaggedName[] groups)
{
if (!getView().isSelectedFromUsers(user) || ! getView().isSelectedFromUserGroups(groups) ||
selectedUser == null || selectedUser.subjectId == null ||
!selectedUser.subjectId.equals(user.getName()))
{
return;
}
LinkedHashSet<String> assignedGroups = new LinkedHashSet<String>(Arrays.asList(selectedUser.groups));
String[] unassignedGroups = new String[groups.length];
int i = 0;
for(TaggedName group : groups)
{
assignedGroups.remove(group.getName());
unassignedGroups[i++] = group.getName();
}
selectedUser.groups = assignedGroups.toArray(new String[assignedGroups.size()]);
adminService.setUser(selectedUser, new AsyncCallback<Boolean>()
{
@Override
public void onFailure(Throwable caught)
{
updateUsersList(() -> {getView().selectUser(user);});
logger.log(Level.WARNING, "setUser " + user.getName() + " got " + caught);
modalDialogsManager.showError("Can't remove " + user.getName() + " from " +
Arrays.toString(unassignedGroups));
}
@Override
public void onSuccess(Boolean result)
{
updateUsersList(() -> {getView().selectUser(user);});
if (!result)
{
modalDialogsManager.showError("Can't remove " + user.getName() + " from " +
Arrays.toString(unassignedGroups));
}
}
});
}
/**
* Makes a given user account to be a member of given groups accounts.
*
* @param user
* The target user account given by its tagged name
* @param groups
* The array of target groups accounts given by tagged names
*/
@Override
public void addUserToGroups(TaggedName user, TaggedName[] groups)
{
if (!getView().isSelectedFromUsers(user) || ! getView().isSelectedFromAllGroups(groups) ||
selectedUser == null || selectedUser.subjectId == null ||
!selectedUser.subjectId.equals(user.getName()))
{
return;
}
LinkedHashSet<String> assignedGroups = new LinkedHashSet<String>(Arrays.asList(selectedUser.groups));
String[] additionalGroups = new String[groups.length];
int i = 0;
for(TaggedName group : groups)
{
assignedGroups.add(group.getName());
additionalGroups[i++] = group.getName();
}
selectedUser.groups = assignedGroups.toArray(new String[assignedGroups.size()]);
adminService.setUser(selectedUser, new AsyncCallback<Boolean>()
{
@Override
public void onFailure(Throwable caught)
{
updateUsersList(() -> {getView().selectUser(user);});
logger.log(Level.WARNING, "setUser " + user.getName() + " got " + caught);
modalDialogsManager.showError("Can't add " + user.getName() + " to " +
Arrays.toString(additionalGroups));
}
@Override
public void onSuccess(Boolean result)
{
updateUsersList(() -> {getView().selectUser(user);});
if (!result)
{
modalDialogsManager.showError("Can't add " + user.getName() + " to " +
Arrays.toString(additionalGroups));
}
}
});
}
}