package fr.openwide.core.basicapp.web.application.administration.form;
import static com.google.common.base.Predicates.equalTo;
import static fr.openwide.core.commons.util.functional.Predicates2.isTrue;
import java.util.Collections;
import org.apache.wicket.Component;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.Session;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.EmailTextField;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.RequiredTextField;
import org.apache.wicket.markup.html.link.AbstractLink;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.IValidationError;
import org.apache.wicket.validation.ValidationError;
import org.apache.wicket.validation.validator.EmailAddressValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.openwide.core.basicapp.core.business.user.model.User;
import fr.openwide.core.basicapp.core.business.user.model.atomic.UserPasswordRecoveryRequestInitiator;
import fr.openwide.core.basicapp.core.business.user.model.atomic.UserPasswordRecoveryRequestType;
import fr.openwide.core.basicapp.core.business.user.service.IUserService;
import fr.openwide.core.basicapp.core.security.service.ISecurityManagementService;
import fr.openwide.core.basicapp.core.util.binding.Bindings;
import fr.openwide.core.basicapp.web.application.BasicApplicationSession;
import fr.openwide.core.basicapp.web.application.administration.template.AdministrationUserDescriptionTemplate;
import fr.openwide.core.basicapp.web.application.common.typedescriptor.user.UserTypeDescriptor;
import fr.openwide.core.basicapp.web.application.common.validator.EmailUnicityValidator;
import fr.openwide.core.basicapp.web.application.common.validator.UserPasswordValidator;
import fr.openwide.core.basicapp.web.application.common.validator.UsernamePatternValidator;
import fr.openwide.core.basicapp.web.application.common.validator.UsernameUnicityValidator;
import fr.openwide.core.spring.util.StringUtils;
import fr.openwide.core.wicket.markup.html.basic.CoreLabel;
import fr.openwide.core.wicket.more.condition.Condition;
import fr.openwide.core.wicket.more.markup.html.basic.EnclosureContainer;
import fr.openwide.core.wicket.more.markup.html.feedback.FeedbackUtils;
import fr.openwide.core.wicket.more.markup.html.form.FormPanelMode;
import fr.openwide.core.wicket.more.markup.html.form.LocaleDropDownChoice;
import fr.openwide.core.wicket.more.markup.html.select2.util.DropDownChoiceWidth;
import fr.openwide.core.wicket.more.markup.html.template.js.jquery.plugins.bootstrap.modal.component.AbstractAjaxModalPopupPanel;
import fr.openwide.core.wicket.more.markup.html.template.js.jquery.plugins.bootstrap.modal.component.DelegatedMarkupPanel;
import fr.openwide.core.wicket.more.model.BindingModel;
import fr.openwide.core.wicket.more.model.GenericEntityModel;
public abstract class AbstractUserPopup<U extends User> extends AbstractAjaxModalPopupPanel<U> {
private static final long serialVersionUID = -3575009149241618972L;
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractUserPopup.class);
private static final UsernamePatternValidator USERNAME_PATTERN_VALIDATOR =
new UsernamePatternValidator() {
private static final long serialVersionUID = 1L;
@Override
protected IValidationError decorate(IValidationError error, IValidatable<String> validatable) {
((ValidationError) error).setKeys(Collections.singletonList("common.validator.username.pattern"));
return error;
}
};
@SpringBean
private IUserService userService;
@SpringBean
private ISecurityManagementService securityManagementService;
private final FormPanelMode mode;
private final UserTypeDescriptor<U> typeDescriptor;
protected Form<?> userForm;
protected PasswordTextField passwordField;
protected PasswordTextField confirmPasswordField;
private final IModel<String> passwordModel = Model.of();
private final IModel<String> confirmPasswordModel = Model.of();
public AbstractUserPopup(String id, IModel<U> userModel, UserTypeDescriptor<U> typeDescriptor) {
this(id, userModel, FormPanelMode.EDIT, typeDescriptor);
}
public AbstractUserPopup(String id, UserTypeDescriptor<U> typeDescriptor) {
this(id, new GenericEntityModel<Long, U>(), FormPanelMode.ADD, typeDescriptor);
}
private AbstractUserPopup(String id, IModel<U> userModel, FormPanelMode mode, UserTypeDescriptor<U> typeDescriptor) {
super(id, userModel);
setStatic();
this.mode = mode;
this.typeDescriptor = typeDescriptor;
}
@Override
protected Component createHeader(String wicketId) {
if (isAddMode()) {
return new Label(wicketId, new ResourceModel("administration.user.add.title"));
} else {
return new Label(wicketId, new StringResourceModel("administration.user.update.title").setModel(getModel()));
}
}
protected final Component createStandardUserFields(String wicketId) {
DelegatedMarkupPanel standardFields = new DelegatedMarkupPanel(wicketId, "standardFields", AbstractUserPopup.class);
passwordField = new PasswordTextField("password", passwordModel);
confirmPasswordField = new PasswordTextField("confirmPassword", confirmPasswordModel);
boolean passwordRequired = securityManagementService.getOptions(typeDescriptor.getEntityClass()).isPasswordAdminUpdateEnabled()
&& !securityManagementService.getOptions(typeDescriptor.getEntityClass()).isPasswordUserRecoveryEnabled();
standardFields.add(
new RequiredTextField<String>("firstName", BindingModel.of(getModel(), Bindings.user().firstName()))
.setLabel(new ResourceModel("business.user.firstName")),
new RequiredTextField<String>("lastName", BindingModel.of(getModel(), Bindings.user().lastName()))
.setLabel(new ResourceModel("business.user.lastName")),
new RequiredTextField<String>("userName", BindingModel.of(getModel(), Bindings.user().userName()))
.setLabel(new ResourceModel("business.user.userName"))
.add(USERNAME_PATTERN_VALIDATOR)
.add(new UsernameUnicityValidator(getModel())),
new EnclosureContainer("addContainer")
.condition(Condition.predicate(Model.of(mode), equalTo(FormPanelMode.ADD)))
.add(
new EnclosureContainer("passwordContainer")
.condition(Condition.predicate(Model.of(securityManagementService.getOptions(typeDescriptor.getEntityClass()).isPasswordAdminUpdateEnabled()), isTrue()))
.add(
passwordField
.setLabel(new ResourceModel("business.user.password"))
.setRequired(passwordRequired)
.add(
new UserPasswordValidator(typeDescriptor)
.userModel(getModel())
),
new CoreLabel("passwordHelp",
new ResourceModel(
typeDescriptor.securityTypeDescriptor().resourceKeyGenerator().resourceKey("password.help"),
new ResourceModel(UserTypeDescriptor.USER.securityTypeDescriptor().resourceKeyGenerator().resourceKey("password.help"))
)
),
confirmPasswordField
.setLabel(new ResourceModel("business.user.confirmPassword"))
.setRequired(passwordRequired)
),
new CheckBox("active", BindingModel.of(getModel(), Bindings.user().active()))
.setLabel(new ResourceModel("business.user.active"))
),
new EmailTextField("email", BindingModel.of(getModel(), Bindings.user().email()))
.setLabel(new ResourceModel("business.user.email"))
.add(EmailAddressValidator.getInstance())
.add(new EmailUnicityValidator(getModel())),
new LocaleDropDownChoice("locale", BindingModel.of(getModel(), Bindings.user().locale()))
.setWidth(DropDownChoiceWidth.AUTO)
.setNullValid(true)
.setLabel(new ResourceModel("business.user.locale"))
);
return standardFields;
}
@Override
protected Component createFooter(String wicketId) {
DelegatedMarkupPanel footer = new DelegatedMarkupPanel(wicketId, AbstractUserPopup.class);
// Validate button
AjaxButton validate = new AjaxButton("save", userForm) {
private static final long serialVersionUID = 1L;
@Override
protected void onAfterSubmit(AjaxRequestTarget target, Form<?> form) {
User user = AbstractUserPopup.this.getModelObject();
try {
if (isAddMode()) {
String password = passwordModel.getObject();
userService.create(user);
userService.onCreate(user, BasicApplicationSession.get().getUser());
if (StringUtils.hasText(password)) {
securityManagementService.updatePassword(user, password, BasicApplicationSession.get().getUser());
} else {
securityManagementService.initiatePasswordRecoveryRequest(
user,
UserPasswordRecoveryRequestType.CREATION,
UserPasswordRecoveryRequestInitiator.ADMIN,
BasicApplicationSession.get().getUser()
);
getSession().success(getString("administration.user.add.success.notification"));
}
getSession().success(getString("administration.user.add.success"));
throw AdministrationUserDescriptionTemplate.<U>mapper()
.ignoreParameter2()
.map(AbstractUserPopup.this.getModel())
.newRestartResponseException();
} else {
User authenticatedUser = BasicApplicationSession.get().getUser();
if (authenticatedUser != null && authenticatedUser.equals(user) && user.getLocale() != null) {
BasicApplicationSession.get().setLocale(user.getLocale());
}
userService.update(user);
getSession().success(getString("administration.user.update.success"));
closePopup(target);
target.add(getPage());
}
} catch (RestartResponseException e) { // NOSONAR
throw e;
} catch (Exception e) {
if (isAddMode()) {
LOGGER.error("Error occured while creating user", e);
} else {
LOGGER.error("Error occured while updating user", e);
}
Session.get().error(getString("common.error.unexpected"));
}
FeedbackUtils.refreshFeedback(target, getPage());
}
@Override
protected void onError(AjaxRequestTarget target, Form<?> form) {
FeedbackUtils.refreshFeedback(target, getPage());
}
};
Label validateLabel;
if (isAddMode()) {
validateLabel = new Label("validateLabel", new ResourceModel("common.action.create"));
} else {
validateLabel = new Label("validateLabel", new ResourceModel("common.action.save"));
}
validate.add(validateLabel);
footer.add(validate);
// Cancel button
AbstractLink cancel = new AbstractLink("cancel") {
private static final long serialVersionUID = 1L;
};
addCancelBehavior(cancel);
footer.add(cancel);
return footer;
}
protected boolean isEditMode() {
return FormPanelMode.EDIT.equals(mode);
}
protected boolean isAddMode() {
return FormPanelMode.ADD.equals(mode);
}
@Override
public IModel<String> getCssClassNamesModel() {
return Model.of("modal-user");
}
@Override
protected void onShow(AjaxRequestTarget target) {
super.onShow(target);
if (isAddMode()) {
getModel().setObject(typeDescriptor.administrationTypeDescriptor().newInstance());
}
}
@Override
protected void onDetach() {
super.onDetach();
passwordModel.detach();
confirmPasswordModel.detach();
}
}