diff --git a/src/main/java/net/hostsharing/hsadminng/config/MessageTranslator.java b/src/main/java/net/hostsharing/hsadminng/config/MessageTranslator.java index b179dcf3..3bcbbda5 100644 --- a/src/main/java/net/hostsharing/hsadminng/config/MessageTranslator.java +++ b/src/main/java/net/hostsharing/hsadminng/config/MessageTranslator.java @@ -1,5 +1,7 @@ package net.hostsharing.hsadminng.config; +import lombok.extern.slf4j.Slf4j; +import lombok.val; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.stereotype.Service; @@ -10,6 +12,7 @@ import java.util.Locale; @Service @RequestScope +@Slf4j public class MessageTranslator { @Autowired @@ -21,19 +24,26 @@ public class MessageTranslator { public String translateTo(final Locale locale, final String messageKey, final Object... args) { try { // we don't use the method which also takes a default message right away ... - final var translatedMessage = messageSource.getMessage(messageKey, args, locale); + val translatedMessage = messageSource.getMessage(messageKey, args, locale); return translatedMessage; } catch (final Exception e) { - final var defaultMessage = messageKey.replace("'", "''"); - final var translatedMessage = messageSource.getMessage(messageKey, args, defaultMessage, locale); - if (locale != Locale.ENGLISH) { - // ... because we want to add a hint that the translation is missing, even if placeholders got replaced - return translatedMessage + " [" + locale + " translation missing]"; - } - return translatedMessage; + // ... but log the missing translation ... + log.error("Missing translation for message key '{}' in locale '{}'", messageKey, locale, e); + + // and decorate the default message to mark it as not really translated: + val defaultMessage = messageKey.substring(messageKey.indexOf('.') + 1) + .replaceAll("--+", " - ") + .replaceAll("(? toEnrichedFieldErrorMessage() { - final var translatedButIsLiteral = messageTranslator.translate("but is"); + final var translatedButIsLiteral = messageTranslator.translate("general.but-is"); // TODO.i18n: the following does not work in all languages, e.g. not in right-to-left languages return fieldError -> fieldError.getField() + " " + fieldError.getDefaultMessage() + " " + translatedButIsLiteral + " " + optionallyQuoted(fieldError.getRejectedValue()); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/accounts/CredentialContextResourceToEntityMapper.java b/src/main/java/net/hostsharing/hsadminng/hs/accounts/CredentialContextResourceToEntityMapper.java index 225ee95a..a0ab46e1 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/accounts/CredentialContextResourceToEntityMapper.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/accounts/CredentialContextResourceToEntityMapper.java @@ -52,13 +52,15 @@ public class CredentialContextResourceToEntityMapper { final var existingContextEntity = em.find(HsCredentialsContextRealEntity.class, resource.getUuid()); if (existingContextEntity == null) { throw new EntityNotFoundException( - messageTranslator.translate("{0} \"{1}\" not found or not accessible", + messageTranslator.translate( + "general.{0}-{1}-not-found-or-not-accessible", "credentials uuid", resource.getUuid())); } if ((resource.getType() != null && !existingContextEntity.getType().equals(resource.getType())) || (resource.getQualifier() != null && !existingContextEntity.getQualifier().equals(resource.getQualifier()))) { throw new EntityNotFoundException( - messageTranslator.translate("existing {0} does not match given resource {1}", + messageTranslator.translate( + "credentials.existing-{0}-does-not-match-given-resource-{1}", existingContextEntity, resource)); } entities.add(existingContextEntity); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/accounts/HsCredentialsController.java b/src/main/java/net/hostsharing/hsadminng/hs/accounts/HsCredentialsController.java index 52e52c7e..23de6056 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/accounts/HsCredentialsController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/accounts/HsCredentialsController.java @@ -203,12 +203,12 @@ public class HsCredentialsController implements CredentialsApi { private void validate(final HsCredentialsEntity newCredentialsEntity) { // the referenced person must be represented by currently logged in person final var personUuid = newCredentialsEntity.getPerson().getUuid(); - final var representedPersonUuids = rbacPersonRepo.findPersonsrepresentedByPersonWithUuid(personUuid) + final var representedPersonUuids = rbacPersonRepo.findPersonsRepresentedByPersonWithUuid(personUuid) .stream().map(HsOfficePerson::getUuid).toList(); if ( !representedPersonUuids.contains(personUuid)) { throw new ValidationException( messageTranslator.translate( - "access-denied-personUuid-{0}-not-represented-by-currently-logged-in-person", + "credentials.access-denied-person-uuid-{0}-not-represented-by-currently-logged-in-person", personUuid)); } } @@ -224,7 +224,7 @@ public class HsCredentialsController implements CredentialsApi { private List findByPersonUuid(final UUID personUuid) { final var person = rbacPersonRepo.findByUuid(personUuid).orElseThrow( () -> new EntityNotFoundException( - messageTranslator.translate("{0} \"{1}\" not found or not accessible", "personUuid", personUuid) + messageTranslator.translate("general.{0}-{1}-not-found-or-not-accessible", "personUuid", personUuid) ) ); @@ -269,7 +269,7 @@ public class HsCredentialsController implements CredentialsApi { final BiConsumer RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> { final var person = rbacPersonRepo.findByUuid(resource.getPersonUuid()).orElseThrow( () -> new EntityNotFoundException( - messageTranslator.translate("{0} \"{1}\" not found or not accessible", "personUuid", resource.getPersonUuid()) + messageTranslator.translate("general.{0}-{1}-not-found-or-not-accessible", "personUuid", resource.getPersonUuid()) ) ); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsCoopAssetTranslations.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsCoopAssetTranslations.java index d61f59ed..f64c33d1 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsCoopAssetTranslations.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsCoopAssetTranslations.java @@ -17,7 +17,7 @@ public class HsCoopAssetTranslations implements RetroactiveTranslator { @Override public boolean canTranslate(final String message) { - return message.equals("ERROR: [400] coop assets transaction would result in a negative balance of assets"); + return message.equals("ERROR: [400] office.coop-assets.transaction-would-result-in-a-negative-balance-of-assets"); } @Override @@ -26,7 +26,7 @@ public class HsCoopAssetTranslations implements RetroactiveTranslator { // and in this case it's just one return ERROR_400_PREFIX + messageTranslator.translate(message.substring(ERROR_400_PREFIX.length())); - // HOWTO extract variable parts from a messages which got created without i18n support: + // HOWTO extract variable parts from messages which got created without i18n support: // final var regex = "(?[^ ]+) (?.+) not found"; // final var pattern = Pattern.compile(regex); // final var matcher = pattern.matcher(message); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionController.java index fc273f75..60eba51e 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionController.java @@ -141,7 +141,8 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse final ArrayList violations) { if (List.of(DEPOSIT, HsOfficeCoopAssetsTransactionTypeResource.ADOPTION).contains(requestBody.getTransactionType()) && requestBody.getAssetValue().signum() < 0) { - violations.add(messageTranslator.translate("for transactionType={0}, assetValue must be positive but is {1,number,#0.00}", + violations.add(messageTranslator.translate( + "office.coop-assets.for-transactiontype-{0}-assetvalue-must-be-positive-but-is-{1,number,#0.00}", requestBody.getTransactionType(), requestBody.getAssetValue())); } } @@ -152,7 +153,8 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse if (List.of(DISBURSAL, HsOfficeCoopAssetsTransactionTypeResource.TRANSFER, CLEARING, LOSS) .contains(requestBody.getTransactionType()) && requestBody.getAssetValue().signum() > 0) { - violations.add(messageTranslator.translate("for transactionType={0}, assetValue must be negative but is {1,number,#0.00}", + violations.add(messageTranslator.translate( + "office.coop-assets.for-transactiontype-{0}-assetvalue-must-be-negative-but-is-{1,number,#0.00}", requestBody.getTransactionType(), requestBody.getAssetValue())); } } @@ -161,7 +163,7 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse final HsOfficeCoopAssetsTransactionInsertResource requestBody, final ArrayList violations) { if (requestBody.getAssetValue().signum() == 0) { - violations.add(messageTranslator.translate("assetValue must not be 0")); + violations.add(messageTranslator.translate("office.coop-assets.assetvalue-must-not-be-0")); } } @@ -227,18 +229,18 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse resource.getMembershipUuid())) .orElseThrow(() -> new EntityNotFoundException( messageTranslator.translate( - "{0} \"{1}\" not found", "membership.uuid", resource.getMembershipUuid()))); + "general.{0}-{1}-not-found", "membership.uuid", resource.getMembershipUuid()))); entity.setMembership(membership); } if (entity.getTransactionType() == REVERSAL) { if (resource.getRevertedAssetTxUuid() == null) { throw new ValidationException(messageTranslator.translate( - "a REVERSAL asset transaction requires specifying a revertedAssetTx.uuid")); + "office.coop-assets.a-reversal-asset-transaction-requires-specifying-a-revertedassettx-uuid")); } final var revertedAssetTx = coopAssetsTransactionRepo.findByUuid(resource.getRevertedAssetTxUuid()) .orElseThrow(() -> new EntityNotFoundException(messageTranslator.translate( - "{0} \"{1}\" not found", + "general.{0}-{1}-not-found", "revertedAssetTx.uuid", resource.getRevertedAssetTxUuid()))); revertedAssetTx.setReversalAssetTx(entity); @@ -246,7 +248,7 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse if (resource.getAssetValue().negate().compareTo(revertedAssetTx.getAssetValue()) != 0) { throw new ValidationException( messageTranslator.translate( - "given assetValue {0,number,#0.00} must be the negative value of the reverted asset transaction: {1,number,#0.00}", + "office.coop-assets.given-assetvalue-{0,number,#0.00}-must-be-the-negative-value-of-the-reverted-asset-transaction-{1,number,#0.00}", resource.getAssetValue(), revertedAssetTx.getAssetValue())); } @@ -270,7 +272,7 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse final var adoptingMembership = determineAdoptingMembership(resource); if ( entity.getMembership() == adoptingMembership) { throw new ValidationException(messageTranslator.translate( - "transferring and adopting membership must be different, but both are {0}", + "office.coop-assets.transferring-and-adopting-membership-must-be-different-but-both-are-{0}", adoptingMembership.getTaggedMemberNumber())); } final var adoptingAssetTx = createAdoptingAssetTx(entity, adoptingMembership); @@ -285,8 +287,8 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse // @formatter:off final var message = messageTranslator.translate( resource.getTransactionType() == HsOfficeCoopAssetsTransactionTypeResource.TRANSFER - ? "either {0} or {1} must be given, not both" - : "neither {0} nor {1} must be given for transactionType={2}", + ? "office.coop-assets.either-{0}-or-{1}-must-be-given-not-both" + : "office.coop-assets.neither-{0}-nor-{1}-must-be-given-for-transactiontype-{2}", "adoptingMembership.uuid", "adoptingMembership.memberNumber", resource.getTransactionType()); @@ -298,7 +300,7 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse final var adoptingMembership = membershipRepo.findByUuid(adoptingMembershipUuid); return adoptingMembership.orElseThrow(() -> new ValidationException(messageTranslator.translate( - "{0} \"{1}\" not found or not accessible", + "general.{0}-{1}-not-found-or-not-accessible", "adoptingMembership.uuid", adoptingMembershipUuid))); } @@ -309,14 +311,14 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse return adoptingMembership.orElseThrow( () -> new ValidationException( messageTranslator.translate( - "{0} \"{1}\" not found or not accessible", + "general.{0}-{1}-not-found-or-not-accessible", "adoptingMembership.memberNumber", adoptingMembershipMemberNumber))); } throw new ValidationException( messageTranslator.translate( - "either {0} or {1} must be given for transactionType={2}", + "office.coop-assets.either-{0}-or-{1}-must-be-given-for-transactiontype-{2}", "adoptingMembership.uuid", "adoptingMembership.memberNumber", resource.getTransactionType() diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsCoopShareTranslations.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsCoopShareTranslations.java index 67665441..1353e8d7 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsCoopShareTranslations.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsCoopShareTranslations.java @@ -16,7 +16,7 @@ public class HsCoopShareTranslations implements RetroactiveTranslator { @Override public boolean canTranslate(final String message) { - return message.equals("ERROR: [400] coop shares transaction would result in a negative number of shares"); + return message.equals("ERROR: [400] office.coop-shares.transaction-would-result-in-a-negative-number-of-shares"); } @Override diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java index 5fc1b969..e6ea4850 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java @@ -129,7 +129,8 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar final ArrayList violations) { if (requestBody.getTransactionType() == SUBSCRIPTION && requestBody.getShareCount() < 0) { - violations.add(messageTranslator.translate("for transactionType={0}, shareCount must be positive but is {1}", + violations.add(messageTranslator.translate( + "office.coop-shares.for-transactiontype-{0}-sharecount-must-be-positive-but-is-{1}", requestBody.getTransactionType(), requestBody.getShareCount())); } } @@ -139,7 +140,8 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar final ArrayList violations) { if (requestBody.getTransactionType() == CANCELLATION && requestBody.getShareCount() > 0) { - violations.add(messageTranslator.translate("for transactionType={0}, shareCount must be negative but is {1}", + violations.add(messageTranslator.translate( + "office.coop-shares.for-transactiontype-{0}-sharecount-must-be-negative-but-is-{1}", requestBody.getTransactionType(), requestBody.getShareCount())); } } @@ -148,7 +150,7 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar final HsOfficeCoopSharesTransactionInsertResource requestBody, final ArrayList violations) { if (requestBody.getShareCount() == 0) { - violations.add(messageTranslator.translate("shareCount must not be 0")); + violations.add(messageTranslator.translate("office.coop-shares.sharecount-must-not-be-0")); } } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonController.java index b59d6b1d..7cf10186 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonController.java @@ -42,7 +42,7 @@ public class HsOfficePersonController implements HsOfficePersonsApi { context.assumeRoles(assumedRoles); final var entities = representedByPersonUuid != null - ? personRepo.findPersonsrepresentedByPersonWithUuid(representedByPersonUuid) + ? personRepo.findPersonsRepresentedByPersonWithUuid(representedByPersonUuid) : personRepo.findPersonByOptionalNameLike(name); final var resources = mapper.mapList(entities, HsOfficePersonResource.class); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRbacRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRbacRepository.java index e171feef..123d1c04 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRbacRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRbacRepository.java @@ -37,7 +37,7 @@ public interface HsOfficePersonRbacRepository extends Repository findPersonsrepresentedByPersonWithUuid(UUID personUuid); + List findPersonsRepresentedByPersonWithUuid(UUID personUuid); @Timed("app.office.persons.repo.save.rbac") HsOfficePersonRbacEntity save(final HsOfficePersonRbacEntity entity); diff --git a/src/main/java/net/hostsharing/hsadminng/ping/PingController.java b/src/main/java/net/hostsharing/hsadminng/ping/PingController.java index 668defba..eb39e2cd 100644 --- a/src/main/java/net/hostsharing/hsadminng/ping/PingController.java +++ b/src/main/java/net/hostsharing/hsadminng/ping/PingController.java @@ -21,9 +21,8 @@ public class PingController implements TestApi { @PreAuthorize("permitAll()") @Timed("app.api.ping") public ResponseEntity ping() { - final var userName = SecurityContextHolder.getContext().getAuthentication().getName(); // HOWTO translate text with placeholders - also see in resource files i18n/messages_*.properties. - final var translatedMessage = messageTranslator.translate("pong {0} - in English", userName); + final var translatedMessage = messageTranslator.translate("test.pinged--in-your-language"); return ResponseEntity.ok(translatedMessage + "\n"); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 520d897f..269119c9 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -72,9 +72,9 @@ metrics: logging: level: org.springframework.security: info - org.springframework.web: DEBUG - org.springframework.web.method.annotation: DEBUG - org.springframework.validation: DEBUG +# org.springframework.web: DEBUG +# org.springframework.web.method.annotation: DEBUG +# org.springframework.validation: DEBUG # HOWTO configure logging, e.g. logging to a separate file, see: # https://docs.spring.io/spring-boot/reference/features/logging.html diff --git a/src/main/resources/db/changelog/5-hs-office/511-coopshares/5110-hs-office-coopshares.sql b/src/main/resources/db/changelog/5-hs-office/511-coopshares/5110-hs-office-coopshares.sql index c6327e7b..be567a3c 100644 --- a/src/main/resources/db/changelog/5-hs-office/511-coopshares/5110-hs-office-coopshares.sql +++ b/src/main/resources/db/changelog/5-hs-office/511-coopshares/5110-hs-office-coopshares.sql @@ -33,7 +33,7 @@ alter table hs_office.coopsharetx --// -- ============================================================================ ---changeset marc.sandlus:hs-office-coopshares-SHARE-COUNT-CONSTRAINT-BY-TRIGGER endDelimiter:--// +--changeset marc.sandlus:hs-office-coopshares-SHARE-COUNT-CONSTRAINT-BY-TRIGGER runOnChange:true validCheckSum:ANY endDelimiter:--// -- ---------------------------------------------------------------------------- alter table hs_office.coopsharetx drop constraint if exists check_positive_total_shares_count; @@ -42,7 +42,6 @@ drop function if exists hs_office.coopsharestx_check_positive_total cascade; create or replace function hs_office.coopsharetx_enforce_positive_total() returns trigger as $$ - declare currentShareCount integer; totalShareCount integer; @@ -53,12 +52,13 @@ begin into currentShareCount; totalShareCount := currentShareCount + NEW.shareCount; if totalShareCount < 0 then - raise exception '[400] coop shares transaction would result in a negative number of shares'; + raise exception '[400] office.coop-shares.transaction-would-result-in-a-negative-number-of-shares'; end if; return NEW; end; $$ LANGUAGE plpgsql;; +drop trigger if exists positive_total_shares_count_tg on hs_office.coopsharetx; create trigger positive_total_shares_count_tg before insert on hs_office.coopsharetx diff --git a/src/main/resources/db/changelog/5-hs-office/512-coopassets/5120-hs-office-coopassets.sql b/src/main/resources/db/changelog/5-hs-office/512-coopassets/5120-hs-office-coopassets.sql index 90d1c37b..0a53f2a2 100644 --- a/src/main/resources/db/changelog/5-hs-office/512-coopassets/5120-hs-office-coopassets.sql +++ b/src/main/resources/db/changelog/5-hs-office/512-coopassets/5120-hs-office-coopassets.sql @@ -73,7 +73,7 @@ CREATE TRIGGER enforce_transaction_constraints --// -- ============================================================================ ---changeset marc.sandlus:hs-office-coopassets-ASSET-VALUE-CONSTRAINT-BY-TRIGGER endDelimiter:--// +--changeset marc.sandlus:hs-office-coopassets-ASSET-VALUE-CONSTRAINT-BY-TRIGGER runOnChange:true validCheckSum:ANY endDelimiter:--// -- ---------------------------------------------------------------------------- alter table hs_office.coopassettx @@ -83,7 +83,6 @@ drop function if exists hs_office.coopassetstx_check_positive_total cascade; create or replace function hs_office.coopassettx_enforce_positive_total() returns trigger as $$ - declare currentAssetValue numeric(12,2); totalAssetValue numeric(12,2); @@ -94,12 +93,14 @@ begin into currentAssetValue; totalAssetValue := currentAssetValue + NEW.assetValue; if totalAssetValue::numeric < 0 then - raise exception '[400] coop assets transaction would result in a negative balance of assets'; + raise exception '[400] office.coop-assets.transaction-would-result-in-a-negative-balance-of-assets'; end if; return NEW; end; $$ LANGUAGE plpgsql;; +drop trigger if exists positive_total_assets_count_tg on hs_office.coopassettx; + create trigger positive_total_assets_count_tg before insert on hs_office.coopassettx for each row execute function hs_office.coopassettx_enforce_positive_total(); diff --git a/src/main/resources/i18n/messages_de.properties b/src/main/resources/i18n/messages_de.properties index c5e7bcf5..5c1863ed 100644 --- a/src/main/resources/i18n/messages_de.properties +++ b/src/main/resources/i18n/messages_de.properties @@ -1,36 +1,38 @@ # This file must be in UTF-8 encoding. Check if you see umlauts or garbage: äöüÄÖÜß. # HINT IntelliJ IDEA shows unused keys in gray. -pong\ {0}\ -\ in\ English=pong {0} - auf Deutsch +test.pinged--in-your-language=pinged - auf Deutsch +test.ponged-{0}--in-your-language=ponged {0} - auf Deutsch +test.available-in-all-properties-files=Hallo {0} - DE! -# config (including authorization) -CAS\ service-ticket\ could\ not\ be\ verified=CAS Service-Ticket konnte nicht verifiziert werden -unknown\ authorization\ ticket=unbekanntes Autorisierungs-Ticket +# authorization +auth.cas-service-ticket-could-not-be-verified=CAS Service-Ticket konnte nicht verifiziert werden +auth.unknown-authorization-ticket=unbekanntes Autorisierungs-Ticket # general validations -{0}\ "{1}"\ not\ found={0} "{1}" nicht gefunden -{0}\ "{1}"\ not\ found\ or\ not\ accessible={0} "{1}" nicht gefunden oder nicht zugänglich -but\ is=ist aber +general.{0}-{1}-not-found={0} "{1}" nicht gefunden +general.{0}-{1}-not-found-or-not-accessible={0} "{1}" nicht gefunden oder nicht zugänglich +general.but-is=ist aber # credentials validations -existing\ {0}\ does\ not\ match\ given\ resource\ {1}=existierender Credentials-Context {0} passt nicht zum angegebenen {1} -access-denied-personUuid-{0}-not-represented-by-currently-logged-in-person=Zugriff verweigert: personUuid "{0}" wird von der eingeloggten Person nicht repräsentiert +credentials.existing-{0}-does-not-match-given-resource-{1}=existierender Credentials-Context {0} passt nicht zum angegebenen {1} +credentials.access-denied-person-uuid-{0}-not-represented-by-currently-logged-in-person=Zugriff verweigert: personUuid "{0}" wird von der eingeloggten Person nicht repräsentiert # office.coop-shares -for\ transactionType\={0},\ shareCount\ must\ be\ positive\ but\ is\ {1}=für transactionType={0}, muss shareCount positiv sein, ist aber {1} -for\ transactionType\={0},\ shareCount\ must\ be\ negative\ but\ is\ {1}=für transactionType={0}, muss shareCount negativ sein, ist aber {1} -shareCount\ must\ not\ be\ 0=shareCount darf nicht 0 sein -coop\ shares\ transaction\ would\ result\ in\ a\ negative\ number\ of\ shares=Geschäftsanteile-Transaktion würde zu negativen Geschäftsanteilen führen +office.coop-shares.for-transactiontype-{0}-sharecount-must-be-positive-but-is-{1}=für transactionType={0}, muss shareCount positiv sein, ist aber {1} +office.coop-shares.for-transactiontype-{0}-sharecount-must-be-negative-but-is-{1}=für transactionType={0}, muss shareCount negativ sein, ist aber {1} +office.coop-shares.sharecount-must-not-be-0=shareCount darf nicht 0 sein +office.coop-shares.transaction-would-result-in-a-negative-number-of-shares=Geschäftsanteile-Transaktion würde zu negativen Geschäftsanteilen führen # office.coop-assets -either\ {0}\ or\ {1}\ must\ be\ given=entweder {0} oder {1} muss angegeben werden -either\ {0}\ or\ {1}\ must\ be\ given,\ not\ both=entweder {0} oder {1} muss angegeben werden, nicht beide -either\ {0}\ or\ {1}\ must\ be\ given\ for\ transactionType\={2}=für transactionType={2} muss entweder {0} oder {1} angegeben werden -neither\ {0}\ nor\ {1}\ must\ be\ given\ for\ transactionType\={2}=für transactionType={2} darf weder {0} noch {1} angegeben werden -assetValue\ must\ not\ be\ 0=assetValue darf nicht 0 sein -for\ transactionType\={0},\ assetValue\ must\ be\ positive\ but\ is\ {1,number,#0.00}=für transactionType={0}, muss assetValue positiv sein, ist aber {1,number,#0.00} -for\ transactionType\={0},\ assetValue\ must\ be\ negative\ but\ is\ {1,number,#0.00}=für transactionType={0}, muss assetValue negativ sein, ist aber {1,number,#0.00} -given\ assetValue\ {0,number,#0.00}\ must\ be\ the\ negative\ value\ of\ the\ reverted\ asset\ transaction\:\ {1,number,#0.00}=assetValue={0,number,#0.00} muss dem negativen Wert des Wertes der stornierten Geschäftsguthaben-Transaktion entsprechen: {1,number,#0.00} -a\ REVERSAL\ asset\ transaction\ requires\ specifying\ a\ revertedAssetTx.uuid=eine REVERSAL Geschäftsguthaben-Transaktion erfordert die Angabe einer revertedAssetTx.uuid -transferring\ and\ adopting\ membership\ must\ be\ different,\ but\ both\ are\ {0}=übertragende und annehmende Mitgliedschaft müssen unterschiedlich sein, aber beide sind {0} -coop\ assets\ transaction\ would\ result\ in\ a\ negative\ balance\ of\ assets=Geschäftsguthaben-Transaktion würde zu einem negativen Geschäftsguthaben-Saldo führen +office.coop-assets.either-{0}-or-{1}-must-be-given=entweder {0} oder {1} muss angegeben werden +office.coop-assets.either-{0}-or-{1}-must-be-given-not-both=entweder {0} oder {1} muss angegeben werden, nicht beide +office.coop-assets.either-{0}-or-{1}-must-be-given-for-transactiontype-{2}=für transactionType={2} muss entweder {0} oder {1} angegeben werden +office.coop-assets.neither-{0}-nor-{1}-must-be-given-for-transactiontype-{2}=für transactionType={2} darf weder {0} noch {1} angegeben werden +office.coop-assets.assetvalue-must-not-be-0=assetValue darf nicht 0 sein +office.coop-assets.for-transactiontype-{0}-assetvalue-must-be-positive-but-is-{1,number,#0.00}=für transactionType={0}, muss assetValue positiv sein, ist aber {1,number,#0.00} +office.coop-assets.for-transactiontype-{0}-assetvalue-must-be-negative-but-is-{1,number,#0.00}=für transactionType={0}, muss assetValue negativ sein, ist aber {1,number,#0.00} +office.coop-assets.given-assetvalue-{0,number,#0.00}-must-be-the-negative-value-of-the-reverted-asset-transaction-{1,number,#0.00}=assetValue={0,number,#0.00} muss dem negativen Wert des Wertes der stornierten Geschäftsguthaben-Transaktion entsprechen: {1,number,#0.00} +office.coop-assets.a-reversal-asset-transaction-requires-specifying-a-revertedassettx-uuid=eine REVERSAL Geschäftsguthaben-Transaktion erfordert die Angabe einer revertedAssetTx.uuid +office.coop-assets.transferring-and-adopting-membership-must-be-different-but-both-are-{0}=übertragende und annehmende Mitgliedschaft müssen unterschiedlich sein, aber beide sind {0} +office.coop-assets.transaction-would-result-in-a-negative-balance-of-assets=Geschäftsguthaben-Transaktion würde zu einem negativen Geschäftsguthaben-Saldo führen diff --git a/src/main/resources/i18n/messages_en.properties b/src/main/resources/i18n/messages_en.properties index e318f0be..95981898 100644 --- a/src/main/resources/i18n/messages_en.properties +++ b/src/main/resources/i18n/messages_en.properties @@ -1,9 +1,39 @@ # This file must be in UTF-8 encoding. Check if you see umlauts or garbage: äöüÄÖÜß # HINT IntelliJ IDEA shows unused keys in gray. -# If the English translation is identical to the translation-key, it does not need to be included here. -# But in that case, you can NOT use a prefix - or the prefix would be shown to the user as well. -# I'm not sure, though, if using the english default translations as keys is really a good idea. +test.pinged--in-your-language=pinged - in English +test.ponged-{0}--in-your-language=ponged {0} - in English +test.available-in-all-properties-files=Hello {0} - EN! + +# authorization +auth.cas-service-ticket-could-not-be-verified=CAS service-ticket could not be verified +auth.unknown-authorization-ticket=unknown authorization ticket + +# general validations +general.{0}-{1}-not-found={0} "{1}" not found +general.{0}-{1}-not-found-or-not-accessible={0} "{1}" not found or not accessible +general.but-is=but is # credentials validations -access-denied-personUuid-{0}-not-represented-by-currently-logged-in-person=access denied: personUuid "{0}" not represented by currently logged in person +credentials.existing-{0}-does-not-match-given-resource-{1}=existing {0} does not match given resource {1} +credentials.access-denied-person-uuid-{0}-not-represented-by-currently-logged-in-person=access denied: personUuid "{0}" not represented by currently logged in person + +# office.coop-shares +office.coop-shares.for-transactiontype-{0}-sharecount-must-be-positive-but-is-{1}=for transactiontType {0} shareCount must be positive but is {1} +office.coop-shares.for-transactiontype-{0}-sharecount-must-be-negative-but-is-{1}=for transactiontType {0} shareCount must be negative but is {1} +office.coop-shares.sharecount-must-not-be-0=shareCount must not be 0 +office.coop-shares.transaction-would-result-in-a-negative-number-of-shares=coop shares transaction would result in a negative number of shares + +# office.coop-assets +office.coop-assets.either-{0}-or-{1}-must-be-given=either {0} or {1} must be given +office.coop-assets.either-{0}-or-{1}-must-be-given-not-both=either {0} or {1} must be given not both +office.coop-assets.either-{0}-or-{1}-must-be-given-for-transactiontype-{2}=either {0} or {1} must be given for transactionType {2} +office.coop-assets.neither-{0}-nor-{1}-must-be-given-for-transactiontype-{2}=neither {0} nor {1} must be given for transactionType {2} +office.coop-assets.assetvalue-must-not-be-0=assetvalue must not be 0 +office.coop-assets.for-transactiontype-{0}-assetvalue-must-be-positive-but-is-{1,number,#0.00}=for transactionType {0} assetValue must be positive but is {1,number,#0.00} +office.coop-assets.for-transactiontype-{0}-assetvalue-must-be-negative-but-is-{1,number,#0.00}=for transactionType {0} assetValue must be negative but is {1,number,#0.00} +office.coop-assets.given-assetvalue-{0,number,#0.00}-must-be-the-negative-value-of-the-reverted-asset-transaction-{1,number,#0.00}=given assetValue {0,number,#0.00} must be the negative value of the reverted asset transaction {1,number,#0.00} +office.coop-assets.a-reversal-asset-transaction-requires-specifying-a-revertedassettx-uuid=a reversal asset transaction requires specifying a revertedAssetTx uuid +office.coop-assets.transferring-and-adopting-membership-must-be-different-but-both-are-{0}=transferring and adopting membership must be different but both are {0} +office.coop-assets.transaction-would-result-in-a-negative-balance-of-assets=coop assets transaction would result in a negative balance of assets + diff --git a/src/main/resources/i18n/messages_fr.properties b/src/main/resources/i18n/messages_fr.properties new file mode 100644 index 00000000..9ac7fa5f --- /dev/null +++ b/src/main/resources/i18n/messages_fr.properties @@ -0,0 +1,38 @@ +# This file must be in UTF-8 encoding. Check if you see umlauts or garbage: äöüÄÖÜß +# HINT IntelliJ IDEA shows unused keys in gray. + +# test.ponged--in-your-language=this translation is deliberately missing +test.pinged--in-your-language=ponged {0} - en Francais +test.available-in-all-properties-files=Salut {0} - FR! + +# authorization +auth.cas-service-ticket-could-not-be-verified=Le ticket de service CAS n'a pas pu être vérifié +auth.unknown-authorization-ticket=ticket d'autorisation inconnu + +# general validations +general.{0}-{1}-not-found={0} "{1}" non trouvé +general.{0}-{1}-not-found-or-not-accessible={0} "{1}" non trouvé ou non accessible +general.but-is=mais c'est + +# credentials validations +credentials.existing-{0}-does-not-match-given-resource-{1}={0} existant ne correspond pas à la ressource donnée {1} +credentials.access-denied-person-uuid-{0}-not-represented-by-currently-logged-in-person=accès refusé : personUuid "{0}" non représenté par la personne actuellement connectée + +# office.coop-shares +office.coop-shares.for-transactiontype-{0}-sharecount-must-be-positive-but-is-{1}=pour le type de transaction {0}, shareCount doit être positif mais est {1} +office.coop-shares.for-transactiontype-{0}-sharecount-must-be-negative-but-is-{1}=pour le type de transaction {0}, shareCount doit être négatif mais est {1} +office.coop-shares.sharecount-must-not-be-0=shareCount ne doit pas être 0 +office.coop-shares.transaction-would-result-in-a-negative-number-of-shares=la transaction de parts coopératives résulterait en un nombre négatif de parts + +# office.coop-assets +office.coop-assets.either-{0}-or-{1}-must-be-given=soit {0} soit {1} doit être fourni +office.coop-assets.either-{0}-or-{1}-must-be-given-not-both=soit {0} soit {1} doit être fourni, pas les deux +office.coop-assets.either-{0}-or-{1}-must-be-given-for-transactiontype-{2}=soit {0} soit {1} doit être fourni pour le type de transaction {2} +office.coop-assets.neither-{0}-nor-{1}-must-be-given-for-transactiontype-{2}=ni {0} ni {1} ne doit être fourni pour le type de transaction {2} +office.coop-assets.assetvalue-must-not-be-0=assetvalue ne doit pas être 0 +office.coop-assets.for-transactiontype-{0}-assetvalue-must-be-positive-but-is-{1,number,#0.00}=pour le type de transaction {0}, assetValue doit être positif mais est {1,number,#0.00} +office.coop-assets.for-transactiontype-{0}-assetvalue-must-be-negative-but-is-{1,number,#0.00}=pour le type de transaction {0}, assetValue doit être négatif mais est {1,number,#0.00} +office.coop-assets.given-assetvalue-{0,number,#0.00}-must-be-the-negative-value-of-the-reverted-asset-transaction-{1,number,#0.00}=assetValue donné {0,number,#0.00} doit être la valeur négative de la transaction d'actif annulée {1,number,#0.00} +office.coop-assets.a-reversal-asset-transaction-requires-specifying-a-revertedassettx-uuid=une transaction d'actif d'annulation nécessite de spécifier un uuid revertedAssetTx +office.coop-assets.transferring-and-adopting-membership-must-be-different-but-both-are-{0}=l'adhésion transférant et adoptante doit être différente, mais les deux sont {0} +office.coop-assets.transaction-would-result-in-a-negative-balance-of-assets=la transaction d'actifs coopératifs résulterait en un solde négatif d'actifs diff --git a/src/test/java/net/hostsharing/hsadminng/config/CasAuthenticationFilterIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/config/CasAuthenticationFilterIntegrationTest.java index 3e00b7c3..db5b7e00 100644 --- a/src/test/java/net/hostsharing/hsadminng/config/CasAuthenticationFilterIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/config/CasAuthenticationFilterIntegrationTest.java @@ -69,7 +69,7 @@ class CasAuthenticationFilterIntegrationTest { // when final var result = restTemplate.exchange( - "http://localhost:" + this.serverPort + "/api/ping", + "http://localhost:" + this.serverPort + "/api/pong", HttpMethod.GET, new HttpEntity<>(null, headers(entry("Authorization", "ST-valid"))), String.class @@ -77,7 +77,7 @@ class CasAuthenticationFilterIntegrationTest { // then assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(result.getBody()).startsWith("pong " + username); + assertThat(result.getBody()).startsWith("ponged " + username); // HOWTO assert log messages assertThat(capturedOutput.getOut()).containsPattern( LogbackLogPattern.of(LogLevel.DEBUG, RealCasAuthenticator.class, "CAS-user: " + username)); diff --git a/src/test/java/net/hostsharing/hsadminng/config/MessageTranslatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/config/MessageTranslatorUnitTest.java new file mode 100644 index 00000000..b77fde1e --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/config/MessageTranslatorUnitTest.java @@ -0,0 +1,72 @@ +package net.hostsharing.hsadminng.config; + +import lombok.AllArgsConstructor; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.web.context.WebApplicationContext; + +import net.hostsharing.hsadminng.context.Context; + +import java.util.Locale; + +import static org.assertj.core.api.Assertions.assertThat; + +import lombok.val; + +@SpringBootTest(classes = { + MessagesResourceConfig.class, + MessageTranslator.class +}) +@ActiveProfiles("test") +@Tag("generalIntegrationTest") +class MessageTranslatorIntegrationTest { + + @Autowired + private WebApplicationContext webApplicationContext; + + @MockitoBean + private Context contextMock; // avoiding dependency issues + + @AllArgsConstructor + enum TestCases { + ENGLISH_KNOWN(Locale.ENGLISH, "test.ponged-{0}--in-your-language", + "ponged testUser - in English"), + ENGLISH_UNKNOWN(Locale.ENGLISH, "test.ponged-{0}--unknown-key", + "【⍰ponged testUser - unknown key⍰】"), + ENGLISH_US(Locale.of("en", "US"), "test.ponged-{0}--in-your-language", + "ponged testUser - in English"), + ENGLISH_UK(Locale.of("en", "UK"), "test.ponged-{0}--in-your-language", + "ponged testUser - in English"), + GERMAN_KNOWN(Locale.GERMAN, "test.ponged-{0}--in-your-language", + "ponged testUser - auf Deutsch"), + FRENCH_UNKNOWN_BUT_ENGLISH_KNOWN(Locale.FRENCH, "test.ponged-{0}--in-your-language", + "【⍰ponged testUser - in English⍰】"), + FRENCH_UNKNOWN_AND_ENGLISH_UNKNOWN(Locale.FRENCH, "test.ponged-{0}--unknown-key", + "【⍰ponged testUser - unknown key⍰】"), + UNKNOWN_LOCALE_AND_ENGLISH_KNOWN(Locale.TRADITIONAL_CHINESE, + "test.ponged-{0}--in-your-language", "【⍰ponged testUser - in English⍰】"), + UNKNOWN_LOCALE_AND_ENGLISH_UNKNOWN(Locale.TRADITIONAL_CHINESE, "test.ponged-{0}--unknown-key", + "【⍰ponged testUser - unknown key⍰】"); + final Locale locale; + final String messageKey; + final String expectedTranslation; + } + + @ParameterizedTest + @EnumSource(TestCases.class) + void shouldHandleDifferentLocalesAppropriately(final TestCases testCase) { + // given + val messageTranslator = webApplicationContext.getBean(MessageTranslator.class); + + // when + val result = messageTranslator.translateTo(testCase.locale, testCase.messageKey, "testUser"); + + // then + assertThat(result).isEqualTo(testCase.expectedTranslation); + } +} diff --git a/src/test/java/net/hostsharing/hsadminng/config/WebSecurityConfigIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/config/WebSecurityConfigIntegrationTest.java index 0210c00e..bbff1b20 100644 --- a/src/test/java/net/hostsharing/hsadminng/config/WebSecurityConfigIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/config/WebSecurityConfigIntegrationTest.java @@ -67,14 +67,14 @@ class WebSecurityConfigIntegrationTest { // http request final var result = restTemplate.exchange( - "http://localhost:" + this.serverPort + "/api/ping", + "http://localhost:" + this.serverPort + "/api/pong", HttpMethod.GET, httpHeaders(entry("Authorization", "Bearer ST-fake-cas-ticket")), String.class ); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(result.getBody()).startsWith("pong fake-user-name"); + assertThat(result.getBody()).startsWith("ponged fake-user-name"); } @Test @@ -85,18 +85,18 @@ class WebSecurityConfigIntegrationTest { // http request final var result = restTemplate.exchange( - "http://localhost:" + this.serverPort + "/api/ping", + "http://localhost:" + this.serverPort + "/api/pong", HttpMethod.GET, httpHeaders(entry("Authorization", "Bearer TGT-fake-cas-ticket")), String.class ); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(result.getBody()).startsWith("pong fake-user-name"); + assertThat(result.getBody()).startsWith("ponged fake-user-name"); } @Test - void accessToApiWithInvalidTicketGrantingTicketShouldBePermitted() { + void accessToOpenApiWithInvalidTicketGrantingTicketShouldBePermitted() { // given givenCasServiceTicketForTicketGrantingTicket("TGT-fake-cas-ticket", "ST-fake-cas-ticket"); givenCasTicketValidationResponse("ST-fake-cas-ticket", "fake-user-name"); @@ -113,14 +113,14 @@ class WebSecurityConfigIntegrationTest { } @Test - void accessToPingApiWithoutTokenShouldBePermitted() { + void accessToOpenApiWithoutTokenShouldBePermitted() { final var result = this.restTemplate.getForEntity( "http://localhost:" + this.serverPort + "/api/ping", String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); } @Test - void accessToPongApiWithValidTokenShouldBePermitted() { + void accessToProtectedApiWithValidTokenShouldBePermitted() { // given givenCasTicketValidationResponse("ST-fake-cas-ticket", "fake-user-name"); @@ -137,7 +137,7 @@ class WebSecurityConfigIntegrationTest { } @Test - void accessToPongApiWithInvalidTokenShouldBeDenied() { + void accessToProtectedApiWithInvalidTokenShouldBeDenied() { // given givenCasTicketValidationResponse("ST-fake-cas-ticket", "fake-user-name"); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/accounts/HsCredentialsControllerRestTest.java b/src/test/java/net/hostsharing/hsadminng/hs/accounts/HsCredentialsControllerRestTest.java index 0ef3f4a1..c3c9a409 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/accounts/HsCredentialsControllerRestTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/accounts/HsCredentialsControllerRestTest.java @@ -190,7 +190,7 @@ class HsCredentialsControllerRestTest { given(rbacPersonRepo.findByUuid(personUuid)).willReturn(Optional.of( HsOfficePersonRbacEntity.builder().uuid(personUuid).personType(NATURAL_PERSON).build() )); - given(rbacPersonRepo.findPersonsrepresentedByPersonWithUuid(personUuid)).willReturn(List.of( + given(rbacPersonRepo.findPersonsRepresentedByPersonWithUuid(personUuid)).willReturn(List.of( // some persons, but not the one from the login-user itself HsOfficePersonRbacEntity.builder().uuid(UUID.randomUUID()).personType(NATURAL_PERSON).build(), HsOfficePersonRbacEntity.builder().uuid(UUID.randomUUID()).personType(LEGAL_PERSON).build() diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionControllerAcceptanceTest.java index 1c414db8..ce6ef5aa 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionControllerAcceptanceTest.java @@ -4,6 +4,7 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.config.MessageTranslator; +import net.hostsharing.hsadminng.config.MessagesResourceConfig; import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; @@ -36,7 +37,7 @@ import static org.hamcrest.Matchers.startsWith; @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class, - MessageTranslator.class} + MessagesResourceConfig.class, MessageTranslator.class} ) @ActiveProfiles("test") @Transactional diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerRestTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerRestTest.java index 7914dacd..b91f2ae9 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerRestTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerRestTest.java @@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.hs.office.membership; import io.hypersistence.utils.hibernate.type.range.Range; import net.hostsharing.hsadminng.config.MessageTranslator; +import net.hostsharing.hsadminng.config.MessagesResourceConfig; import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionRepository; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRbacEntity; @@ -41,7 +42,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest(HsOfficeMembershipController.class) -@Import({StrictMapper.class, DisableSecurityConfig.class, MessageTranslator.class}) +@Import({ StrictMapper.class, DisableSecurityConfig.class, MessagesResourceConfig.class, MessageTranslator.class}) @ActiveProfiles("test") public class HsOfficeMembershipControllerRestTest { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRbacRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRbacRepositoryIntegrationTest.java index cb03c6e1..4c88315e 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRbacRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRbacRepositoryIntegrationTest.java @@ -259,14 +259,14 @@ class HsOfficePersonRbacRepositoryIntegrationTest extends ContextBasedTestWithCl } @Test - public void findPersonsrepresentedByPersonWithUuid() { + public void findPersonsRepresentedByPersonWithUuid() { // given context("superuser-alex@hostsharing.net"); final var personUuid = personRbacRepo.findPersonByOptionalNameLike("Fouler").getFirst().getUuid(); // when - @SuppressWarnings("unchecked") final List representedPersons = personRbacRepo.findPersonsrepresentedByPersonWithUuid(personUuid); + @SuppressWarnings("unchecked") final List representedPersons = personRbacRepo.findPersonsRepresentedByPersonWithUuid(personUuid); // then assertThat(representedPersons).map(Object::toString).containsExactlyInAnyOrder( diff --git a/src/test/java/net/hostsharing/hsadminng/ping/PingControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/ping/PingControllerAcceptanceTest.java index df7516bf..32670487 100644 --- a/src/test/java/net/hostsharing/hsadminng/ping/PingControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/ping/PingControllerAcceptanceTest.java @@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.config.DisableSecurityConfig; import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; import org.springframework.beans.factory.annotation.Autowired; @@ -40,36 +41,52 @@ class PingControllerAcceptanceTest { @Autowired Context contextMock; - enum PingTranslationTestCase { - EN(Locale.ENGLISH, "pong superuser-alex@hostsharing.net - in English"), - DE(Locale.GERMAN, "pong superuser-alex@hostsharing.net - auf Deutsch"), - FR(Locale.FRENCH, "pong superuser-alex@hostsharing.net - in English [fr translation missing]"); + enum PongTranslationTestCase { + EN(Locale.ENGLISH, "ponged superuser-alex@hostsharing.net - in English"), + DE(Locale.GERMAN, "ponged superuser-alex@hostsharing.net - auf Deutsch"); Locale givenLocale; CharSequence expectedPongTranslation; - PingTranslationTestCase(final Locale givenLocale, final String expectedPongTranslation) { + PongTranslationTestCase(final Locale givenLocale, final String expectedPongTranslation) { this.givenLocale = givenLocale; this.expectedPongTranslation = expectedPongTranslation; } } @ParameterizedTest - @EnumSource(PingTranslationTestCase.class) - void pingRepliesWithTranslatedPongResponse(final PingTranslationTestCase testCase) { + @EnumSource(PongTranslationTestCase.class) + void pongRepliesWithTranslatedPongResponse(final PongTranslationTestCase testCase) { final var responseBody = RestAssured // @formatter:off .given() .header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Accept-Language", testCase.givenLocale) .port(port) .when() - .get("http://localhost/api/ping") + .get("http://localhost/api/pong") .then().log().all().assertThat() .statusCode(200) .contentType("text/plain;charset=UTF-8") .extract().body().asString(); - // @formatter:on + // @formatter:on assertThat(responseBody).isEqualTo(testCase.expectedPongTranslation + "\n"); } + + @Test + void pingRepliesWithTranslatedPongResponse() { + final var responseBody = RestAssured // @formatter:off + .given() + .header("Accept-Language", Locale.GERMAN) + .port(port) + .when() + .get("http://localhost/api/ping") + .then().log().all().assertThat() + .statusCode(200) + .contentType("text/plain;charset=UTF-8") + .extract().body().asString(); + // @formatter:on + + assertThat(responseBody).isEqualTo("pinged - auf Deutsch\n"); + } } diff --git a/src/test/java/net/hostsharing/hsadminng/ping/PingControllerRestTest.java b/src/test/java/net/hostsharing/hsadminng/ping/PingControllerRestTest.java index 3d584838..ac650b00 100644 --- a/src/test/java/net/hostsharing/hsadminng/ping/PingControllerRestTest.java +++ b/src/test/java/net/hostsharing/hsadminng/ping/PingControllerRestTest.java @@ -38,8 +38,8 @@ class PingControllerRestTest { @RequiredArgsConstructor enum I18nTestCases { - EN("en", "pong anonymousUser - in English"), - DE("de", "pong anonymousUser - auf Deutsch"); + EN("en", "pinged - in English"), + DE("de", "pinged - auf Deutsch"); final String language; final String expectedTranslation;