add application event for newly created booking items and create domain setup hosting asset (WIP)
This commit is contained in:
parent
cb4aecb9c8
commit
d189d2670c
@ -0,0 +1,16 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.booking.item;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class BookingItemCreatedEvent extends ApplicationEvent {
|
||||||
|
private final @NotNull HsBookingItem newBookingItem;
|
||||||
|
|
||||||
|
public BookingItemCreatedEvent(@NotNull HsBookingItemController source, @NotNull final HsBookingItem newBookingItem) {
|
||||||
|
super(source);
|
||||||
|
this.newBookingItem = newBookingItem;
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ import net.hostsharing.hsadminng.mapper.KeyValueMap;
|
|||||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||||
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
|
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
@ -33,6 +34,9 @@ public class HsBookingItemController implements HsBookingItemsApi {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private StrictMapper mapper;
|
private StrictMapper mapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private HsBookingItemRbacRepository bookingItemRepo;
|
private HsBookingItemRbacRepository bookingItemRepo;
|
||||||
|
|
||||||
@ -63,7 +67,8 @@ public class HsBookingItemController implements HsBookingItemsApi {
|
|||||||
context.define(currentSubject, assumedRoles);
|
context.define(currentSubject, assumedRoles);
|
||||||
|
|
||||||
final var entityToSave = mapper.map(body, HsBookingItemRbacEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER);
|
final var entityToSave = mapper.map(body, HsBookingItemRbacEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER);
|
||||||
final var mapped = new BookingItemEntitySaveProcessor(em, entityToSave)
|
final var saveProcessor = new BookingItemEntitySaveProcessor(em, entityToSave);
|
||||||
|
final var mapped = saveProcessor
|
||||||
.preprocessEntity()
|
.preprocessEntity()
|
||||||
.validateEntity()
|
.validateEntity()
|
||||||
.prepareForSave()
|
.prepareForSave()
|
||||||
@ -72,6 +77,8 @@ public class HsBookingItemController implements HsBookingItemsApi {
|
|||||||
.mapUsing(e -> mapper.map(e, HsBookingItemResource.class, ITEM_TO_RESOURCE_POSTMAPPER))
|
.mapUsing(e -> mapper.map(e, HsBookingItemResource.class, ITEM_TO_RESOURCE_POSTMAPPER))
|
||||||
.revampProperties();
|
.revampProperties();
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(new BookingItemCreatedEvent(this, saveProcessor.getEntity()));
|
||||||
|
|
||||||
final var uri =
|
final var uri =
|
||||||
MvcUriComponentsBuilder.fromController(getClass())
|
MvcUriComponentsBuilder.fromController(getClass())
|
||||||
.path("/api/hs/booking/items/{id}")
|
.path("/api/hs/booking/items/{id}")
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.hostsharing.hsadminng.hs.booking.item.validators;
|
package net.hostsharing.hsadminng.hs.booking.item.validators;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
import net.hostsharing.hsadminng.errors.MultiValidationException;
|
import net.hostsharing.hsadminng.errors.MultiValidationException;
|
||||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemResource;
|
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemResource;
|
||||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItem;
|
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItem;
|
||||||
@ -20,7 +21,11 @@ public class BookingItemEntitySaveProcessor {
|
|||||||
private final HsEntityValidator<HsBookingItem> validator;
|
private final HsEntityValidator<HsBookingItem> validator;
|
||||||
private String expectedStep = "preprocessEntity";
|
private String expectedStep = "preprocessEntity";
|
||||||
private final EntityManager em;
|
private final EntityManager em;
|
||||||
|
|
||||||
|
@Getter
|
||||||
private HsBookingItem entity;
|
private HsBookingItem entity;
|
||||||
|
|
||||||
|
@Getter
|
||||||
private HsBookingItemResource resource;
|
private HsBookingItemResource resource;
|
||||||
|
|
||||||
public BookingItemEntitySaveProcessor(final EntityManager em, final HsBookingItem entity) {
|
public BookingItemEntitySaveProcessor(final EntityManager em, final HsBookingItem entity) {
|
||||||
|
@ -55,6 +55,11 @@ class HsDomainSetupBookingItemValidator extends HsBookingItemEntityValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String generateVerificationCode(final EntityManager em, final PropertiesProvider propertiesProvider) {
|
private static String generateVerificationCode(final EntityManager em, final PropertiesProvider propertiesProvider) {
|
||||||
|
final var userDefinedVerificationCode = propertiesProvider.getDirectValue(VERIFICATION_CODE_PROPERTY_NAME, String.class);
|
||||||
|
if (userDefinedVerificationCode != null) {
|
||||||
|
return userDefinedVerificationCode;
|
||||||
|
}
|
||||||
|
|
||||||
final var alphaNumeric = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
final var alphaNumeric = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||||
final var secureRandom = new SecureRandom();
|
final var secureRandom = new SecureRandom();
|
||||||
final var sb = new StringBuilder();
|
final var sb = new StringBuilder();
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.hosting.asset;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.booking.item.BookingItemCreatedEvent;
|
||||||
|
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity;
|
||||||
|
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntitySaveProcessor;
|
||||||
|
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class HsBookingItemCreatedListener implements ApplicationListener<BookingItemCreatedEvent> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EntityManagerWrapper emw;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(final BookingItemCreatedEvent event) {
|
||||||
|
System.out.println("Received newly created booking item: " + event.getNewBookingItem());
|
||||||
|
final var newBookingItemRealEntity =
|
||||||
|
emw.getReference(HsBookingItemRealEntity.class, event.getNewBookingItem().getUuid());
|
||||||
|
final var newHostingAsset = switch (newBookingItemRealEntity.getType()) {
|
||||||
|
case PRIVATE_CLOUD -> null;
|
||||||
|
case CLOUD_SERVER -> null;
|
||||||
|
case MANAGED_SERVER -> null;
|
||||||
|
case MANAGED_WEBSPACE -> null;
|
||||||
|
case DOMAIN_SETUP -> createDomainSetupHostingAsset(newBookingItemRealEntity);
|
||||||
|
};
|
||||||
|
if (newHostingAsset != null) {
|
||||||
|
new HostingAssetEntitySaveProcessor(emw, newHostingAsset)
|
||||||
|
.preprocessEntity()
|
||||||
|
.validateEntity()
|
||||||
|
.prepareForSave()
|
||||||
|
.save()
|
||||||
|
.validateContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HsHostingAsset createDomainSetupHostingAsset(final HsBookingItemRealEntity fromBookingItem) {
|
||||||
|
return HsHostingAssetRbacEntity.builder()
|
||||||
|
.bookingItem(fromBookingItem)
|
||||||
|
.type(HsHostingAssetType.DOMAIN_SETUP)
|
||||||
|
.identifier(fromBookingItem.getDirectValue("domainName", String.class))
|
||||||
|
.subHostingAssets(List.of(
|
||||||
|
// TARGET_UNIX_USER_PROPERTY_NAME
|
||||||
|
))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ components:
|
|||||||
- CLOUD_SERVER
|
- CLOUD_SERVER
|
||||||
- MANAGED_SERVER
|
- MANAGED_SERVER
|
||||||
- MANAGED_WEBSPACE
|
- MANAGED_WEBSPACE
|
||||||
|
- DOMAIN_SETUP
|
||||||
|
|
||||||
HsBookingItem:
|
HsBookingItem:
|
||||||
type: object
|
type: object
|
||||||
|
@ -5,6 +5,7 @@ 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.project.HsBookingProjectRealRepository;
|
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealRepository;
|
||||||
|
import net.hostsharing.hsadminng.hs.hosting.asset.validators.Dns;
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
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;
|
||||||
@ -180,6 +181,64 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
location.substring(location.lastIndexOf('/') + 1));
|
location.substring(location.lastIndexOf('/') + 1));
|
||||||
assertThat(newSubjectUuid).isNotNull();
|
assertThat(newSubjectUuid).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globalAdmin_canAddBookingItemWithHostingAsset() {
|
||||||
|
|
||||||
|
context.define("superuser-alex@hostsharing.net");
|
||||||
|
final var givenProject = debitorRepo.findDebitorByDebitorNumber(1000111).stream()
|
||||||
|
.map(d -> realProjectRepo.findAllByDebitorUuid(d.getUuid()))
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
|
||||||
|
Dns.fakeResultForDomain("example.org",
|
||||||
|
Dns.Result.fromRecords("Hostsharing-domain-setup-verification-code=just-a-fake-verification-code"));
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// finally, the new bookingItem can be accessed under the generated UUID
|
||||||
|
final var newSubjectUuid = UUID.fromString(
|
||||||
|
location.substring(location.lastIndexOf('/') + 1));
|
||||||
|
assertThat(newSubjectUuid).isNotNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
|
@ -3,6 +3,7 @@ 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;
|
||||||
@ -14,6 +15,7 @@ import static java.util.Map.entry;
|
|||||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.DOMAIN_SETUP;
|
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.DOMAIN_SETUP;
|
||||||
import static org.apache.commons.lang3.StringUtils.right;
|
import static org.apache.commons.lang3.StringUtils.right;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||||
|
|
||||||
class HsDomainSetupBookingItemValidatorUnitTest {
|
class HsDomainSetupBookingItemValidatorUnitTest {
|
||||||
|
|
||||||
@ -41,10 +43,12 @@ class HsDomainSetupBookingItemValidatorUnitTest {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = HsBookingItemEntityValidatorRegistry.doValidate(em, domainSetupBookingItemEntity);
|
final var thrown = catchThrowable(() -> {
|
||||||
|
new BookingItemEntitySaveProcessor(em, domainSetupBookingItemEntity).preprocessEntity().validateEntity();
|
||||||
|
});
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).isEmpty();
|
assertThat(thrown).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -62,10 +66,12 @@ class HsDomainSetupBookingItemValidatorUnitTest {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final var result = HsBookingItemEntityValidatorRegistry.doValidate(em, domainSetupBookingItemEntity);
|
final var thrown = catchThrowable(() -> {
|
||||||
|
new BookingItemEntitySaveProcessor(em, domainSetupBookingItemEntity).preprocessEntity().validateEntity();
|
||||||
|
});
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).isEmpty();
|
assertThat(thrown).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user