application-event for booking-item-created with domain-setup-example #110
@ -29,12 +29,17 @@ public class HsBookingItemCreatedListener implements ApplicationListener<Booking
|
|||||||
case DOMAIN_SETUP -> createDomainSetupHostingAsset(newBookingItemRealEntity);
|
case DOMAIN_SETUP -> createDomainSetupHostingAsset(newBookingItemRealEntity);
|
||||||
};
|
};
|
||||||
if (newHostingAsset != null) {
|
if (newHostingAsset != null) {
|
||||||
new HostingAssetEntitySaveProcessor(emw, newHostingAsset)
|
try {
|
||||||
.preprocessEntity()
|
new HostingAssetEntitySaveProcessor(emw, newHostingAsset)
|
||||||
.validateEntity()
|
.preprocessEntity()
|
||||||
.prepareForSave()
|
.validateEntity()
|
||||||
.save()
|
.prepareForSave()
|
||||||
.validateContext();
|
.save()
|
||||||
|
.validateContext();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
// TODO.impl: store status in a separate field, maybe enum+message
|
||||||
|
newBookingItemRealEntity.getResources().put("status", e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,11 @@ import io.hypersistence.utils.hibernate.type.range.Range;
|
|||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||||
|
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorRepository;
|
||||||
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealRepository;
|
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealRepository;
|
||||||
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAsset;
|
||||||
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealRepository;
|
||||||
import net.hostsharing.hsadminng.hs.hosting.asset.validators.Dns;
|
import net.hostsharing.hsadminng.hs.hosting.asset.validators.Dns;
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
|
||||||
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
|
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
|
||||||
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
||||||
import org.junit.jupiter.api.ClassOrderer;
|
import org.junit.jupiter.api.ClassOrderer;
|
||||||
@ -51,7 +53,10 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
HsBookingProjectRealRepository realProjectRepo;
|
HsBookingProjectRealRepository realProjectRepo;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
HsOfficeDebitorRepository debitorRepo;
|
HsBookingDebitorRepository debitorRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HsHostingAssetRealRepository realHostingAssetRepo;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
JpaAttempt jpaAttempt;
|
JpaAttempt jpaAttempt;
|
||||||
@ -65,7 +70,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
|
|
||||||
// given
|
// given
|
||||||
context("superuser-alex@hostsharing.net");
|
context("superuser-alex@hostsharing.net");
|
||||||
final var givenProject = debitorRepo.findDebitorByDebitorNumber(1000111).stream()
|
final var givenProject = debitorRepo.findByDebitorNumber(1000111).stream()
|
||||||
.map(d -> realProjectRepo.findAllByDebitorUuid(d.getUuid()))
|
.map(d -> realProjectRepo.findAllByDebitorUuid(d.getUuid()))
|
||||||
.flatMap(List::stream)
|
.flatMap(List::stream)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@ -133,7 +138,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
void globalAdmin_canAddBookingItem() {
|
void globalAdmin_canAddBookingItem() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenProject = debitorRepo.findDebitorByDebitorNumber(1000111).stream()
|
final var givenProject = debitorRepo.findByDebitorNumber(1000111).stream()
|
||||||
.map(d -> realProjectRepo.findAllByDebitorUuid(d.getUuid()))
|
.map(d -> realProjectRepo.findAllByDebitorUuid(d.getUuid()))
|
||||||
.flatMap(List::stream)
|
.flatMap(List::stream)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@ -183,10 +188,10 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void globalAdmin_canAddBookingItemWithHostingAsset() {
|
void projectAgent_canAddBookingItemWithHostingAsset() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net", "hs_booking.project#D-1000111-D-1000111defaultproject:AGENT");
|
||||||
final var givenProject = debitorRepo.findDebitorByDebitorNumber(1000111).stream()
|
final var givenProject = debitorRepo.findByDebitorNumber(1000111).stream()
|
||||||
.map(d -> realProjectRepo.findAllByDebitorUuid(d.getUuid()))
|
.map(d -> realProjectRepo.findAllByDebitorUuid(d.getUuid()))
|
||||||
.flatMap(List::stream)
|
.flatMap(List::stream)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@ -234,10 +239,80 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
.header("Location", matchesRegex("http://localhost:[1-9][0-9]*/api/hs/booking/items/[^/]*"))
|
.header("Location", matchesRegex("http://localhost:[1-9][0-9]*/api/hs/booking/items/[^/]*"))
|
||||||
.extract().header("Location"); // @formatter:on
|
.extract().header("Location"); // @formatter:on
|
||||||
|
|
||||||
// finally, the new bookingItem can be accessed under the generated UUID
|
// then, the new BookingItem can be accessed under the generated UUID
|
||||||
final var newSubjectUuid = UUID.fromString(
|
final var newBookingItem = fetchRealBookingItemFromURI(location);
|
||||||
location.substring(location.lastIndexOf('/') + 1));
|
assertThat(newBookingItem)
|
||||||
assertThat(newSubjectUuid).isNotNull();
|
.extracting(bi -> bi.getDirectValue("domainName", String.class))
|
||||||
|
.isEqualTo("example.org");
|
||||||
|
|
||||||
|
// and the related HostingAsset also got created
|
||||||
|
assertThat(realHostingAssetRepo.findByIdentifier("example.org")).isNotEmpty()
|
||||||
|
.map(HsHostingAsset::getBookingItem)
|
||||||
|
.contains(newBookingItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void projectAgent_canAddBookingItemEvenIfHostingAssetCreationFails() {
|
||||||
|
|
||||||
|
context.define("superuser-alex@hostsharing.net", "hs_booking.project#D-1000111-D-1000111defaultproject:AGENT");
|
||||||
|
final var givenProject = debitorRepo.findByDebitorNumber(1000111).stream()
|
||||||
|
.map(d -> realProjectRepo.findAllByDebitorUuid(d.getUuid()))
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
|
||||||
|
Dns.fakeResultForDomain("example.org", Dns.Result.fromRecords()); // without valid verificationCode
|
||||||
|
|
||||||
|
final var location = RestAssured // @formatter:off
|
||||||
|
.given()
|
||||||
|
.header("current-subject", "superuser-alex@hostsharing.net")
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("""
|
||||||
|
{
|
||||||
|
"projectUuid": "{projectUuid}",
|
||||||
|
"type": "DOMAIN_SETUP",
|
||||||
|
"caption": "some new domain-setup booking",
|
||||||
|
"resources": {
|
||||||
|
"domainName": "example.org",
|
||||||
|
"targetUnixUser": "fir01-web",
|
||||||
|
"verificationCode": "just-a-fake-verification-code"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.replace("{projectUuid}", givenProject.getUuid().toString())
|
||||||
|
)
|
||||||
|
.port(port)
|
||||||
|
.when()
|
||||||
|
.post("http://localhost/api/hs/booking/items")
|
||||||
|
.then().log().all().assertThat()
|
||||||
|
.statusCode(201)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("", lenientlyEquals("""
|
||||||
|
{
|
||||||
|
"type": "DOMAIN_SETUP",
|
||||||
|
"caption": "some new domain-setup booking",
|
||||||
|
"validFrom": "{today}",
|
||||||
|
"validTo": null,
|
||||||
|
"resources": { "domainName": "example.org", "targetUnixUser": "fir01-web" }
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.replace("{today}", LocalDate.now().toString())
|
||||||
|
.replace("{todayPlus1Month}", LocalDate.now().plusMonths(1).toString()))
|
||||||
|
)
|
||||||
|
.header("Location", matchesRegex("http://localhost:[1-9][0-9]*/api/hs/booking/items/[^/]*"))
|
||||||
|
.extract().header("Location"); // @formatter:on
|
||||||
|
|
||||||
|
// then, the new BookingItem can be accessed under the generated UUID
|
||||||
|
final var newBookingItem = fetchRealBookingItemFromURI(location);
|
||||||
|
assertThat(newBookingItem)
|
||||||
|
.extracting(bi -> bi.getDirectValue("domainName", String.class))
|
||||||
|
.isEqualTo("example.org");
|
||||||
|
assertThat(newBookingItem)
|
||||||
|
.extracting(bi -> bi.getDirectValue("status", String.class))
|
||||||
|
.isEqualTo("[[DNS] no TXT record 'Hostsharing-domain-setup-verification-code=just-a-fake-verification-code' found for domain name 'example.org' (nor in its super-domain)]");
|
||||||
|
|
||||||
|
// but the related HostingAsset did not get created
|
||||||
|
assertThat(realHostingAssetRepo.findByIdentifier("example.org")).isEmpty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,4 +539,13 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
private Map.Entry<String, Object> resource(final String key, final Object value) {
|
private Map.Entry<String, Object> resource(final String key, final Object value) {
|
||||||
return entry(key, value);
|
return entry(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HsBookingItemRealEntity fetchRealBookingItemFromURI(final String location) {
|
||||||
|
final var newBookingItemUuid = UUID.fromString(
|
||||||
|
location.substring(location.lastIndexOf('/') + 1));
|
||||||
|
assertThat(newBookingItemUuid).isNotNull();
|
||||||
|
final var optional = realBookingItemRepo.findByUuid(newBookingItemUuid);
|
||||||
|
assertThat(optional).isNotEmpty();
|
||||||
|
return optional.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package net.hostsharing.hsadminng.hs.booking.item.validators;
|
|||||||
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorEntity;
|
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorEntity;
|
||||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity;
|
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity;
|
||||||
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealEntity;
|
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealEntity;
|
||||||
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityValidatorRegistry;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
Loading…
Reference in New Issue
Block a user