package org.sigmah.client.ui.presenter.admin; /* * #%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 com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Image; import com.google.inject.ImplementedBy; import com.google.inject.Inject; import com.google.inject.Singleton; import com.extjs.gxt.ui.client.event.ButtonEvent; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.FormEvent; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.event.SelectionListener; import com.extjs.gxt.ui.client.store.ListStore; import com.extjs.gxt.ui.client.store.StoreEvent; import com.extjs.gxt.ui.client.store.StoreListener; import com.extjs.gxt.ui.client.widget.form.ComboBox; import com.extjs.gxt.ui.client.widget.form.FileUploadField; import com.extjs.gxt.ui.client.widget.form.FormPanel.Encoding; import com.extjs.gxt.ui.client.widget.form.FormPanel.Method; import com.extjs.gxt.ui.client.widget.form.TextField; import java.util.Set; import org.sigmah.client.dispatch.CommandResultHandler; 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.N10N; import org.sigmah.client.ui.presenter.base.HasForm; import org.sigmah.client.ui.view.admin.ParametersAdminView; import org.sigmah.client.ui.widget.BackupStatusWidget; import org.sigmah.client.ui.widget.button.Button; import org.sigmah.client.ui.widget.form.FormPanel; import org.sigmah.client.util.ClientUtils; import org.sigmah.client.util.ImageProvider; import org.sigmah.offline.sync.SuccessCallback; import org.sigmah.shared.command.BackupArchiveManagementCommand; import org.sigmah.shared.command.GetGlobalExportSettings; import org.sigmah.shared.command.GetOrgUnits; import org.sigmah.shared.command.UpdateGlobalExportSettingsCommand; import org.sigmah.shared.command.UpdateOrganization; import org.sigmah.shared.command.result.ListResult; import org.sigmah.shared.command.result.VoidResult; import org.sigmah.shared.dto.BackupDTO; import org.sigmah.shared.dto.GlobalExportSettingsDTO; import org.sigmah.shared.dto.organization.OrganizationDTO; import org.sigmah.shared.dto.orgunit.OrgUnitDTO; import org.sigmah.shared.dto.value.FileDTO.LoadingScope; import org.sigmah.shared.servlet.ServletConstants; import org.sigmah.shared.servlet.ServletConstants.Servlet; import org.sigmah.shared.servlet.ServletConstants.ServletMethod; import org.sigmah.shared.servlet.ServletUrlBuilder; import org.sigmah.shared.util.ExportUtils.ExportFormat; import com.allen_sauer.gwt.log.client.Log; /** * Admin Parameters Presenter which manages {@link ParametersAdminView}. * * @author Maxime Lombard (mlombard@ideia.fr) * @author Denis Colliot (dcolliot@ideia.fr) */ @Singleton public class ParametersAdminPresenter extends AbstractAdminPresenter<ParametersAdminPresenter.View> implements HasForm { /** * Description of the view managed by this presenter. */ @ImplementedBy(ParametersAdminView.class) public static interface View extends AbstractAdminPresenter.View { // -- // General parameters. // -- FormPanel getGeneralParametersForm(); TextField<String> getOrganizationNameTextField(); FileUploadField getLogoFileField(); Image getLogoPreview(); Button getGeneralParametersSaveButton(); // -- // Backup. // -- FormPanel getBackupForm(); /** * Sets the selected backup download type. * * @param downloadType * The backup download type. */ void setSelectedBackupDownloadFormat(LoadingScope downloadType); /** * Returns the selected backup download type. * * @return The selected backup download type, or {@code null} if no option is selected. </ul> */ LoadingScope getSelectedBackupDownloadType(); ComboBox<OrgUnitDTO> getBackupManagementOrgUnitsComboBox(); Button getBackupSaveButton(); BackupStatusWidget getBackupStatus(); // -- // Export management. // -- FormPanel getExportManagementForm(); /** * Sets the selected export management format. * * @param exportFormat * The export management format: * <ul> * <li>{@link ExportFormat#XLS}</li> * <li>{@link ExportFormat#ODS}</li> * </ul> */ void setSelectedExportFormat(ExportFormat exportFormat); /** * Returns the selected export management format. * * @return The selected export management format: * <ul> * <li>{@link ExportFormat#XLS}</li> * <li>{@link ExportFormat#ODS}</li> * <li>{@code null} if no option is selected.</li> * </ul> */ ExportFormat getSelectedExportFormat(); Button getExportManagementSaveButton(); } /** * Backup status update timer (in ms). */ private static final int BACKUP_STATUS_UPDATE_TIMER_DELAY = 5000; /** * Timer used to regularly update the backup status once a backup process has been started. */ private Timer updateBackupStatusTimer; private ImageProvider imageProvider; /** * Presenters's initialization. * * @param view * Presenter's view interface. * @param injector * Injected client injector. */ @Inject protected ParametersAdminPresenter(View view, Injector injector, ImageProvider imageProvider) { super(view, injector); this.imageProvider = imageProvider; } /** * {@inheritDoc} */ @Override public Page getPage() { return Page.ADMIN_PARAMETERS; } /** * {@inheritDoc} */ @Override public void onBind() { // -- // General parameters handlers. // -- // Logo form submit handler. view.getGeneralParametersForm().addListener(Events.Submit, new Listener<FormEvent>() { @Override public void handleEvent(final FormEvent be) { final String newLogoFileName = ClientUtils.deletePreTags(be.getResultHtml()); if (ServletConstants.isErrorResponse(newLogoFileName)) { if (Log.isErrorEnabled()) { Log.error("Upload process failed. Received error code '" + newLogoFileName + "'."); } view.getGeneralParametersSaveButton().setLoading(false); throw new IllegalStateException(); } // Updates logo preview with uploaded file. displayLogo(newLogoFileName); N10N.validNotif(I18N.CONSTANTS.organizationManagementLogoNotificationTitle(), I18N.CONSTANTS.organizationManagementLogoNotificationMessage()); // Launches general form save (for organization name). saveGeneralParametersForm(newLogoFileName); } }); // Save button handler. view.getGeneralParametersSaveButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(final ButtonEvent ce) { if (ClientUtils.isBlank(view.getOrganizationNameTextField().getValue())) { N10N.warn(I18N.CONSTANTS.organizationManagementBlankNameNotificationError()); return; } final String logoFileName = view.getLogoFileField().getValue(); view.getGeneralParametersSaveButton().setLoading(true); if (ClientUtils.isNotBlank(logoFileName)) { // Submit logo file upload form. final ServletUrlBuilder urlBuilder = new ServletUrlBuilder(injector.getAuthenticationProvider(), injector.getPageManager(), Servlet.FILE, ServletMethod.UPLOAD_ORGANIZATION_LOGO); urlBuilder.addParameter(RequestParameter.ID, auth().getOrganizationId()); view.getGeneralParametersForm().setAction(urlBuilder.toString()); view.getGeneralParametersForm().setEncoding(Encoding.MULTIPART); view.getGeneralParametersForm().setMethod(Method.POST); view.getGeneralParametersForm().submit(); } else { // Directly executed action to update org name. saveGeneralParametersForm(auth().getOrganizationLogo()); } } }); // -- // Backup files handlers. // -- // Org unit models store listeners. view.getBackupManagementOrgUnitsComboBox().getStore().addStoreListener(new StoreListener<OrgUnitDTO>() { @Override public void storeClear(final StoreEvent<OrgUnitDTO> se) { view.getBackupManagementOrgUnitsComboBox().setEnabled(false); } @Override public void storeAdd(final StoreEvent<OrgUnitDTO> se) { view.getBackupManagementOrgUnitsComboBox().setEnabled(true); } }); view.getBackupSaveButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(final ButtonEvent ce) { saveBackupFilesForm(); } }); updateBackupStatusTimer = new Timer() { @Override public void run() { updateBackupStatus(false); } }; // -- // Export management handlers. // -- view.getExportManagementSaveButton().addSelectionListener(new SelectionListener<ButtonEvent>() { @Override public void componentSelected(final ButtonEvent ce) { saveExportManagementForm(); } }); } /** * {@inheritDoc} */ @Override public void onPageRequest(final PageRequest request) { // 'General Parameters' form reset is processed in 'onViewRevealed()' due to 'FileUploadField' constraints. view.getBackupForm().reset(); view.getBackupForm().clearAll(); view.getExportManagementForm().reset(); view.getExportManagementForm().clearAll(); // Loads organization data. view.getOrganizationNameTextField().setValue(auth().getOrganizationName()); displayLogo(auth().getOrganizationLogo()); // Retrieves OrgUnits and populates store. dispatch.execute(new GetOrgUnits(OrgUnitDTO.Mode.WITH_TREE), new CommandResultHandler<ListResult<OrgUnitDTO>>() { @Override public void onCommandSuccess(final ListResult<OrgUnitDTO> result) { for (OrgUnitDTO orgUnitDTO : result.getData()) { // Recursily fills the store. fillOrgUnitsCombobox(orgUnitDTO, view.getBackupManagementOrgUnitsComboBox().getStore()); } } }); // Updates backup status. updateBackupStatus(true); updateBackupStatusTimer.scheduleRepeating(BACKUP_STATUS_UPDATE_TIMER_DELAY); // Retrieves configured export format. dispatch.execute(new GetGlobalExportSettings(auth().getOrganizationId(), false), new CommandResultHandler<GlobalExportSettingsDTO>() { @Override public void onCommandSuccess(final GlobalExportSettingsDTO result) { view.setSelectedExportFormat(result.getDefaultOrganizationExportFormat()); view.getExportManagementForm().resetValueHasChanged(); } }, view.getExportManagementSaveButton()); } /** * {@inheritDoc} */ @Override protected void onViewRevealed() { // 'FileUploadField' reset needs to be processed once view has been rendered. view.getLogoFileField().reset(); } /** * {@inheritDoc} */ @Override public FormPanel[] getForms() { // Backup form does not not manage data to be saved. return new FormPanel[] { view.getGeneralParametersForm(), view.getExportManagementForm() }; } /** * {@inheritDoc} */ @Override protected void onLeavingOk() { updateBackupStatusTimer.cancel(); } // ------------------------------------------------------------------------------------------- // // UTILITY METHODS. // // ------------------------------------------------------------------------------------------- /** * Function to display the organization logo * * @param organisationLogo * File id of the logo */ private void displayLogo(final String organisationLogo) { imageProvider.provideDataUrl(organisationLogo, new SuccessCallback<String>() { @Override public void onSuccess(String dataUrl) { view.getLogoPreview().setUrl(dataUrl); } }); } /** * Updates the backup status. * * @param saveButtonLoading * {@code true} to set the save button in loading mode during update, {@code false} to ignore it. */ private void updateBackupStatus(final boolean saveButtonLoading) { dispatch.execute(new BackupArchiveManagementCommand(auth().getOrganizationId()), new CommandResultHandler<BackupDTO>() { @Override public void onCommandSuccess(final BackupDTO result) { view.getBackupStatus().update(result, new ClickHandler() { @Override public void onClick(final ClickEvent event) { final ServletUrlBuilder builder = new ServletUrlBuilder(injector.getAuthenticationProvider(), injector.getPageManager(), Servlet.FILE, ServletMethod.DOWNLOAD_ARCHIVE); builder.addParameter(RequestParameter.ID, result.getArchiveFileName()); ClientUtils.launchDownload(builder.toString()); } }); } }, saveButtonLoading ? view.getBackupSaveButton() : null); } /** * Fills combobox with given the children of the given root org units. * * @param unit * The root org unit. * @param store * The field store. */ private static void fillOrgUnitsCombobox(final OrgUnitDTO unit, final ListStore<OrgUnitDTO> store) { store.add(unit); final Set<OrgUnitDTO> children = unit.getChildrenOrgUnits(); if (ClientUtils.isNotEmpty(children)) { for (final OrgUnitDTO child : children) { fillOrgUnitsCombobox(child, store); } } } /** * Validates and saves the general parameters form. * * @param organizationLogoFileName * The organization logo file name (should never be {@code null}). */ private void saveGeneralParametersForm(final String organizationLogoFileName) { if (!view.getGeneralParametersForm().isValid()) { view.getGeneralParametersSaveButton().setLoading(false); return; } final OrganizationDTO organizationDTO = new OrganizationDTO(); organizationDTO.setId(auth().getOrganizationId()); organizationDTO.setName(view.getOrganizationNameTextField().getValue()); organizationDTO.setLogo(organizationLogoFileName); // Saves new organization name. dispatch.execute(new UpdateOrganization(organizationDTO), new CommandResultHandler<OrganizationDTO>() { @Override public void onCommandFailure(final Throwable e) { N10N.error(I18N.CONSTANTS.organizationManagementWebServiceNotificationError()); } @Override public void onCommandSuccess(final OrganizationDTO result) { N10N.validNotif(I18N.CONSTANTS.organizationManagementSaveChangesNotificationTitle(), I18N.CONSTANTS.organizationManagementSaveChangesNotificationMessage()); view.getGeneralParametersForm().resetValueHasChanged(); } }, view.getGeneralParametersSaveButton()); } /** * Validates and saves the backup files form. */ private void saveBackupFilesForm() { if (!view.getBackupForm().isValid()) { return; } if (view.getSelectedBackupDownloadType() == null || view.getBackupManagementOrgUnitsComboBox().getValue() == null) { N10N.warn(I18N.CONSTANTS.form_validation_ko()); return; } final BackupDTO backupConf = new BackupDTO(); backupConf.setOrganizationId(auth().getOrganizationId()); backupConf.setOrgUnitId(view.getBackupManagementOrgUnitsComboBox().getValue().getId()); backupConf.setLoadingScope(view.getSelectedBackupDownloadType()); dispatch.execute(new BackupArchiveManagementCommand(backupConf), new CommandResultHandler<BackupDTO>() { @Override public void onCommandSuccess(final BackupDTO result) { if (result == null) { N10N.valid(I18N.CONSTANTS.backupManagement_process_started()); } else { N10N.warn(I18N.CONSTANTS.backupManagement_process_alreadyRunning()); } updateBackupStatus(true); } }, view.getBackupSaveButton()); } /** * Validates and saves the export management form. */ private void saveExportManagementForm() { if (!view.getExportManagementForm().isValid()) { return; } final UpdateGlobalExportSettingsCommand command = new UpdateGlobalExportSettingsCommand(); command.setUpdateDefaultExportFormat(true); command.setDefaultOrganizationExportFormat(view.getSelectedExportFormat()); command.setOrganizationId(auth().getOrganizationId()); dispatch.execute(command, new CommandResultHandler<VoidResult>() { @Override public void onCommandFailure(final Throwable caught) { N10N.warn(I18N.CONSTANTS.saveExportConfiguration(), I18N.MESSAGES.adminStandardCreationFailure(I18N.CONSTANTS.defaultExportFormat())); } @Override public void onCommandSuccess(final VoidResult result) { N10N.validNotif(I18N.CONSTANTS.exportManagementSaveChangesNotificationTitle(), I18N.CONSTANTS.exportManagementSaveChangesNotificationMessage()); view.getExportManagementForm().resetValueHasChanged(); } }, view.getExportManagementSaveButton()); } }