add i18n support for CoopShareTx (#168)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/168 Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
This commit is contained in:
		| @@ -1,4 +1,4 @@ | ||||
| package net.hostsharing.hsadminng.hs.hosting.asset; | ||||
| package net.hostsharing.hsadminng.hs.office.coopassets; | ||||
| 
 | ||||
| import net.hostsharing.hsadminng.config.MessageTranslator; | ||||
| import net.hostsharing.hsadminng.config.RetroactiveTranslator; | ||||
| @@ -8,7 +8,7 @@ import org.springframework.stereotype.Service; | ||||
| 
 | ||||
| // HOWTO translate messages which got created without i18n support, in this case in a PostgreSQL constraint trigger | ||||
| @Service | ||||
| public class HsHostingAssetTranslations implements RetroactiveTranslator { | ||||
| public class HsCoopAssetTranslations implements RetroactiveTranslator { | ||||
| 
 | ||||
|     public static final String ERROR_400_PREFIX = "ERROR: [400] "; | ||||
| 
 | ||||
| @@ -0,0 +1,26 @@ | ||||
| package net.hostsharing.hsadminng.hs.office.coopshares; | ||||
|  | ||||
| import net.hostsharing.hsadminng.config.MessageTranslator; | ||||
| import net.hostsharing.hsadminng.config.RetroactiveTranslator; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| // HOWTO translate messages which got created without i18n support, in this case in a PostgreSQL constraint trigger | ||||
| @Service | ||||
| public class HsCoopShareTranslations implements RetroactiveTranslator { | ||||
|  | ||||
|     public static final String ERROR_400_PREFIX = "ERROR: [400] "; | ||||
|  | ||||
|     @Autowired | ||||
|     private MessageTranslator messageTranslator; | ||||
|  | ||||
|     @Override | ||||
|     public boolean canTranslate(final String message) { | ||||
|         return message.equals("ERROR: [400] coop shares transaction would result in a negative number of shares"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String translate(final String message) { | ||||
|         return ERROR_400_PREFIX + messageTranslator.translate(message.substring(ERROR_400_PREFIX.length())); | ||||
|     } | ||||
| } | ||||
| @@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.hs.office.coopshares; | ||||
|  | ||||
| import io.micrometer.core.annotation.Timed; | ||||
| import io.swagger.v3.oas.annotations.security.SecurityRequirement; | ||||
| import net.hostsharing.hsadminng.config.MessageTranslator; | ||||
| import net.hostsharing.hsadminng.context.Context; | ||||
| import net.hostsharing.hsadminng.errors.MultiValidationException; | ||||
| import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopSharesApi; | ||||
| @@ -37,6 +38,9 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar | ||||
|     @Autowired | ||||
|     private StrictMapper mapper; | ||||
|  | ||||
|     @Autowired | ||||
|     private MessageTranslator messageTranslator; | ||||
|  | ||||
|     @Autowired | ||||
|     private HsOfficeCoopSharesTransactionRepository coopSharesTransactionRepo; | ||||
|  | ||||
| @@ -118,32 +122,31 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar | ||||
|         MultiValidationException.throwIfNotEmpty(violations); | ||||
|     } | ||||
|  | ||||
|     private static void validateSubscriptionTransaction( | ||||
|     private void validateSubscriptionTransaction( | ||||
|             final HsOfficeCoopSharesTransactionInsertResource requestBody, | ||||
|             final ArrayList<String> violations) { | ||||
|         if (requestBody.getTransactionType() == SUBSCRIPTION | ||||
|                 && requestBody.getShareCount() < 0) { | ||||
|             violations.add("for %s, shareCount must be positive but is \"%d\"".formatted( | ||||
|             violations.add(messageTranslator.translate("for transactionType={0}, shareCount must be positive but is {1}", | ||||
|                     requestBody.getTransactionType(), requestBody.getShareCount())); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static void validateCancellationTransaction( | ||||
|     private void validateCancellationTransaction( | ||||
|             final HsOfficeCoopSharesTransactionInsertResource requestBody, | ||||
|             final ArrayList<String> violations) { | ||||
|         if (requestBody.getTransactionType() == CANCELLATION | ||||
|                 && requestBody.getShareCount() > 0) { | ||||
|             violations.add("for %s, shareCount must be negative but is \"%d\"".formatted( | ||||
|             violations.add(messageTranslator.translate("for transactionType={0}, shareCount must be negative but is {1}", | ||||
|                     requestBody.getTransactionType(), requestBody.getShareCount())); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static void validateshareCount( | ||||
|     private void validateshareCount( | ||||
|             final HsOfficeCoopSharesTransactionInsertResource requestBody, | ||||
|             final ArrayList<String> violations) { | ||||
|         if (requestBody.getShareCount() == 0) { | ||||
|             violations.add("shareCount must not be 0 but is \"%d\"".formatted( | ||||
|                     requestBody.getShareCount())); | ||||
|             violations.add(messageTranslator.translate("shareCount must not be 0")); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -12,6 +12,12 @@ unknown\ authorization\ ticket=unbekanntes Autorisierungs-Ticket | ||||
| {0}\ "{1}"\ not\ found\ or\ not\ accessible={0} "{1}" nicht gefunden oder nicht zugänglich | ||||
| but\ is=ist aber | ||||
|  | ||||
| # 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-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 | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.hs.office.coopshares; | ||||
| import io.restassured.RestAssured; | ||||
| import io.restassured.http.ContentType; | ||||
| import net.hostsharing.hsadminng.HsadminNgApplication; | ||||
| import net.hostsharing.hsadminng.config.MessageTranslator; | ||||
| import net.hostsharing.hsadminng.context.Context; | ||||
| import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository; | ||||
| import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; | ||||
| @@ -32,7 +33,7 @@ import static org.hamcrest.Matchers.hasSize; | ||||
| import static org.hamcrest.Matchers.startsWith; | ||||
|  | ||||
| @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, | ||||
|         classes = {HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class}) | ||||
|         classes = {HsadminNgApplication.class, DisableSecurityConfig.class, MessageTranslator.class, JpaAttempt.class}) | ||||
| @ActiveProfiles("test") | ||||
| @Transactional | ||||
| @Tag("officeIntegrationTest") | ||||
| @@ -180,7 +181,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased | ||||
|     } | ||||
|  | ||||
|     @Nested | ||||
|     class AddCoopSharesTransaction { | ||||
|     class PostNewCoopSharesTransaction { | ||||
|  | ||||
|         @Test | ||||
|         void globalAdmin_canAddCoopSharesTransaction() { | ||||
| @@ -191,6 +192,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased | ||||
|             final var location = RestAssured // @formatter:off | ||||
|                 .given() | ||||
|                     .header("Authorization", "Bearer superuser-alex@hostsharing.net") | ||||
|                     .header("Accept-Language", "de") | ||||
|                     .contentType(ContentType.JSON).body(""" | ||||
|                        { | ||||
|                            "membership.uuid": "%s", | ||||
| @@ -306,6 +308,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased | ||||
|             RestAssured // @formatter:off | ||||
|                 .given() | ||||
|                     .header("Authorization", "Bearer superuser-alex@hostsharing.net") | ||||
|                     .header("Accept-Language", "de") | ||||
|                     .contentType(ContentType.JSON) | ||||
|                     .body(""" | ||||
|                         { | ||||
| @@ -329,7 +332,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased | ||||
|                         { | ||||
|                             "statusCode": 400, | ||||
|                             "statusPhrase": "Bad Request", | ||||
|                             "message": "ERROR: [400] coop shares transaction would result in a negative number of shares" | ||||
|                             "message": "ERROR: [400] Geschäftsanteile-Transaktion würde zu negativen Geschäftsanteilen führen" | ||||
|                         } | ||||
|                         """));  // @formatter:on | ||||
|         } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package net.hostsharing.hsadminng.hs.office.coopshares; | ||||
|  | ||||
| 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.mapper.StrictMapper; | ||||
| @@ -27,7 +28,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. | ||||
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||||
|  | ||||
| @WebMvcTest(HsOfficeCoopSharesTransactionController.class) | ||||
| @Import({DisableSecurityConfig.class, MessageTranslator.class}) | ||||
| @Import({DisableSecurityConfig.class, | ||||
|          MessagesResourceConfig.class, | ||||
|          MessageTranslator.class}) | ||||
| @ActiveProfiles("test") | ||||
| class HsOfficeCoopSharesTransactionControllerRestTest { | ||||
|  | ||||
| @@ -61,45 +64,45 @@ class HsOfficeCoopSharesTransactionControllerRestTest { | ||||
|     enum BadRequestTestCases { | ||||
|         MEMBERSHIP_UUID_MISSING( | ||||
|                 requestBody -> requestBody.without("membership.uuid"), | ||||
|                 "membershipUuid must not be null"), | ||||
|                 "membershipUuid darf nicht null sein ist aber null"), | ||||
|  | ||||
|         TRANSACTION_TYPE_MISSING( | ||||
|                 requestBody -> requestBody.without("transactionType"), | ||||
|                 "transactionType must not be null"), | ||||
|                 "transactionType darf nicht null sein ist aber null"), | ||||
|  | ||||
|         VALUE_DATE_MISSING( | ||||
|                 requestBody -> requestBody.without("valueDate"), | ||||
|                 "valueDate must not be null"), | ||||
|                 "valueDate darf nicht null sein ist aber null"), | ||||
|  | ||||
|         SHARES_COUNT_FOR_SUBSCRIPTION_MUST_BE_POSITIVE( | ||||
|                 requestBody -> requestBody | ||||
|                         .with("transactionType", "SUBSCRIPTION") | ||||
|                         .with("shareCount", -1), | ||||
|                 "for SUBSCRIPTION, shareCount must be positive but is \"-1\""), | ||||
|                 "für transactionType=SUBSCRIPTION, muss shareCount positiv sein, ist aber -1"), | ||||
|  | ||||
|         SHARES_COUNT_FOR_CANCELLATION_MUST_BE_NEGATIVE( | ||||
|                 requestBody -> requestBody | ||||
|                         .with("transactionType", "CANCELLATION") | ||||
|                         .with("shareCount", 1), | ||||
|                 "for CANCELLATION, shareCount must be negative but is \"1\""), | ||||
|                 "für transactionType=CANCELLATION, muss shareCount negativ sein, ist aber 1"), | ||||
|  | ||||
|         SHARES_COUNT_MUST_NOT_BE_NULL( | ||||
|                 requestBody -> requestBody | ||||
|                         .with("transactionType", "REVERSAL") | ||||
|                         .with("shareCount", 0), | ||||
|                 "shareCount must not be 0 but is \"0\""), | ||||
|                 "shareCount darf nicht 0 sein"), | ||||
|  | ||||
|         REFERENCE_MISSING( | ||||
|                 requestBody -> requestBody.without("reference"), | ||||
|                 "reference must not be null"), | ||||
|                 "reference darf nicht null sein ist aber null"), | ||||
|  | ||||
|         REFERENCE_TOO_SHORT( | ||||
|                 requestBody -> requestBody.with("reference", "12345"), | ||||
|                 "reference size must be between 6 and 48 but is \"12345\""), | ||||
|                 "reference Größe muss zwischen 6 und 48 sein ist aber \"12345\""), | ||||
|  | ||||
|         REFERENCE_TOO_LONG( | ||||
|                 requestBody -> requestBody.with("reference", "0123456789012345678901234567890123456789012345678"), | ||||
|                 "reference size must be between 6 and 48 but is \"0123456789012345678901234567890123456789012345678\""); | ||||
|                 "reference Größe muss zwischen 6 und 48 sein ist aber \"0123456789012345678901234567890123456789012345678\""); | ||||
|  | ||||
|         private final Function<JsonBuilder, JsonBuilder> givenBodyTransformation; | ||||
|         private final String expectedErrorMessage; | ||||
| @@ -124,6 +127,7 @@ class HsOfficeCoopSharesTransactionControllerRestTest { | ||||
|         mockMvc.perform(MockMvcRequestBuilders | ||||
|                         .post("/api/hs/office/coopsharestransactions") | ||||
|                         .header("Authorization", "Bearer superuser-alex@hostsharing.net") | ||||
|                         .header("Accept-Language", "de") | ||||
|                         .contentType(MediaType.APPLICATION_JSON) | ||||
|                         .content(testCase.givenRequestBody()) | ||||
|                         .accept(MediaType.APPLICATION_JSON)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user