/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos 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 2 of the License, or
(at your option) any later version.
Cyclos 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 Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.controls.settings;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TimeZone;
import javax.servlet.http.HttpServletRequest;
import nl.strohalm.cyclos.annotations.Inject;
import nl.strohalm.cyclos.controls.ActionContext;
import nl.strohalm.cyclos.controls.BaseFormAction;
import nl.strohalm.cyclos.entities.settings.LocalSettings;
import nl.strohalm.cyclos.entities.settings.LocalSettings.DatePattern;
import nl.strohalm.cyclos.entities.settings.LocalSettings.Language;
import nl.strohalm.cyclos.entities.settings.LocalSettings.TransactionNumber;
import nl.strohalm.cyclos.services.access.ChannelService;
import nl.strohalm.cyclos.services.customization.MessageImportType;
import nl.strohalm.cyclos.services.customization.TranslationMessageService;
import nl.strohalm.cyclos.services.settings.SettingsService;
import nl.strohalm.cyclos.utils.FileUnits;
import nl.strohalm.cyclos.utils.RequestHelper;
import nl.strohalm.cyclos.utils.TextFormat;
import nl.strohalm.cyclos.utils.TimePeriod;
import nl.strohalm.cyclos.utils.binding.BeanBinder;
import nl.strohalm.cyclos.utils.binding.DataBinder;
import nl.strohalm.cyclos.utils.binding.DataBinderHelper;
import nl.strohalm.cyclos.utils.binding.MapBean;
import nl.strohalm.cyclos.utils.binding.PropertyBinder;
import nl.strohalm.cyclos.utils.conversion.TimeZoneConverter;
import org.apache.commons.lang.StringUtils;
/**
* Action used to edit local settings
* @author luis
*/
public class EditLocalSettingsAction extends BaseFormAction {
private ChannelService channelService;
private TranslationMessageService translationMessageService;
private DataBinder<LocalSettings> dataBinder;
public DataBinder<LocalSettings> getDataBinder() {
if (dataBinder == null) {
final BeanBinder<TransactionNumber> transactionNumberBinder = BeanBinder.instance(TransactionNumber.class, "transactionNumber");
transactionNumberBinder.registerBinder("prefix", PropertyBinder.instance(String.class, "prefix"));
transactionNumberBinder.registerBinder("padLength", PropertyBinder.instance(Integer.TYPE, "padLength"));
transactionNumberBinder.registerBinder("suffix", PropertyBinder.instance(String.class, "suffix"));
transactionNumberBinder.registerBinder("enabled", PropertyBinder.instance(Boolean.TYPE, "enabled"));
final BeanBinder<LocalSettings> binder = BeanBinder.instance(LocalSettings.class);
binder.registerBinder("applicationName", PropertyBinder.instance(String.class, "applicationName"));
binder.registerBinder("applicationUsername", PropertyBinder.instance(String.class, "applicationUsername"));
binder.registerBinder("rootUrl", PropertyBinder.instance(String.class, "rootUrl"));
binder.registerBinder("language", PropertyBinder.instance(Language.class, "language"));
binder.registerBinder("numberLocale", PropertyBinder.instance(LocalSettings.NumberLocale.class, "numberLocale"));
binder.registerBinder("precision", PropertyBinder.instance(LocalSettings.Precision.class, "precision"));
binder.registerBinder("highPrecision", PropertyBinder.instance(LocalSettings.Precision.class, "highPrecision"));
binder.registerBinder("decimalInputMethod", PropertyBinder.instance(LocalSettings.DecimalInputMethod.class, "decimalInputMethod"));
binder.registerBinder("datePattern", PropertyBinder.instance(LocalSettings.DatePattern.class, "datePattern"));
binder.registerBinder("timePattern", PropertyBinder.instance(LocalSettings.TimePattern.class, "timePattern"));
binder.registerBinder("timeZone", PropertyBinder.instance(TimeZone.class, "timeZone", TimeZoneConverter.instance()));
binder.registerBinder("containerUrl", PropertyBinder.instance(String.class, "containerUrl"));
binder.registerBinder("maxIteratorResults", PropertyBinder.instance(Integer.TYPE, "maxIteratorResults"));
binder.registerBinder("maxPageResults", PropertyBinder.instance(Integer.TYPE, "maxPageResults"));
binder.registerBinder("maxAjaxResults", PropertyBinder.instance(Integer.TYPE, "maxAjaxResults"));
binder.registerBinder("maxUploadSize", PropertyBinder.instance(Integer.TYPE, "maxUploadSize"));
binder.registerBinder("maxUploadUnits", PropertyBinder.instance(FileUnits.class, "maxUploadUnits"));
binder.registerBinder("maxImageWidth", PropertyBinder.instance(Integer.TYPE, "maxImageWidth"));
binder.registerBinder("maxImageHeight", PropertyBinder.instance(Integer.TYPE, "maxImageHeight"));
binder.registerBinder("maxThumbnailWidth", PropertyBinder.instance(Integer.TYPE, "maxThumbnailWidth"));
binder.registerBinder("maxThumbnailHeight", PropertyBinder.instance(Integer.TYPE, "maxThumbnailHeight"));
binder.registerBinder("csvUseHeader", PropertyBinder.instance(Boolean.TYPE, "csvUseHeader"));
binder.registerBinder("csvRecordSeparator", PropertyBinder.instance(LocalSettings.CsvRecordSeparator.class, "csvRecordSeparator"));
binder.registerBinder("csvValueSeparator", PropertyBinder.instance(LocalSettings.CsvValueSeparator.class, "csvValueSeparator"));
binder.registerBinder("csvStringQuote", PropertyBinder.instance(LocalSettings.CsvStringQuote.class, "csvStringQuote"));
binder.registerBinder("cyclosId", PropertyBinder.instance(String.class, "cyclosId"));
binder.registerBinder("smsEnabled", PropertyBinder.instance(Boolean.TYPE, "smsEnabled"));
binder.registerBinder("sendSmsWebServiceUrl", PropertyBinder.instance(String.class, "sendSmsWebServiceUrl"));
binder.registerBinder("smsCustomFieldId", PropertyBinder.instance(Long.TYPE, "smsCustomFieldId"));
binder.registerBinder("smsChannelName", PropertyBinder.instance(String.class, "smsChannelName"));
binder.registerBinder("emailRequired", PropertyBinder.instance(Boolean.TYPE, "emailRequired"));
binder.registerBinder("emailUnique", PropertyBinder.instance(Boolean.TYPE, "emailUnique"));
binder.registerBinder("transactionNumber", transactionNumberBinder);
binder.registerBinder("brokeringExpirationPeriod", DataBinderHelper.timePeriodBinder("brokeringExpirationPeriod"));
binder.registerBinder("deleteMessagesOnTrashAfter", DataBinderHelper.timePeriodBinder("deleteMessagesOnTrashAfter"));
binder.registerBinder("deletePendingRegistrationsAfter", DataBinderHelper.timePeriodBinder("deletePendingRegistrationsAfter"));
binder.registerBinder("memberSortOrder", PropertyBinder.instance(LocalSettings.SortOrder.class, "memberSortOrder"));
binder.registerBinder("memberResultDisplay", PropertyBinder.instance(LocalSettings.MemberResultDisplay.class, "memberResultDisplay"));
binder.registerBinder("adDescriptionFormat", PropertyBinder.instance(TextFormat.class, "adDescriptionFormat"));
binder.registerBinder("messageFormat", PropertyBinder.instance(TextFormat.class, "messageFormat"));
binder.registerBinder("schedulingHour", PropertyBinder.instance(Integer.TYPE, "schedulingHour"));
binder.registerBinder("schedulingMinute", PropertyBinder.instance(Integer.TYPE, "schedulingMinute"));
binder.registerBinder("transferListenerClass", PropertyBinder.instance(String.class, "transferListenerClass"));
binder.registerBinder("maxChargebackTime", DataBinderHelper.timePeriodBinder("maxChargebackTime"));
binder.registerBinder("chargebackDescription", PropertyBinder.instance(String.class, "chargebackDescription"));
binder.registerBinder("showCountersInAdCategories", PropertyBinder.instance(Boolean.TYPE, "showCountersInAdCategories"));
dataBinder = binder;
}
return dataBinder;
}
public TranslationMessageService getMessageService() {
return translationMessageService;
}
public SettingsService getSettingsService() {
return settingsService;
}
@Inject
public void setChannelService(final ChannelService channelService) {
this.channelService = channelService;
}
@Inject
public void setTranslationMessageService(final TranslationMessageService translationMessageService) {
this.translationMessageService = translationMessageService;
}
@Override
protected void formAction(final ActionContext context) throws Exception {
final LocalSettings oldSettings = settingsService.getLocalSettings();
LocalSettings settings = resolveLocalSettings(context);
settings = settingsService.save(settings);
// There are some steps when the language is changed...
if (oldSettings.getLanguage() != settings.getLanguage()) {
// Replace message bundle file
final Properties properties = translationMessageService.readFile(settings.getLocale());
translationMessageService.importFromProperties(properties, MessageImportType.REPLACE);
// Replace the translation settings (mail and messages)
settingsService.reloadTranslation();
}
context.sendMessage("settings.local.modified");
}
@Override
protected void prepareForm(final ActionContext context) throws Exception {
final HttpServletRequest request = context.getRequest();
final EditLocalSettingsForm form = context.getForm();
final LocalSettings settings = settingsService.getLocalSettings();
form.setSetting("enableSms", StringUtils.isNotEmpty(settings.getSendSmsWebServiceUrl()) || StringUtils.isNotEmpty(settings.getSmsChannelName()));
final TransactionNumber transactionNumber = settings.getTransactionNumber();
form.setSetting("enableTransactionNumber", transactionNumber != null && transactionNumber.getPadLength() > 0);
getDataBinder().writeAsString(form.getSetting(), settings);
RequestHelper.storeEnum(request, LocalSettings.Language.class, "languages");
RequestHelper.storeEnum(request, FileUnits.class, "uploadUnits");
RequestHelper.storeEnum(request, LocalSettings.NumberLocale.class, "numberLocales");
RequestHelper.storeEnum(request, LocalSettings.Precision.class, "precisions");
RequestHelper.storeEnum(request, LocalSettings.DecimalInputMethod.class, "decimalInputMethods");
final Map<DatePattern, String> datePatterns = new LinkedHashMap<DatePattern, String>();
for (final DatePattern datePattern : DatePattern.values()) {
datePatterns.put(datePattern, messageHelper.getDatePatternDescription(datePattern).toUpperCase());
}
request.setAttribute("datePatterns", datePatterns);
RequestHelper.storeEnum(request, LocalSettings.TimePattern.class, "timePatterns");
RequestHelper.storeEnum(request, LocalSettings.CsvRecordSeparator.class, "csvRecordSeparators");
RequestHelper.storeEnum(request, LocalSettings.CsvValueSeparator.class, "csvValueSeparators");
RequestHelper.storeEnum(request, LocalSettings.CsvStringQuote.class, "csvStringQuotes");
RequestHelper.storeEnum(request, LocalSettings.MemberResultDisplay.class, "memberResultDisplays");
RequestHelper.storeEnum(request, LocalSettings.SortOrder.class, "memberSortOrders");
RequestHelper.storeEnum(request, TextFormat.class, "textFormats");
request.setAttribute("brokeringExpirationUnits", Arrays.asList(TimePeriod.Field.DAYS, TimePeriod.Field.MONTHS, TimePeriod.Field.YEARS));
request.setAttribute("deleteMessagesExpirationUnits", Arrays.asList(TimePeriod.Field.DAYS, TimePeriod.Field.MONTHS, TimePeriod.Field.YEARS));
request.setAttribute("maxChargebackTimeUnits", Arrays.asList(TimePeriod.Field.DAYS, TimePeriod.Field.WEEKS, TimePeriod.Field.MONTHS));
request.setAttribute("indexRebuildingTimeUnits", Arrays.asList(TimePeriod.Field.DAYS, TimePeriod.Field.WEEKS, TimePeriod.Field.MONTHS));
request.setAttribute("smsChannels", channelService.listNonBuiltin());
request.setAttribute("smsCustomFields", channelService.possibleCustomFieldsAsPrincipal());
// Transform the time zones in an
final List<String> timeZones = new ArrayList<String>();
for (final String id : TimeZone.getAvailableIDs()) {
if (!id.contains("/") || id.contains("Etc")) {
continue;
}
timeZones.add(id);
}
Collections.sort(timeZones);
timeZones.add(0, "GMT");
request.setAttribute("timeZones", timeZones);
}
@Override
protected void validateForm(final ActionContext context) {
final LocalSettings settings = resolveLocalSettings(context);
settingsService.validate(settings);
}
/**
* Resolve the submitted local settings instance
*/
private LocalSettings resolveLocalSettings(final ActionContext context) {
final EditLocalSettingsForm form = context.getForm();
final LocalSettings settings = getDataBinder().readFromString(form.getSetting());
// If transaction number is not enabled, clear the setting
final MapBean tn = (MapBean) form.getSetting("transactionNumber");
if (!Boolean.parseBoolean((String) tn.get("enabled"))) {
settings.setTransactionNumber(null);
}
return settings;
}
}