From e5ec8678194a2ef1afd843c97c63dc88e3cd4f21 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Tue, 25 Oct 2022 10:32:57 +0200 Subject: [PATCH] get endpoints for coopassets+coopshares --- ...OfficeCoopAssetsTransactionController.java | 17 + ...OfficeCoopSharesTransactionController.java | 16 + .../hs-office-coopassets-with-uuid.yaml | 27 ++ .../hs-office-coopshares-with-uuid.yaml | 27 ++ .../api-definition/hs-office/hs-office.yaml | 7 +- ...tsTransactionControllerAcceptanceTest.java | 48 +++ ...esTransactionControllerAcceptanceTest.java | 369 +++++++++--------- 7 files changed, 316 insertions(+), 195 deletions(-) create mode 100644 src/main/resources/api-definition/hs-office/hs-office-coopassets-with-uuid.yaml create mode 100644 src/main/resources/api-definition/hs-office/hs-office-coopshares-with-uuid.yaml 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 dfb82c10..c794e1fd 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 @@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopAssetsApi; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopAssetsTransactionInsertResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopAssetsTransactionResource; +import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopSharesTransactionResource; import net.hostsharing.hsadminng.mapper.Mapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; @@ -78,6 +79,22 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse return ResponseEntity.created(uri).body(mapped); } + @Override + @Transactional(readOnly = true) + + public ResponseEntity getCoopAssetTransactionByUuid( + final String currentUser, final String assumedRoles, final UUID assetTransactionUuid) { + + context.define(currentUser, assumedRoles); + + final var result = coopAssetsTransactionRepo.findByUuid(assetTransactionUuid); + if (result.isEmpty()) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(mapper.map(result.get(), HsOfficeCoopAssetsTransactionResource.class)); + + } + private void validate(final HsOfficeCoopAssetsTransactionInsertResource requestBody) { final var violations = new ArrayList(); validateDebitTransaction(requestBody, violations); 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 78716866..783557f5 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 @@ -1,5 +1,6 @@ package net.hostsharing.hsadminng.hs.office.coopshares; +import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeContactResource; import net.hostsharing.hsadminng.mapper.Mapper; import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopSharesApi; @@ -79,6 +80,21 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar return ResponseEntity.created(uri).body(mapped); } + @Override + @Transactional(readOnly = true) + public ResponseEntity getCoopShareTransactionByUuid( + final String currentUser, final String assumedRoles, final UUID shareTransactionUuid) { + + context.define(currentUser, assumedRoles); + + final var result = coopSharesTransactionRepo.findByUuid(shareTransactionUuid); + if (result.isEmpty()) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(mapper.map(result.get(), HsOfficeCoopSharesTransactionResource.class)); + + } + private void validate(final HsOfficeCoopSharesTransactionInsertResource requestBody) { final var violations = new ArrayList(); validateSubscriptionTransaction(requestBody, violations); diff --git a/src/main/resources/api-definition/hs-office/hs-office-coopassets-with-uuid.yaml b/src/main/resources/api-definition/hs-office/hs-office-coopassets-with-uuid.yaml new file mode 100644 index 00000000..6dae49c0 --- /dev/null +++ b/src/main/resources/api-definition/hs-office/hs-office-coopassets-with-uuid.yaml @@ -0,0 +1,27 @@ +get: + tags: + - hs-office-coopAssets + description: 'Fetch a single asset transaction by its uuid, if visible for the current subject.' + operationId: getCoopAssetTransactionByUuid + parameters: + - $ref: './auth.yaml#/components/parameters/currentUser' + - $ref: './auth.yaml#/components/parameters/assumedRoles' + - name: assetTransactionUUID + in: path + required: true + schema: + type: string + format: uuid + description: UUID of the asset transaction to fetch. + responses: + "200": + description: OK + content: + 'application/json': + schema: + $ref: './hs-office-coopassets-schemas.yaml#/components/schemas/HsOfficeCoopAssetsTransaction' + + "401": + $ref: './error-responses.yaml#/components/responses/Unauthorized' + "403": + $ref: './error-responses.yaml#/components/responses/Forbidden' diff --git a/src/main/resources/api-definition/hs-office/hs-office-coopshares-with-uuid.yaml b/src/main/resources/api-definition/hs-office/hs-office-coopshares-with-uuid.yaml new file mode 100644 index 00000000..8d40ace8 --- /dev/null +++ b/src/main/resources/api-definition/hs-office/hs-office-coopshares-with-uuid.yaml @@ -0,0 +1,27 @@ +get: + tags: + - hs-office-coopShares + description: 'Fetch a single share transaction by its uuid, if visible for the current subject.' + operationId: getCoopShareTransactionByUuid + parameters: + - $ref: './auth.yaml#/components/parameters/currentUser' + - $ref: './auth.yaml#/components/parameters/assumedRoles' + - name: shareTransactionUUID + in: path + required: true + schema: + type: string + format: uuid + description: UUID of the share transaction to fetch. + responses: + "200": + description: OK + content: + 'application/json': + schema: + $ref: './hs-office-coopshares-schemas.yaml#/components/schemas/HsOfficeCoopSharesTransaction' + + "401": + $ref: './error-responses.yaml#/components/responses/Unauthorized' + "403": + $ref: './error-responses.yaml#/components/responses/Forbidden' diff --git a/src/main/resources/api-definition/hs-office/hs-office.yaml b/src/main/resources/api-definition/hs-office/hs-office.yaml index 15014baa..f3110867 100644 --- a/src/main/resources/api-definition/hs-office/hs-office.yaml +++ b/src/main/resources/api-definition/hs-office/hs-office.yaml @@ -85,8 +85,13 @@ paths: /api/hs/office/coopsharestransactions: $ref: "./hs-office-coopshares.yaml" + /api/hs/office/coopsharestransactions/{shareTransactionUUID}: + $ref: "./hs-office-coopshares-with-uuid.yaml" - # Coop Assets Transaction + # Coop Assets Transaction /api/hs/office/coopassetstransactions: $ref: "./hs-office-coopassets.yaml" + + /api/hs/office/coopassetstransactions/{assetTransactionUUID}: + $ref: "./hs-office-coopassets-with-uuid.yaml" 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 93b0eb7c..6b768d3b 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 @@ -5,6 +5,7 @@ import io.restassured.http.ContentType; import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionRepository; +import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionRepository; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository; import net.hostsharing.test.Accepts; import net.hostsharing.test.JpaAttempt; @@ -18,6 +19,7 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityManager; +import java.time.LocalDate; import java.util.UUID; import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid; @@ -39,6 +41,9 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest { @Autowired Context context; + @Autowired + HsOfficeCoopAssetsTransactionRepository coopAssetsTransactionRepo; + @Autowired HsOfficeMembershipRepository membershipRepo; @@ -228,6 +233,49 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest { } } + @Nested + @Accepts({"CoopAssetTransaction:R(Read)"}) + class GetCoopAssetTransaction { + + @Test + void globalAdmin_withoutAssumedRole_canGetArbitraryCoopAssetTransaction() { + context.define("superuser-alex@hostsharing.net"); + final var givenCoopAssetTransactionUuid = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid(); + + RestAssured // @formatter:off + .given().header("current-user", "superuser-alex@hostsharing.net").port(port).when().get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid).then().log().body().assertThat().statusCode(200).contentType("application/json").body("", lenientlyEquals(""" + { + "transactionType": "DEPOSIT" + } + """)); // @formatter:on + } + + @Test + @Accepts({"CoopAssetTransaction:X(Access Control)"}) + void normalUser_canNotGetUnrelatedCoopAssetTransaction() { + context.define("superuser-alex@hostsharing.net"); + final var givenCoopAssetTransactionUuid = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid(); + + RestAssured // @formatter:off + .given().header("current-user", "selfregistered-user-drew@hostsharing.org").port(port).when().get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid).then().log().body().assertThat().statusCode(404); // @formatter:on + } + + @Test + @Accepts({"CoopAssetTransaction:X(Access Control)"}) + void contactAdminUser_canGetRelatedCoopAssetTransaction() { + context.define("superuser-alex@hostsharing.net"); + final var givenCoopAssetTransactionUuid = coopAssetsTransactionRepo.findCoopAssetsTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid(); + + RestAssured // @formatter:off + .given().header("current-user", "contact-admin@firstcontact.example.com").port(port).when().get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid).then().log().body().assertThat().statusCode(200).contentType("application/json").body("", lenientlyEquals(""" + { + "transactionType": "DEPOSIT", + "assetValue": 320 + } + """)); // @formatter:on + } + } + @BeforeEach @AfterEach void cleanup() { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerAcceptanceTest.java index 95d05007..aa7f24bb 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionControllerAcceptanceTest.java @@ -17,6 +17,7 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityManager; +import java.time.LocalDate; import java.util.UUID; import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid; @@ -25,213 +26,24 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.startsWith; -@SpringBootTest( - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = { HsadminNgApplication.class, JpaAttempt.class } -) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {HsadminNgApplication.class, JpaAttempt.class}) @Transactional class HsOfficeCoopSharesTransactionControllerAcceptanceTest { - @LocalServerPort - private Integer port; - @Autowired Context context; - @Autowired Context contextMock; - @Autowired HsOfficeCoopSharesTransactionRepository coopSharesTransactionRepo; - @Autowired HsOfficeMembershipRepository membershipRepo; - @Autowired JpaAttempt jpaAttempt; - @Autowired EntityManager em; - - @Nested - @Accepts({ "CoopSharesTransaction:F(Find)" }) - class ListCoopSharesTransactions { - - @Test - void globalAdmin_canViewAllCoopSharesTransactions() { - - RestAssured // @formatter:off - .given() - .header("current-user", "superuser-alex@hostsharing.net") - .port(port) - .when() - .get("http://localhost/api/hs/office/coopsharestransactions") - .then().log().all().assertThat() - .statusCode(200) - .contentType("application/json") - .body("", hasSize(9)); // @formatter:on - } - - @Test - void globalAdmin_canFindCoopSharesTransactionsByMemberNumber() { - - context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002) - .get(0); - - RestAssured // @formatter:off - .given() - .header("current-user", "superuser-alex@hostsharing.net") - .port(port) - .when() - .get("http://localhost/api/hs/office/coopsharestransactions?membershipUuid="+givenMembership.getUuid()) - .then().log().all().assertThat() - .statusCode(200) - .contentType("application/json") - .body("", lenientlyEquals(""" - [ - { - "transactionType": "SUBSCRIPTION", - "shareCount": 4, - "valueDate": "2010-03-15", - "reference": "ref 10002-1", - "comment": "initial subscription" - }, - { - "transactionType": "CANCELLATION", - "shareCount": -2, - "valueDate": "2021-09-01", - "reference": "ref 10002-2", - "comment": "cancelling some" - }, - { - "transactionType": "ADJUSTMENT", - "shareCount": 2, - "valueDate": "2022-10-20", - "reference": "ref 10002-3", - "comment": "some adjustment" - } - ] - """)); // @formatter:on - } - - @Test - void globalAdmin_canFindCoopSharesTransactionsByMemberNumberAndDateRange() { - - context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002) - .get(0); - - RestAssured // @formatter:off - .given() - .header("current-user", "superuser-alex@hostsharing.net") - .port(port) - .when() - .get("http://localhost/api/hs/office/coopsharestransactions?membershipUuid=" - + givenMembership.getUuid() + "&fromValueDate=2020-01-01&toValueDate=2021-12-31") - .then().log().all().assertThat() - .statusCode(200) - .contentType("application/json") - .body("", lenientlyEquals(""" - [ - { - "transactionType": "CANCELLATION", - "shareCount": -2, - "valueDate": "2021-09-01", - "reference": "ref 10002-2", - "comment": "cancelling some" - } - ] - """)); // @formatter:on - } - } - - @Nested - @Accepts({ "CoopSharesTransaction:C(Create)" }) - class AddCoopSharesTransaction { - - @Test - void globalAdmin_canAddCoopSharesTransaction() { - - context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001) - .get(0); - - final var location = RestAssured // @formatter:off - .given() - .header("current-user", "superuser-alex@hostsharing.net") - .contentType(ContentType.JSON) - .body(""" - { - "membershipUuid": "%s", - "transactionType": "SUBSCRIPTION", - "shareCount": 8, - "valueDate": "2022-10-13", - "reference": "temp ref A", - "comment": "just some test coop shares transaction" - } - """.formatted(givenMembership.getUuid())) - .port(port) - .when() - .post("http://localhost/api/hs/office/coopsharestransactions") - .then().log().all().assertThat() - .statusCode(201) - .contentType(ContentType.JSON) - .body("uuid", isUuidValid()) - .body("", lenientlyEquals(""" - { - "transactionType": "SUBSCRIPTION", - "shareCount": 8, - "valueDate": "2022-10-13", - "reference": "temp ref A", - "comment": "just some test coop shares transaction" - } - """)) - .header("Location", startsWith("http://localhost")) - .extract().header("Location"); // @formatter:on - - // finally, the new coopSharesTransaction can be accessed under the generated UUID - final var newUserUuid = UUID.fromString( - location.substring(location.lastIndexOf('/') + 1)); - assertThat(newUserUuid).isNotNull(); - } - - @Test - void globalAdmin_canNotCancelMoreSharesThanCurrentlySubscribed() { - - context.define("superuser-alex@hostsharing.net"); - final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001) - .get(0); - - final var location = RestAssured // @formatter:off - .given() - .header("current-user", "superuser-alex@hostsharing.net") - .contentType(ContentType.JSON) - .body(""" - { - "membershipUuid": "%s", - "transactionType": "CANCELLATION", - "shareCount": -80, - "valueDate": "2022-10-13", - "reference": "temp ref X", - "comment": "just some test coop shares transaction" - } - """.formatted(givenMembership.getUuid())) - .port(port) - .when() - .post("http://localhost/api/hs/office/coopsharestransactions") - .then().log().all().assertThat() - .statusCode(400) - .contentType(ContentType.JSON) - .body("", lenientlyEquals(""" - { - "status": 400, - "error": "Bad Request", - "message": "ERROR: [400] coop shares transaction would result in a negative number of shares" - } - """)); // @formatter:on - } - } + @LocalServerPort + private Integer port; @BeforeEach @AfterEach @@ -240,8 +52,177 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest { context.define("superuser-alex@hostsharing.net", null); // HsOfficeCoopSharesTransactionEntity respectively hs_office_coopsharestransaction_rv // cannot be deleted at all, but the underlying table record can be deleted. - em.createNativeQuery("delete from hs_office_coopsharestransaction where reference like 'temp %'") - .executeUpdate(); + em.createNativeQuery("delete from hs_office_coopsharestransaction where reference like 'temp %'").executeUpdate(); }).assertSuccessful(); } + + @Nested + @Accepts({"CoopSharesTransaction:F(Find)"}) + class ListCoopSharesTransactions { + + @Test + void globalAdmin_canViewAllCoopSharesTransactions() { + + RestAssured // @formatter:off + .given().header("current-user", "superuser-alex@hostsharing.net").port(port).when().get("http://localhost/api/hs/office/coopsharestransactions").then().log().all().assertThat().statusCode(200).contentType("application/json").body("", hasSize(9)); // @formatter:on + } + + @Test + void globalAdmin_canFindCoopSharesTransactionsByMemberNumber() { + + context.define("superuser-alex@hostsharing.net"); + final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002).get(0); + + RestAssured // @formatter:off + .given().header("current-user", "superuser-alex@hostsharing.net").port(port).when().get("http://localhost/api/hs/office/coopsharestransactions?membershipUuid=" + givenMembership.getUuid()).then().log().all().assertThat().statusCode(200).contentType("application/json").body("", lenientlyEquals(""" + [ + { + "transactionType": "SUBSCRIPTION", + "shareCount": 4, + "valueDate": "2010-03-15", + "reference": "ref 10002-1", + "comment": "initial subscription" + }, + { + "transactionType": "CANCELLATION", + "shareCount": -2, + "valueDate": "2021-09-01", + "reference": "ref 10002-2", + "comment": "cancelling some" + }, + { + "transactionType": "ADJUSTMENT", + "shareCount": 2, + "valueDate": "2022-10-20", + "reference": "ref 10002-3", + "comment": "some adjustment" + } + ] + """)); // @formatter:on + } + + @Test + void globalAdmin_canFindCoopSharesTransactionsByMemberNumberAndDateRange() { + + context.define("superuser-alex@hostsharing.net"); + final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10002).get(0); + + RestAssured // @formatter:off + .given().header("current-user", "superuser-alex@hostsharing.net").port(port).when().get("http://localhost/api/hs/office/coopsharestransactions?membershipUuid=" + givenMembership.getUuid() + "&fromValueDate=2020-01-01&toValueDate=2021-12-31").then().log().all().assertThat().statusCode(200).contentType("application/json").body("", lenientlyEquals(""" + [ + { + "transactionType": "CANCELLATION", + "shareCount": -2, + "valueDate": "2021-09-01", + "reference": "ref 10002-2", + "comment": "cancelling some" + } + ] + """)); // @formatter:on + } + } + + @Nested + @Accepts({"CoopSharesTransaction:C(Create)"}) + class AddCoopSharesTransaction { + + @Test + void globalAdmin_canAddCoopSharesTransaction() { + + context.define("superuser-alex@hostsharing.net"); + final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001).get(0); + + final var location = RestAssured // @formatter:off + .given().header("current-user", "superuser-alex@hostsharing.net").contentType(ContentType.JSON).body(""" + { + "membershipUuid": "%s", + "transactionType": "SUBSCRIPTION", + "shareCount": 8, + "valueDate": "2022-10-13", + "reference": "temp ref A", + "comment": "just some test coop shares transaction" + } + """.formatted(givenMembership.getUuid())).port(port).when().post("http://localhost/api/hs/office/coopsharestransactions").then().log().all().assertThat().statusCode(201).contentType(ContentType.JSON).body("uuid", isUuidValid()).body("", lenientlyEquals(""" + { + "transactionType": "SUBSCRIPTION", + "shareCount": 8, + "valueDate": "2022-10-13", + "reference": "temp ref A", + "comment": "just some test coop shares transaction" + } + """)).header("Location", startsWith("http://localhost")).extract().header("Location"); // @formatter:on + + // finally, the new coopSharesTransaction can be accessed under the generated UUID + final var newUserUuid = UUID.fromString(location.substring(location.lastIndexOf('/') + 1)); + assertThat(newUserUuid).isNotNull(); + } + + @Test + void globalAdmin_canNotCancelMoreSharesThanCurrentlySubscribed() { + + context.define("superuser-alex@hostsharing.net"); + final var givenMembership = membershipRepo.findMembershipsByOptionalPartnerUuidAndOptionalMemberNumber(null, 10001).get(0); + + final var location = RestAssured // @formatter:off + .given().header("current-user", "superuser-alex@hostsharing.net").contentType(ContentType.JSON).body(""" + { + "membershipUuid": "%s", + "transactionType": "CANCELLATION", + "shareCount": -80, + "valueDate": "2022-10-13", + "reference": "temp ref X", + "comment": "just some test coop shares transaction" + } + """.formatted(givenMembership.getUuid())).port(port).when().post("http://localhost/api/hs/office/coopsharestransactions").then().log().all().assertThat().statusCode(400).contentType(ContentType.JSON).body("", lenientlyEquals(""" + { + "status": 400, + "error": "Bad Request", + "message": "ERROR: [400] coop shares transaction would result in a negative number of shares" + } + """)); // @formatter:on + } + } + + @Nested + @Accepts({"CoopShareTransaction:R(Read)"}) + class GetCoopShareTransaction { + + @Test + void globalAdmin_withoutAssumedRole_canGetArbitraryCoopShareTransaction() { + context.define("superuser-alex@hostsharing.net"); + final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid(); + + RestAssured // @formatter:off + .given().header("current-user", "superuser-alex@hostsharing.net").port(port).when().get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid).then().log().body().assertThat().statusCode(200).contentType("application/json").body("", lenientlyEquals(""" + { + "transactionType": "SUBSCRIPTION" + } + """)); // @formatter:on + } + + @Test + @Accepts({"CoopShareTransaction:X(Access Control)"}) + void normalUser_canNotGetUnrelatedCoopShareTransaction() { + context.define("superuser-alex@hostsharing.net"); + final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid(); + + RestAssured // @formatter:off + .given().header("current-user", "selfregistered-user-drew@hostsharing.org").port(port).when().get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid).then().log().body().assertThat().statusCode(404); // @formatter:on + } + + @Test + @Accepts({"CoopShareTransaction:X(Access Control)"}) + void contactAdminUser_canGetRelatedCoopShareTransaction() { + context.define("superuser-alex@hostsharing.net"); + final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid(); + + RestAssured // @formatter:off + .given().header("current-user", "contact-admin@firstcontact.example.com").port(port).when().get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid).then().log().body().assertThat().statusCode(200).contentType("application/json").body("", lenientlyEquals(""" + { + "transactionType": "SUBSCRIPTION", + "shareCount": 4 + } + """)); // @formatter:on + } + } }