make locale mandatory and validate language and country codes given are supported.

This commit is contained in:
Keith Woodlock
2012-05-31 02:10:13 +01:00
parent bb838509fc
commit 803db98668
5 changed files with 113 additions and 132 deletions
@@ -1,8 +0,0 @@
package org.mifosng.platform;
import org.mifosng.data.command.UpdateUsernamePasswordCommand;
public interface WritePlatformService {
void updateUsernamePasswordOnFirstTimeLogin(UpdateUsernamePasswordCommand command);
}
@@ -1,81 +0,0 @@
package org.mifosng.platform;
import static org.mifosng.platform.Specifications.usersThatMatch;
import org.mifosng.data.command.UpdateUsernamePasswordCommand;
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
import org.mifosng.platform.infrastructure.BasicPasswordEncodablePlatformUser;
import org.mifosng.platform.infrastructure.PlatformPasswordEncoder;
import org.mifosng.platform.infrastructure.PlatformUser;
import org.mifosng.platform.infrastructure.UsernameAlreadyExistsException;
import org.mifosng.platform.user.domain.AppUser;
import org.mifosng.platform.user.domain.AppUserRepository;
import org.mifosng.platform.user.domain.PlatformUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class WritePlatformServiceJpaRepositoryImpl implements WritePlatformService {
private final PlatformUserRepository platformUserRepository;
private final PlatformPasswordEncoder platformPasswordEncoder;
@Autowired
public WritePlatformServiceJpaRepositoryImpl(
final PlatformUserRepository platformUserRepository,
final PlatformPasswordEncoder platformPasswordEncoder
) {
this.platformUserRepository = platformUserRepository;
this.platformPasswordEncoder = platformPasswordEncoder;
}
@Transactional
@Override
public void updateUsernamePasswordOnFirstTimeLogin(final UpdateUsernamePasswordCommand command) {
AppUser currentUser = extractAuthenticatedUser();
try {
PlatformUser platformUser = ((AppUserRepository) this.platformUserRepository).findOne(usersThatMatch(currentUser.getOrganisation(), command.getOldUsername()));
PlatformUser dummyPlatformUser = new BasicPasswordEncodablePlatformUser(
((AppUser) platformUser).getId(),
platformUser.getUsername(), command.getPassword());
String encodePassword = this.platformPasswordEncoder.encode(dummyPlatformUser);
if (command.isUsernameToBeChanged()) {
platformUser.updateUsernamePasswordOnFirstTimeLogin(
command.getUsername(), encodePassword);
} else {
platformUser.updatePasswordOnFirstTimeLogin(encodePassword);
}
((AppUserRepository) this.platformUserRepository).save((AppUser) platformUser);
} catch (DataIntegrityViolationException e) {
throw new UsernameAlreadyExistsException(e);
}
}
private AppUser extractAuthenticatedUser() {
AppUser currentUser = null;
SecurityContext context = SecurityContextHolder.getContext();
if (context != null) {
Authentication auth = context.getAuthentication();
if (auth != null) {
currentUser = (AppUser) auth.getPrincipal();
}
}
if (currentUser == null) {
throw new UnAuthenticatedUserException();
}
return currentUser;
}
}
@@ -16,4 +16,6 @@ public interface ApiDataConversionService {
Locale clientApplicationLocale);
Locale localeFromString(String locale);
Locale localeFrom(String languageCode, String courntryCode, String variantCode);
}
@@ -1,9 +1,12 @@
package org.mifosng.platform.api.infrastructure;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@@ -13,6 +16,7 @@ import org.joda.time.format.DateTimeFormat;
import org.mifosng.platform.api.data.ApiParameterError;
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.format.number.NumberFormatter;
import org.springframework.stereotype.Service;
@Service
@@ -55,9 +59,33 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
Integer number = null;
if (StringUtils.isNotBlank(numericalValueFormatted)) {
String sourceWithoutSpaces = numericalValueFormatted.replaceAll(" ", "");
NumberFormat format = NumberFormat.getNumberInstance(clientApplicationLocale);
Number parsedNumber = format.parse(sourceWithoutSpaces);
String source = numericalValueFormatted.trim();
NumberFormat format = NumberFormat.getInstance(clientApplicationLocale);
DecimalFormat df = (DecimalFormat) format;
DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
df.setParseBigDecimal(true);
// http://bugs.sun.com/view_bug.do?bug_id=4510618
char groupingSeparator = symbols.getGroupingSeparator();
if (groupingSeparator == '\u00a0') {
source = source.replaceAll(" ", Character.toString('\u00a0'));
}
Number parsedNumber = df.parse(source);
double parsedNumberDouble = parsedNumber.doubleValue();
int parsedNumberInteger = parsedNumber.intValue();
if (source.contains(Character.toString(symbols.getDecimalSeparator()))) {
throw new ParseException(source, 0);
}
if (!Double.valueOf(parsedNumberDouble).equals(Double.valueOf(Integer.valueOf(parsedNumberInteger)))) {
throw new ParseException(source, 0);
}
number = parsedNumber.intValue();
}
@@ -66,9 +94,9 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.invalid.number.format", "The parameter "
+ parameterName + " is invalid for provided locale"
+ clientApplicationLocale.toString() + ".",
"validation.msg.invalid.integer.format", "The parameter "
+ parameterName + " has value: " + numericalValueFormatted + " which is invalid integer value for provided locale of ["
+ clientApplicationLocale.toString() + "].",
parameterName, numericalValueFormatted,
clientApplicationLocale);
dataValidationErrors.add(error);
@@ -80,20 +108,27 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
}
@Override
public BigDecimal convertFrom(String numericalValueFormatted,
String parameterName, Locale clientApplicationLocale) {
public BigDecimal convertFrom(final String numericalValueFormatted, final String parameterName, final Locale clientApplicationLocale) {
try {
BigDecimal number = null;
if (StringUtils.isNotBlank(numericalValueFormatted)) {
String sourceWithoutSpaces = numericalValueFormatted
.replaceAll(" ", "");
NumberFormat format = NumberFormat
.getNumberInstance(clientApplicationLocale);
Number parsedNumber = format.parse(sourceWithoutSpaces);
number = BigDecimal.valueOf(Double.valueOf(parsedNumber
.doubleValue()));
String source = numericalValueFormatted.trim();
NumberFormat format = NumberFormat.getNumberInstance(clientApplicationLocale);
DecimalFormat df = (DecimalFormat) format;
DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
// http://bugs.sun.com/view_bug.do?bug_id=4510618
char groupingSeparator = symbols.getGroupingSeparator();
if (groupingSeparator == '\u00a0') {
source = source.replaceAll(" ", Character.toString('\u00a0'));
}
NumberFormatter numberFormatter = new NumberFormatter();
Number parsedNumber = numberFormatter.parse(source, clientApplicationLocale);
number = BigDecimal.valueOf(Double.valueOf(parsedNumber.doubleValue()));
}
return number;
@@ -101,9 +136,9 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.invalid.number.format", "The parameter "
+ parameterName + " is invalid for provided locale"
+ clientApplicationLocale.toString() + ".",
"validation.msg.invalid.decimal.format", "The parameter "
+ parameterName + " has value: " + numericalValueFormatted + " which is invalid decimal value for provided locale of ["
+ clientApplicationLocale.toString() + "].",
parameterName, numericalValueFormatted,
clientApplicationLocale);
dataValidationErrors.add(error);
@@ -117,33 +152,65 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
@Override
public Locale localeFromString(final String localeAsString) {
Locale locale = Locale.getDefault();
if (StringUtils.isBlank(localeAsString)) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format", "The parameter locale is invalid. It cannot be blank.", "locale");
dataValidationErrors.add(error);
if (StringUtils.isNotBlank(localeAsString)) {
String[] localeParts = localeAsString.split("_");
String language = "en";
String country = "GB";
String variant = "";
if (localeParts != null && localeParts.length == 1) {
language = localeParts[0];
locale = new Locale(language);
}
if (localeParts != null && localeParts.length == 2) {
language = localeParts[0];
country = localeParts[1];
locale = new Locale(language, country);
}
if (localeParts != null && localeParts.length == 3) {
language = localeParts[0];
country = localeParts[1];
variant = localeParts[2];
locale = new Locale(language, country, variant);
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
String languageCode = "";
String courntryCode = "";
String variantCode = "";
String[] localeParts = localeAsString.split("_");
if (localeParts != null && localeParts.length == 1) {
languageCode = localeParts[0];
}
if (localeParts != null && localeParts.length == 2) {
languageCode = localeParts[0];
courntryCode = localeParts[1];
}
if (localeParts != null && localeParts.length == 3) {
languageCode = localeParts[0];
courntryCode = localeParts[1];
variantCode = localeParts[2];
}
return localeFrom(languageCode, courntryCode, variantCode);
}
@Override
public Locale localeFrom(final String languageCode, final String courntryCode, final String variantCode) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
List<String> allowedLanguages = Arrays.asList(Locale.getISOLanguages());
if (!allowedLanguages.contains(languageCode.toLowerCase())) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format", "The parameter locale has an invalid language value " + languageCode + " .", "locale", languageCode);
dataValidationErrors.add(error);
}
if (StringUtils.isNotBlank(courntryCode.toUpperCase())) {
List<String> allowedCountries = Arrays.asList(Locale.getISOCountries());
if (!allowedCountries.contains(courntryCode)) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format", "The parameter locale has an invalid country value " + courntryCode + " .", "locale", courntryCode);
dataValidationErrors.add(error);
}
}
return locale;
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
return new Locale(languageCode.toLowerCase(), courntryCode.toUpperCase(), variantCode);
}
}
@@ -128,6 +128,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
AppUser currentUser = context.authenticatedUser();
// FIXME - check client id matches.
Note noteForUpdate = this.noteRepository.findOne(notesThatMatch(currentUser.getOrganisation(), command.getId()));
if (noteForUpdate == null) {
throw new NoteNotFoundException(command.getClientId());