hosting-asset-validation-baseline #56
@ -16,6 +16,7 @@ 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.EntityNotFoundException;
|
||||
import jakarta.validation.ValidationException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@ -130,8 +131,12 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
|
||||
return entityToSave;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final BiConsumer<HsHostingAssetInsertResource, HsHostingAssetEntity> RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
|
||||
entity.putConfig(KeyValueMap.from(resource.getConfig()));
|
||||
if (resource.getParentAssetUuid() != null) {
|
||||
entity.setParentAsset(assetRepo.findByUuid(resource.getParentAssetUuid())
|
||||
.orElseThrow(() -> new EntityNotFoundException("ERROR: [400] parentAssetUuid %s not found".formatted(
|
||||
resource.getParentAssetUuid()))));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.CaseDef.inOtherCas
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.ColumnValue.usingCase;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.ColumnValue.usingDefaultCase;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NULLABLE;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.DELETE;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT;
|
||||
@ -137,7 +136,7 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject {
|
||||
.importEntityAlias("bookingItem", HsBookingItemEntity.class, usingDefaultCase(),
|
||||
dependsOnColumn("bookingItemUuid"),
|
||||
directlyFetchedByDependsOnColumn(),
|
||||
NOT_NULL)
|
||||
NULLABLE)
|
||||
|
||||
.switchOnColumn("type",
|
||||
inCaseOf(CLOUD_SERVER.name(),
|
||||
|
@ -53,7 +53,11 @@ components:
|
||||
bookingItemUuid:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: false
|
||||
nullable: true
|
||||
parentAssetUuid:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
type:
|
||||
$ref: '#/components/schemas/HsHostingAssetType'
|
||||
identifier:
|
||||
@ -72,7 +76,6 @@ components:
|
||||
- type
|
||||
- identifier
|
||||
- caption
|
||||
- debitorUuid
|
||||
- config
|
||||
additionalProperties: false
|
||||
|
||||
|
@ -24,13 +24,17 @@ create table if not exists hs_hosting_asset
|
||||
(
|
||||
uuid uuid unique references RbacObject (uuid),
|
||||
version int not null default 0,
|
||||
bookingItemUuid uuid not null references hs_booking_item(uuid),
|
||||
bookingItemUuid uuid null references hs_booking_item(uuid),
|
||||
type HsHostingAssetType not null,
|
||||
parentAssetUuid uuid null references hs_hosting_asset(uuid),
|
||||
identifier varchar(80) not null,
|
||||
caption varchar(80) not null,
|
||||
config jsonb not null
|
||||
config jsonb not null,
|
||||
|
||||
constraint chk_hs_hosting_asset_has_booking_item_or_parent_asset check (bookingItemUuid is not null or parentAssetUuid is not null)
|
||||
);
|
||||
|
||||
|
||||
--//
|
||||
|
||||
|
||||
|
@ -39,8 +39,6 @@ begin
|
||||
SELECT * FROM hs_hosting_asset WHERE uuid = NEW.parentAssetUuid INTO newParentServer;
|
||||
|
||||
SELECT * FROM hs_booking_item WHERE uuid = NEW.bookingItemUuid INTO newBookingItem;
|
||||
assert newBookingItem.uuid is not null, format('newBookingItem must not be null for NEW.bookingItemUuid = %s', NEW.bookingItemUuid);
|
||||
|
||||
|
||||
perform createRoleWithGrants(
|
||||
hsHostingAssetOWNER(NEW),
|
||||
|
@ -19,6 +19,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
|
||||
import static net.hostsharing.hsadminng.rbac.test.JsonMatcher.lenientlyEquals;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.matchesRegex;
|
||||
@ -113,7 +114,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
.header("current-user", "superuser-alex@hostsharing.net")
|
||||
.port(port)
|
||||
.when()
|
||||
.get("http://localhost/api/hs/hosting/assets?type=" + HsHostingAssetType.MANAGED_SERVER)
|
||||
.get("http://localhost/api/hs/hosting/assets?type=" + MANAGED_SERVER)
|
||||
.then().log().all().assertThat()
|
||||
.statusCode(200)
|
||||
.contentType("application/json")
|
||||
@ -159,7 +160,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
class AddServer {
|
||||
|
||||
@Test
|
||||
void globalAdmin_canAddAsset() {
|
||||
void globalAdmin_canAddBookedAsset() {
|
||||
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenBookingItem = givenBookingItem("First", "some PrivateCloud");
|
||||
@ -173,7 +174,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"bookingItemUuid": "%s",
|
||||
"type": "MANAGED_SERVER",
|
||||
"identifier": "vm1400",
|
||||
"caption": "some new CloudServer",
|
||||
"caption": "some new ManagedServer",
|
||||
"config": { "CPUs": 2, "RAM": 100, "SSD": 300, "Traffic": 250 }
|
||||
}
|
||||
""".formatted(givenBookingItem.getUuid()))
|
||||
@ -187,7 +188,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
{
|
||||
"type": "MANAGED_SERVER",
|
||||
"identifier": "vm1400",
|
||||
"caption": "some new CloudServer",
|
||||
"caption": "some new ManagedServer",
|
||||
"config": { "CPUs": 2, "RAM": 100, "SSD": 300, "Traffic": 250 }
|
||||
}
|
||||
"""))
|
||||
@ -200,6 +201,48 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
assertThat(newUserUuid).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void parentAssetAgent_canAddSubAsset() {
|
||||
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenParentAsset = givenParentAsset("First", MANAGED_SERVER);
|
||||
|
||||
final var location = RestAssured // @formatter:off
|
||||
.given()
|
||||
.header("current-user", "person-FirbySusan@example.com")
|
||||
.contentType(ContentType.JSON)
|
||||
.body("""
|
||||
{
|
||||
"parentAssetUuid": "%s",
|
||||
"type": "MANAGED_WEBSPACE",
|
||||
"identifier": "xyz00",
|
||||
"caption": "some new ManagedWebspace in client's ManagedServer",
|
||||
"config": { "SSD": 100, "Traffic": 250 }
|
||||
}
|
||||
""".formatted(givenParentAsset.getUuid()))
|
||||
.port(port)
|
||||
.when()
|
||||
.post("http://localhost/api/hs/hosting/assets")
|
||||
.then().log().all().assertThat()
|
||||
.statusCode(201)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("", lenientlyEquals("""
|
||||
{
|
||||
"type": "MANAGED_WEBSPACE",
|
||||
"identifier": "xyz00",
|
||||
"caption": "some new ManagedWebspace in client's ManagedServer",
|
||||
"config": { "SSD": 100, "Traffic": 250 }
|
||||
}
|
||||
"""))
|
||||
.header("Location", matchesRegex("http://localhost:[1-9][0-9]*/api/hs/hosting/assets/[^/]*"))
|
||||
.extract().header("Location"); // @formatter:on
|
||||
|
||||
// finally, the new asset can be accessed under the generated UUID
|
||||
final var newUserUuid = UUID.fromString(
|
||||
location.substring(location.lastIndexOf('/') + 1));
|
||||
assertThat(newUserUuid).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void additionalValidationsArePerformend_whenAddingAsset() {
|
||||
|
||||
@ -215,7 +258,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"bookingItemUuid": "%s",
|
||||
"type": "MANAGED_SERVER",
|
||||
"identifier": "vm1400",
|
||||
"caption": "some new CloudServer",
|
||||
"caption": "some new ManagedServer",
|
||||
"config": { "CPUs": 0, "extra": 42 }
|
||||
}
|
||||
""".formatted(givenBookingItem.getUuid()))
|
||||
@ -235,7 +278,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
}
|
||||
|
||||
@Nested
|
||||
class GetASset {
|
||||
class GetAsset {
|
||||
|
||||
@Test
|
||||
void globalAdmin_canGetArbitraryAsset() {
|
||||
@ -412,6 +455,12 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
.findAny().orElseThrow();
|
||||
}
|
||||
|
||||
HsHostingAssetEntity givenParentAsset(final String debitorName, final HsHostingAssetType assetType) {
|
||||
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike(debitorName).stream().findAny().orElseThrow();
|
||||
final var givenAsset = assetRepo.findAllByCriteria(givenDebitor.getUuid(), null, assetType).stream().findAny().orElseThrow();
|
||||
return givenAsset;
|
||||
}
|
||||
|
||||
private HsHostingAssetEntity givenSomeTemporaryAssetForDebitorNumber(final String identifierSuffix,
|
||||
final Map.Entry<String, Integer> resources) {
|
||||
return jpaAttempt.transacted(() -> {
|
||||
|
Loading…
Reference in New Issue
Block a user