add optional alarm-contact to hosting-asset #64
@ -16,7 +16,9 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
@ -26,6 +28,9 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAss
|
||||
@RestController
|
||||
public class HsHostingAssetController implements HsHostingAssetsApi {
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
|
||||
@Autowired
|
||||
private Context context;
|
||||
|
||||
@ -119,7 +124,7 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
|
||||
|
||||
final var current = assetRepo.findByUuid(assetUuid).orElseThrow();
|
||||
|
||||
new HsHostingAssetEntityPatcher(current).apply(body);
|
||||
new HsHostingAssetEntityPatcher(em, current).apply(body);
|
||||
|
||||
final var saved = validated(assetRepo.save(current));
|
||||
final var mapped = mapper.map(saved, HsHostingAssetResource.class);
|
||||
|
@ -100,7 +100,7 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "alarmcontactuuid")
|
||||
private HsHostingContactEntity alarmContactUuid;
|
||||
private HsHostingContactEntity alarmContact;
|
||||
|
||||
@OneToMany(cascade = CascadeType.REFRESH, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name="parentassetuuid", referencedColumnName="uuid")
|
||||
|
@ -1,17 +1,22 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset;
|
||||
|
||||
import net.hostsharing.hsadminng.hs.hosting.contact.HsHostingContactEntity;
|
||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetPatchResource;
|
||||
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
||||
import net.hostsharing.hsadminng.mapper.KeyValueMap;
|
||||
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class HsHostingAssetEntityPatcher implements EntityPatcher<HsHostingAssetPatchResource> {
|
||||
|
||||
private final EntityManager em;
|
||||
private final HsHostingAssetEntity entity;
|
||||
|
||||
public HsHostingAssetEntityPatcher(final HsHostingAssetEntity entity) {
|
||||
HsHostingAssetEntityPatcher(final EntityManager em, final HsHostingAssetEntity entity) {
|
||||
this.em = em;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@ -21,5 +26,15 @@ public class HsHostingAssetEntityPatcher implements EntityPatcher<HsHostingAsset
|
||||
.ifPresent(entity::setCaption);
|
||||
Optional.ofNullable(resource.getConfig())
|
||||
.ifPresent(r -> entity.getConfig().patch(KeyValueMap.from(resource.getConfig())));
|
||||
OptionalFromJson.of(resource.getAlarmContactUuid()).ifPresent(newValue -> {
|
||||
verifyNotNull(newValue, "alarmContact");
|
||||
entity.setAlarmContact(em.getReference(HsHostingContactEntity.class, newValue));
|
||||
});
|
||||
}
|
||||
|
||||
private void verifyNotNull(final UUID newValue, final String propertyName) {
|
||||
hsh-michaelhoennig marked this conversation as resolved
Outdated
|
||||
if (newValue == null) {
|
||||
throw new IllegalArgumentException("property '" + propertyName + "' must not be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ components:
|
||||
type: string
|
||||
caption:
|
||||
type: string
|
||||
alarmContact:
|
||||
$ref: '../hs-office/hs-office-contact-schemas.yaml#/components/schemas/HsOfficeContact'
|
||||
config:
|
||||
$ref: '#/components/schemas/HsHostingAssetConfiguration'
|
||||
required:
|
||||
@ -46,6 +48,10 @@ components:
|
||||
caption:
|
||||
type: string
|
||||
nullable: true
|
||||
alarmContactUuid:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
config:
|
||||
$ref: '#/components/schemas/HsHostingAssetConfiguration'
|
||||
|
||||
@ -72,6 +78,10 @@ components:
|
||||
minLength: 3
|
||||
maxLength: 80
|
||||
nullable: false
|
||||
alarmContactUuid:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
config:
|
||||
$ref: '#/components/schemas/HsHostingAssetConfiguration'
|
||||
required:
|
||||
|
@ -7,6 +7,8 @@ import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
|
||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRepository;
|
||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
|
||||
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
||||
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
|
||||
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
||||
@ -54,6 +56,9 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
@Autowired
|
||||
HsOfficeDebitorRepository debitorRepo;
|
||||
|
||||
@Autowired
|
||||
HsOfficeContactRepository contactRepo;
|
||||
|
||||
@Autowired
|
||||
JpaAttempt jpaAttempt;
|
||||
|
||||
@ -425,6 +430,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
|
||||
final var givenAsset = givenSomeTemporaryHostingAsset("2001", MANAGED_SERVER,
|
||||
config("monit_max_ssd_usage", 80), config("monit_max_hdd_usage", 90), config("monit_max_cpu_usage", 90), config("monit_max_ram_usage", 70));
|
||||
final var alarmContactUuid = givenContact().getUuid();
|
||||
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
@ -432,13 +438,14 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
.contentType(ContentType.JSON)
|
||||
.body("""
|
||||
{
|
||||
"alarmContactUuid": "%s",
|
||||
"config": {
|
||||
"monit_max_ssd_usage": 85,
|
||||
"monit_max_hdd_usage": null,
|
||||
"monit_min_free_ssd": 5
|
||||
}
|
||||
}
|
||||
""")
|
||||
""".formatted(alarmContactUuid))
|
||||
.port(port)
|
||||
.when()
|
||||
.patch("http://localhost/api/hs/hosting/assets/" + givenAsset.getUuid())
|
||||
@ -450,6 +457,11 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"type": "MANAGED_SERVER",
|
||||
"identifier": "vm2001",
|
||||
"caption": "some test-asset",
|
||||
"alarmContact": {
|
||||
"uuid": "%s",
|
||||
"caption": "second contact",
|
||||
"emailAddresses": { "main": "contact-admin@secondcontact.example.com" }
|
||||
},
|
||||
"config": {
|
||||
"monit_max_cpu_usage": 90,
|
||||
"monit_max_ram_usage": 70,
|
||||
@ -457,12 +469,15 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"monit_min_free_ssd": 5
|
||||
}
|
||||
}
|
||||
""")); // @formatter:on
|
||||
""".formatted(alarmContactUuid)));
|
||||
// @formatter:on
|
||||
|
||||
// finally, the asset is actually updated
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
assertThat(assetRepo.findByUuid(givenAsset.getUuid())).isPresent().get()
|
||||
.matches(asset -> {
|
||||
assertThat(asset.getAlarmContact().toString()).isEqualTo(
|
||||
"contact(caption='second contact', emailAddresses='{main=contact-admin@secondcontact.example.com}')");
|
||||
assertThat(asset.getConfig().toString()).isEqualTo(
|
||||
"{ monit_max_cpu_usage: 90, monit_max_ram_usage: 70, monit_max_ssd_usage: 85, monit_min_free_ssd: 5 }");
|
||||
return true;
|
||||
@ -470,6 +485,13 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
}
|
||||
}
|
||||
|
||||
private HsOfficeContactEntity givenContact() {
|
||||
return jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
return contactRepo.findContactByOptionalCaptionLike("second").stream().findFirst().orElseThrow();
|
||||
}).returnedValue();
|
||||
}
|
||||
|
||||
@Nested
|
||||
@Order(5)
|
||||
class DeleteAsset {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset;
|
||||
|
||||
import net.hostsharing.hsadminng.hs.hosting.contact.HsHostingContactEntity;
|
||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetPatchResource;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
||||
import net.hostsharing.hsadminng.mapper.KeyValueMap;
|
||||
import net.hostsharing.hsadminng.rbac.test.PatchUnitTestBase;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@ -31,6 +31,7 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
> {
|
||||
|
||||
private static final UUID INITIAL_BOOKING_ITEM_UUID = UUID.randomUUID();
|
||||
private static final UUID PATCHED_CONTACT_UUID = UUID.randomUUID();
|
||||
|
||||
private static final Map<String, Object> INITIAL_CONFIG = patchMap(
|
||||
entry("CPU", 1),
|
||||
@ -47,6 +48,9 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
entry("SSD", 256),
|
||||
entry("MEM", 64)
|
||||
);
|
||||
final HsHostingContactEntity givenInitialContact = HsHostingContactEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.build();
|
||||
|
||||
private static final String INITIAL_CAPTION = "initial caption";
|
||||
private static final String PATCHED_CAPTION = "patched caption";
|
||||
@ -56,10 +60,12 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
|
||||
@BeforeEach
|
||||
void initMocks() {
|
||||
lenient().when(em.getReference(eq(HsOfficeDebitorEntity.class), any())).thenAnswer(invocation ->
|
||||
HsOfficeDebitorEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||
// lenient().when(em.getReference(eq(HsOfficeDebitorEntity.class), any())).thenAnswer(invocation ->
|
||||
// HsOfficeDebitorEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||
lenient().when(em.getReference(eq(HsHostingAssetEntity.class), any())).thenAnswer(invocation ->
|
||||
HsHostingAssetEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||
lenient().when(em.getReference(eq(HsHostingContactEntity.class), any())).thenAnswer(invocation ->
|
||||
HsHostingContactEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -69,6 +75,7 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
entity.setBookingItem(TEST_BOOKING_ITEM);
|
||||
entity.getConfig().putAll(KeyValueMap.from(INITIAL_CONFIG));
|
||||
entity.setCaption(INITIAL_CAPTION);
|
||||
entity.setAlarmContact(givenInitialContact);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@ -79,7 +86,7 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
|
||||
@Override
|
||||
protected HsHostingAssetEntityPatcher createPatcher(final HsHostingAssetEntity server) {
|
||||
return new HsHostingAssetEntityPatcher(server);
|
||||
return new HsHostingAssetEntityPatcher(em, server);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -96,7 +103,18 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
||||
PATCH_CONFIG,
|
||||
HsHostingAssetEntity::putConfig,
|
||||
PATCHED_CONFIG)
|
||||
.notNullable(),
|
||||
new JsonNullableProperty<>(
|
||||
"alarmContact",
|
||||
HsHostingAssetPatchResource::setAlarmContactUuid,
|
||||
PATCHED_CONTACT_UUID,
|
||||
HsHostingAssetEntity::setAlarmContact,
|
||||
newContact(PATCHED_CONTACT_UUID))
|
||||
.notNullable()
|
||||
);
|
||||
}
|
||||
|
||||
static HsHostingContactEntity newContact(final UUID uuid) {
|
||||
return HsHostingContactEntity.builder().uuid(uuid).build();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user
muss raus, darf null sein