add DomainSetup-HostingAssets for new BookingItem via created-event #111
@ -0,0 +1,20 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.booking.item;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class BookingItemCreatedAppEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
private BookingItemCreatedEventEntity entity;
|
||||||
|
|
||||||
|
public BookingItemCreatedAppEvent(
|
||||||
|
@NotNull final HsBookingItemController source,
|
||||||
|
@NotNull final HsBookingItemRealEntity newBookingItem,
|
||||||
|
final String assetJson) {
|
||||||
|
super(source);
|
||||||
|
this.entity = new BookingItemCreatedEventEntity(newBookingItem, assetJson);
|
||||||
|
}
|
||||||
|
}
|
@ -1,60 +0,0 @@
|
|||||||
package net.hostsharing.hsadminng.hs.booking.item;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.springframework.context.ApplicationEvent;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class BookingItemCreatedEvent extends ApplicationEvent {
|
|
||||||
|
|
||||||
private static final Map<UUID, BookingItemCreatedEvent> events = new HashMap<>(); // FIXME: use DB table
|
|
||||||
|
|
||||||
static BookingItemCreatedEvent of(final HsBookingItemRealEntity bookingItem) {
|
|
||||||
return events.get(bookingItem.getUuid());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public static class Status {
|
|
||||||
|
|
||||||
private final String message;
|
|
||||||
|
|
||||||
private Status(final String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Status finished() {
|
|
||||||
return new Status(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Status failed(final String errorMessage) {
|
|
||||||
return new Status(errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isFinished() {
|
|
||||||
return message == null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final @NotNull UUID bookingItemUuid;
|
|
||||||
private final @NotNull String assetJson;
|
|
||||||
|
|
||||||
private Status status;
|
|
||||||
|
|
||||||
public BookingItemCreatedEvent(
|
|
||||||
@NotNull final HsBookingItemController source,
|
|
||||||
@NotNull final HsBookingItem newBookingItem,
|
|
||||||
final String assetJson) {
|
|
||||||
super(source);
|
|
||||||
this.bookingItemUuid = newBookingItem.getUuid();
|
|
||||||
this.assetJson = assetJson;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(final Status status) {
|
|
||||||
this.status = status;
|
|
||||||
events.put(bookingItemUuid, this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,60 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.booking.item;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.MapsId;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.persistence.Version;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(schema = "hs_booking", name = "item_created_event")
|
||||||
|
@SuperBuilder(toBuilder = true)
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class BookingItemCreatedEventEntity {
|
||||||
|
@Id
|
||||||
|
@Column(name="bookingitemuuid")
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
@MapsId
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
@JoinColumn(name = "bookingitemuuid", nullable = false)
|
||||||
|
private HsBookingItemRealEntity bookingItem;
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private int version;
|
||||||
|
|
||||||
|
@Column(name = "assetjson")
|
||||||
|
private String assetJson;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Column(name = "statusmessage")
|
||||||
|
private String statusMessage;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Column
|
||||||
|
private boolean completed;
|
||||||
|
|
||||||
|
public void setBookingItem(HsBookingItemRealEntity bookingItem) {
|
||||||
|
this.bookingItem = bookingItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BookingItemCreatedEventEntity(
|
||||||
|
@NotNull final HsBookingItemRealEntity newBookingItem,
|
||||||
|
final String assetJson) {
|
||||||
|
this.bookingItem = newBookingItem;
|
||||||
|
this.assetJson = assetJson;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.booking.item;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.Repository;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface BookingItemCreatedEventRepository extends Repository<BookingItemCreatedEventEntity, UUID> {
|
||||||
|
|
||||||
|
BookingItemCreatedEventEntity save(HsBookingItemRealEntity current);
|
||||||
|
|
||||||
|
BookingItemCreatedEventEntity findByBookingItem(HsBookingItemRealEntity newBookingItem);
|
||||||
|
}
|
@ -83,8 +83,9 @@ public class HsBookingItemController implements HsBookingItemsApi {
|
|||||||
.revampProperties();
|
.revampProperties();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
applicationEventPublisher.publishEvent(new BookingItemCreatedEvent(
|
final var bookingItemRealEntity = em.getReference(HsBookingItemRealEntity.class, saveProcessor.getEntity().getUuid());
|
||||||
this, saveProcessor.getEntity(), jsonMapper.writeValueAsString(body.getAsset())));
|
applicationEventPublisher.publishEvent(new BookingItemCreatedAppEvent(
|
||||||
|
this, bookingItemRealEntity, jsonMapper.writeValueAsString(body.getAsset())));
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetAutoInsertResource;
|
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetAutoInsertResource;
|
||||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetTypeResource;
|
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetTypeResource;
|
||||||
import net.hostsharing.hsadminng.hs.booking.item.BookingItemCreatedEvent;
|
import net.hostsharing.hsadminng.hs.booking.item.BookingItemCreatedAppEvent;
|
||||||
import net.hostsharing.hsadminng.hs.booking.item.BookingItemCreatedEvent.Status;
|
|
||||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity;
|
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity;
|
||||||
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntitySaveProcessor;
|
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntitySaveProcessor;
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
|
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
|
||||||
@ -28,7 +27,7 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMA
|
|||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SMTP_SETUP;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SMTP_SETUP;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class HsBookingItemCreatedListener implements ApplicationListener<BookingItemCreatedEvent> {
|
public class HsBookingItemCreatedListener implements ApplicationListener<BookingItemCreatedAppEvent> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private EntityManagerWrapper emw;
|
private EntityManagerWrapper emw;
|
||||||
@ -41,19 +40,19 @@ public class HsBookingItemCreatedListener implements ApplicationListener<Booking
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void onApplicationEvent(final BookingItemCreatedEvent event) {
|
public void onApplicationEvent(final BookingItemCreatedAppEvent event) {
|
||||||
final var newBookingItemRealEntity =
|
final var newBookingItemRealEntity = event.getEntity().getBookingItem();
|
||||||
emw.getReference(HsBookingItemRealEntity.class, event.getBookingItemUuid());
|
final var asset = jsonMapper.readValue(event.getEntity().getAssetJson(), HsHostingAssetAutoInsertResource.class);
|
||||||
final var asset = jsonMapper.readValue(event.getAssetJson(), HsHostingAssetAutoInsertResource.class);
|
|
||||||
final var factory = switch (newBookingItemRealEntity.getType()) {
|
final var factory = switch (newBookingItemRealEntity.getType()) {
|
||||||
case PRIVATE_CLOUD -> null;
|
case PRIVATE_CLOUD -> null;
|
||||||
case CLOUD_SERVER -> null;
|
case CLOUD_SERVER -> null;
|
||||||
case MANAGED_SERVER -> null;
|
case MANAGED_SERVER -> null;
|
||||||
case MANAGED_WEBSPACE -> null;
|
case MANAGED_WEBSPACE -> null; // TODO.impl: implement ManagedWebspace HostingAsset creation, where possible
|
||||||
case DOMAIN_SETUP -> new DomainSetupHostingAssetFactory(newBookingItemRealEntity, asset);
|
case DOMAIN_SETUP -> new DomainSetupHostingAssetFactory(newBookingItemRealEntity, asset);
|
||||||
};
|
};
|
||||||
if (factory != null) {
|
if (factory != null) {
|
||||||
event.setStatus(factory.performSaveProcess());
|
event.getEntity().setStatusMessage(factory.performSaveProcess());
|
||||||
|
emw.persist(event.getEntity()); // TODO.impl: once we implement retry, we might need merge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,23 +70,23 @@ public class HsBookingItemCreatedListener implements ApplicationListener<Booking
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status performSaveProcess() {
|
String performSaveProcess() {
|
||||||
final var newHostingAsset = create();
|
final var newHostingAsset = create();
|
||||||
try {
|
try {
|
||||||
return persist(newHostingAsset);
|
persist(newHostingAsset);
|
||||||
|
return null;
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
return Status.failed(e.getMessage());
|
return e.getMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Status persist(final HsHostingAsset newHostingAsset) {
|
protected void persist(final HsHostingAsset newHostingAsset) {
|
||||||
new HostingAssetEntitySaveProcessor(emw, newHostingAsset)
|
new HostingAssetEntitySaveProcessor(emw, newHostingAsset)
|
||||||
.preprocessEntity()
|
.preprocessEntity()
|
||||||
.validateEntity()
|
.validateEntity()
|
||||||
.prepareForSave()
|
.prepareForSave()
|
||||||
.save()
|
.save()
|
||||||
.validateContext();
|
.validateContext();
|
||||||
return Status.finished();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,10 +165,9 @@ public class HsBookingItemCreatedListener implements ApplicationListener<Booking
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Status persist(final HsHostingAsset newHostingAsset) {
|
protected void persist(final HsHostingAsset newHostingAsset) {
|
||||||
final var status = super.persist(newHostingAsset);
|
super.persist(newHostingAsset);
|
||||||
newHostingAsset.getSubHostingAssets().forEach(super::persist);
|
newHostingAsset.getSubHostingAssets().forEach(super::persist);
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,21 @@ create table if not exists hs_booking.item
|
|||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
--changeset michael.hoennig:hs-booking-item-EVENT-TABLE endDelimiter:--//
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
create table if not exists hs_booking.item_created_event
|
||||||
|
(
|
||||||
|
bookingItemUuid uuid unique references hs_booking.item (uuid),
|
||||||
|
version int not null default 0,
|
||||||
|
assetJson text,
|
||||||
|
statusMessage text,
|
||||||
|
completed boolean not null default false
|
||||||
|
);
|
||||||
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset michael.hoennig:hs-booking-item-MAIN-TABLE-JOURNAL endDelimiter:--//
|
--changeset michael.hoennig:hs-booking-item-MAIN-TABLE-JOURNAL endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
@ -13,6 +13,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.validators.Dns;
|
|||||||
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.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.ClassOrderer;
|
import org.junit.jupiter.api.ClassOrderer;
|
||||||
import org.junit.jupiter.api.MethodOrderer;
|
import org.junit.jupiter.api.MethodOrderer;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
@ -61,6 +62,9 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
@Autowired
|
@Autowired
|
||||||
HsHostingAssetRealRepository realHostingAssetRepo;
|
HsHostingAssetRealRepository realHostingAssetRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
BookingItemCreatedEventRepository bookingItemCreationEventRepo;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
JpaAttempt jpaAttempt;
|
JpaAttempt jpaAttempt;
|
||||||
|
|
||||||
@ -261,8 +265,8 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
assertThat(realHostingAssetRepo.findByIdentifier("example.org|SMTP")).isNotEmpty()
|
assertThat(realHostingAssetRepo.findByIdentifier("example.org|SMTP")).isNotEmpty()
|
||||||
.map(HsHostingAsset::getParentAsset)
|
.map(HsHostingAsset::getParentAsset)
|
||||||
.isEqualTo(domainSetupHostingAsset);
|
.isEqualTo(domainSetupHostingAsset);
|
||||||
final var status = BookingItemCreatedEvent.of(newBookingItem);
|
final var event = bookingItemCreationEventRepo.findByBookingItem(newBookingItem);
|
||||||
assertThat(status.getStatus().isFinished());
|
assertThat(event.isCompleted());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,8 +332,8 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
assertThat(newBookingItem)
|
assertThat(newBookingItem)
|
||||||
.extracting(bi -> bi.getDirectValue("domainName", String.class))
|
.extracting(bi -> bi.getDirectValue("domainName", String.class))
|
||||||
.isEqualTo("example.org");
|
.isEqualTo("example.org");
|
||||||
final var status = BookingItemCreatedEvent.of(newBookingItem);
|
final var event = bookingItemCreationEventRepo.findByBookingItem(newBookingItem);
|
||||||
assertThat(status.getStatus().getMessage())
|
assertThat(event.getStatusMessage())
|
||||||
.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)]");
|
.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
|
// but the related HostingAsset did not get created
|
||||||
@ -565,6 +569,13 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
}).assertSuccessful().returnedValue();
|
}).assertSuccessful().returnedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void cleanupEventEntities() {
|
||||||
|
jpaAttempt.transacted(() -> {
|
||||||
|
em.createQuery("delete from BookingItemCreatedEventEntity").executeUpdate();
|
||||||
|
}).assertSuccessful();
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user