add assigned-asset, add more hosting-asset test-data and introduce HsBookingDebitor+hs_booking_debitor_rv (#58)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/58 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
@ -0,0 +1,55 @@
|
||||
package net.hostsharing.hsadminng.hs.booking.debitor;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
|
||||
// a partial HsOfficeDebitorEntity to reduce the number of SQL queries to load the entity
|
||||
@Entity
|
||||
@Table(name = "hs_booking_debitor_rv")
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@DisplayName("BookingDebitor")
|
||||
public class HsBookingDebitorEntity implements Stringifyable {
|
||||
|
||||
public static final String DEBITOR_NUMBER_TAG = "D-";
|
||||
|
||||
private static Stringify<HsBookingDebitorEntity> stringify =
|
||||
stringify(HsBookingDebitorEntity.class, "booking-debitor")
|
||||
.withIdProp(HsBookingDebitorEntity::toShortString)
|
||||
.withProp(HsBookingDebitorEntity::getDefaultPrefix)
|
||||
.quotedValues(false);
|
||||
|
||||
@Id
|
||||
private UUID uuid;
|
||||
|
||||
@Column(name = "debitornumber")
|
||||
private Integer debitorNumber;
|
||||
|
||||
@Column(name = "defaultprefix", columnDefinition = "char(3) not null")
|
||||
private String defaultPrefix;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return stringify.apply(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toShortString() {
|
||||
return DEBITOR_NUMBER_TAG + debitorNumber;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package net.hostsharing.hsadminng.hs.booking.debitor;
|
||||
|
||||
import org.springframework.data.repository.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface HsBookingDebitorRepository extends Repository<HsBookingDebitorEntity, UUID> {
|
||||
|
||||
Optional<HsBookingDebitorEntity> findByUuid(UUID id);
|
||||
|
||||
List<HsBookingDebitorEntity> findByDebitorNumber(int debitorNumber);
|
||||
}
|
@ -160,6 +160,10 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject, Validatab
|
||||
return resources;
|
||||
}
|
||||
|
||||
public HsBookingProjectEntity getRelatedProject() {
|
||||
return project != null ? project : parentItem.getRelatedProject();
|
||||
}
|
||||
|
||||
public static RbacView rbac() {
|
||||
return rbacViewFor("bookingItem", HsBookingItemEntity.class)
|
||||
.withIdentityView(SQL.projection("caption"))
|
||||
@ -198,6 +202,6 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject, Validatab
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
rbac().generateWithBaseFileName("6-hs-booking/620-booking-item/6203-hs-booking-item-rbac");
|
||||
rbac().generateWithBaseFileName("6-hs-booking/630-booking-item/6303-hs-booking-item-rbac");
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,10 @@ import java.util.UUID;
|
||||
|
||||
public interface HsBookingItemRepository extends Repository<HsBookingItemEntity, UUID> {
|
||||
|
||||
List<HsBookingItemEntity> findAll();
|
||||
Optional<HsBookingItemEntity> findByUuid(final UUID bookingItemUuid);
|
||||
|
||||
List<HsBookingItemEntity> findByCaption(String bookingItemCaption);
|
||||
|
||||
List<HsBookingItemEntity> findAllByProjectUuid(final UUID projectItemUuid);
|
||||
|
||||
HsBookingItemEntity save(HsBookingItemEntity current);
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.hostsharing.hsadminng.hs.booking.project;
|
||||
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorRepository;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.api.HsBookingProjectsApi;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingProjectInsertResource;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingProjectPatchResource;
|
||||
@ -12,8 +13,10 @@ 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 java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@RestController
|
||||
public class HsBookingProjectController implements HsBookingProjectsApi {
|
||||
@ -27,6 +30,9 @@ public class HsBookingProjectController implements HsBookingProjectsApi {
|
||||
@Autowired
|
||||
private HsBookingProjectRepository bookingProjectRepo;
|
||||
|
||||
@Autowired
|
||||
private HsBookingDebitorRepository debitorRepo;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseEntity<List<HsBookingProjectResource>> listBookingProjectsByDebitorUuid(
|
||||
@ -50,7 +56,7 @@ public class HsBookingProjectController implements HsBookingProjectsApi {
|
||||
|
||||
context.define(currentUser, assumedRoles);
|
||||
|
||||
final var entityToSave = mapper.map(body, HsBookingProjectEntity.class);
|
||||
final var entityToSave = mapper.map(body, HsBookingProjectEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER);
|
||||
|
||||
final var saved = bookingProjectRepo.save(entityToSave);
|
||||
|
||||
@ -111,4 +117,12 @@ public class HsBookingProjectController implements HsBookingProjectsApi {
|
||||
final var mapped = mapper.map(saved, HsBookingProjectResource.class);
|
||||
return ResponseEntity.ok(mapped);
|
||||
}
|
||||
|
||||
final BiConsumer<HsBookingProjectInsertResource, HsBookingProjectEntity> RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
|
||||
if (resource.getDebitorUuid() != null) {
|
||||
entity.setDebitor(debitorRepo.findByUuid(resource.getDebitorUuid())
|
||||
.orElseThrow(() -> new EntityNotFoundException("ERROR: [400] debitorUuid %s not found".formatted(
|
||||
resource.getDebitorUuid()))));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.hostsharing.hsadminng.hs.booking.project;
|
||||
|
||||
import lombok.*;
|
||||
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
|
||||
@ -49,7 +50,7 @@ public class HsBookingProjectEntity implements Stringifyable, RbacObject {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "debitoruuid")
|
||||
private HsOfficeDebitorEntity debitor;
|
||||
private HsBookingDebitorEntity debitor;
|
||||
|
||||
@Column(name = "caption")
|
||||
private String caption;
|
||||
@ -61,7 +62,7 @@ public class HsBookingProjectEntity implements Stringifyable, RbacObject {
|
||||
|
||||
@Override
|
||||
public String toShortString() {
|
||||
return ofNullable(debitor).map(HsOfficeDebitorEntity::toShortString).orElse("D-???????") +
|
||||
return ofNullable(debitor).map(HsBookingDebitorEntity::toShortString).orElse("D-???????") +
|
||||
":" + caption;
|
||||
}
|
||||
|
||||
@ -108,6 +109,6 @@ public class HsBookingProjectEntity implements Stringifyable, RbacObject {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
rbac().generateWithBaseFileName("6-hs-booking/610-booking-project/6103-hs-booking-project-rbac");
|
||||
rbac().generateWithBaseFileName("6-hs-booking/620-booking-project/6203-hs-booking-project-rbac");
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ import java.util.UUID;
|
||||
|
||||
public interface HsBookingProjectRepository extends Repository<HsBookingProjectEntity, UUID> {
|
||||
|
||||
List<HsBookingProjectEntity> findAll();
|
||||
Optional<HsBookingProjectEntity> findByUuid(final UUID bookingProjectUuid);
|
||||
List<HsBookingProjectEntity> findByCaption(final String projectCaption);
|
||||
|
||||
List<HsBookingProjectEntity> findAllByDebitorUuid(final UUID bookingProjectUuid);
|
||||
|
||||
|
@ -33,9 +33,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
|
||||
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.GLOBAL;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NULLABLE;
|
||||
@ -65,6 +63,7 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Validata
|
||||
.withProp(HsHostingAssetEntity::getIdentifier)
|
||||
.withProp(HsHostingAssetEntity::getCaption)
|
||||
.withProp(HsHostingAssetEntity::getParentAsset)
|
||||
.withProp(HsHostingAssetEntity::getAssignedToAsset)
|
||||
.withProp(HsHostingAssetEntity::getBookingItem)
|
||||
.withProp(HsHostingAssetEntity::getConfig)
|
||||
.quotedValues(false);
|
||||
@ -84,6 +83,10 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Validata
|
||||
@JoinColumn(name = "parentassetuuid")
|
||||
private HsHostingAssetEntity parentAsset;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "assignedtoassetuuid")
|
||||
private HsHostingAssetEntity assignedToAsset;
|
||||
|
||||
@Column(name = "type")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private HsHostingAssetType type;
|
||||
@ -144,12 +147,17 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Validata
|
||||
NULLABLE)
|
||||
.toRole("bookingItem", AGENT).grantPermission(INSERT)
|
||||
|
||||
.importEntityAlias("parentAsset", HsHostingAssetEntity.class, usingCase(MANAGED_SERVER),
|
||||
.importEntityAlias("parentAsset", HsHostingAssetEntity.class, usingDefaultCase(),
|
||||
dependsOnColumn("parentAssetUuid"),
|
||||
directlyFetchedByDependsOnColumn(),
|
||||
NULLABLE)
|
||||
.toRole("parentAsset", ADMIN).grantPermission(INSERT)
|
||||
|
||||
.importEntityAlias("assignedToAsset", HsHostingAssetEntity.class, usingDefaultCase(),
|
||||
dependsOnColumn("assignedToAssetUuid"),
|
||||
directlyFetchedByDependsOnColumn(),
|
||||
NULLABLE)
|
||||
|
||||
.createRole(OWNER, (with) -> {
|
||||
with.incomingSuperRole("bookingItem", ADMIN);
|
||||
with.incomingSuperRole("parentAsset", ADMIN);
|
||||
@ -160,13 +168,15 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Validata
|
||||
with.incomingSuperRole("parentAsset", AGENT);
|
||||
with.permission(UPDATE);
|
||||
})
|
||||
.createSubRole(AGENT)
|
||||
.createSubRole(AGENT, (with) -> {
|
||||
with.outgoingSubRole("assignedToAsset", TENANT);
|
||||
})
|
||||
.createSubRole(TENANT, (with) -> {
|
||||
with.outgoingSubRole("bookingItem", TENANT);
|
||||
with.outgoingSubRole("parentAsset", TENANT);
|
||||
with.permission(SELECT);
|
||||
})
|
||||
.limitDiagramTo("asset", "bookingItem", "bookingItem.debitorRel", "parentServer", "global");
|
||||
.limitDiagramTo("asset", "bookingItem", "bookingItem.debitorRel", "parentAsset", "assignedToAsset", "global");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
@ -10,9 +10,10 @@ import java.util.UUID;
|
||||
|
||||
public interface HsHostingAssetRepository extends Repository<HsHostingAssetEntity, UUID> {
|
||||
|
||||
List<HsHostingAssetEntity> findAll();
|
||||
Optional<HsHostingAssetEntity> findByUuid(final UUID serverUuid);
|
||||
|
||||
List<HsHostingAssetEntity> findByIdentifier(String assetIdentifier);
|
||||
|
||||
@Query("""
|
||||
SELECT asset FROM HsHostingAssetEntity asset
|
||||
WHERE (:projectUuid IS NULL OR asset.bookingItem.project.uuid = :projectUuid)
|
||||
|
@ -6,11 +6,13 @@ public enum HsHostingAssetType {
|
||||
MANAGED_SERVER, // named e.g. vm1234
|
||||
MANAGED_WEBSPACE(MANAGED_SERVER), // named eg. xyz00
|
||||
UNIX_USER(MANAGED_WEBSPACE), // named e.g. xyz00-abc
|
||||
DOMAIN_SETUP(UNIX_USER), // named e.g. example.org
|
||||
DOMAIN_DNS_SETUP(MANAGED_WEBSPACE), // named e.g. example.org
|
||||
DOMAIN_HTTP_SETUP(MANAGED_WEBSPACE), // named e.g. example.org
|
||||
DOMAIN_EMAIL_SETUP(MANAGED_WEBSPACE), // named e.g. example.org
|
||||
|
||||
// TODO.spec: SECURE_MX
|
||||
EMAIL_ALIAS(MANAGED_WEBSPACE), // named e.g. xyz00-abc
|
||||
EMAIL_ADDRESS(DOMAIN_SETUP), // named e.g. sample@example.org
|
||||
EMAIL_ADDRESS(DOMAIN_EMAIL_SETUP), // named e.g. sample@example.org
|
||||
PGSQL_USER(MANAGED_WEBSPACE), // named e.g. xyz00_abc
|
||||
PGSQL_DATABASE(MANAGED_WEBSPACE), // named e.g. xyz00_abc, TODO.spec: or PGSQL_USER?
|
||||
MARIADB_USER(MANAGED_WEBSPACE), // named e.g. xyz00_abc
|
||||
|
@ -1,20 +0,0 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
||||
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
|
||||
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.validation.IntegerPropertyValidator.integerProperty;
|
||||
|
||||
class HsCloudServerHostingAssetValidator extends HsEntityValidator<HsHostingAssetEntity, HsHostingAssetType> {
|
||||
|
||||
public HsCloudServerHostingAssetValidator() {
|
||||
super(
|
||||
integerProperty("CPUs").min(1).max(32).required(),
|
||||
integerProperty("RAM").unit("GB").min(1).max(128).required(),
|
||||
integerProperty("SSD").unit("GB").min(25).max(1000).step(25).required(),
|
||||
integerProperty("HDD").unit("GB").min(0).max(4000).step(250).optional(),
|
||||
integerProperty("Traffic").unit("GB").min(250).max(10000).step(250).required()
|
||||
);
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ public class HsHostingAssetEntityValidators {
|
||||
|
||||
private static final Map<Enum<HsHostingAssetType>, HsEntityValidator<HsHostingAssetEntity, HsHostingAssetType>> validators = new HashMap<>();
|
||||
static {
|
||||
register(CLOUD_SERVER, new HsCloudServerHostingAssetValidator());
|
||||
register(CLOUD_SERVER, new HsEntityValidator<>());
|
||||
register(MANAGED_SERVER, new HsManagedServerHostingAssetValidator());
|
||||
register(MANAGED_WEBSPACE, new HsManagedWebspaceHostingAssetValidator());
|
||||
}
|
||||
|
@ -10,11 +10,13 @@ class HsManagedServerHostingAssetValidator extends HsEntityValidator<HsHostingAs
|
||||
|
||||
public HsManagedServerHostingAssetValidator() {
|
||||
super(
|
||||
integerProperty("CPUs").min(1).max(32).required(),
|
||||
integerProperty("RAM").unit("GB").min(1).max(128).required(),
|
||||
integerProperty("SSD").unit("GB").min(25).max(1000).step(25).required(),
|
||||
integerProperty("HDD").unit("GB").min(0).max(4000).step(250).optional(),
|
||||
integerProperty("Traffic").unit("GB").min(250).max(10000).step(250).required()
|
||||
integerProperty("monit_min_free_ssd").min(1).max(1000).optional(),
|
||||
integerProperty("monit_min_free_hdd").min(1).max(4000).optional(),
|
||||
integerProperty("monit_max_ssd_usage").unit("%").min(10).max(100).required(),
|
||||
integerProperty("monit_max_hdd_usage").unit("%").min(10).max(100).optional(),
|
||||
integerProperty("monit_max_cpu_usage").unit("%").min(10).max(100).required(),
|
||||
integerProperty("monit_max_ram_usage").unit("%").min(10).max(100).required()
|
||||
// TODO: stringProperty("monit_alarm_email").unit("GB").optional()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,9 @@ import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.validation.IntegerPropertyValidator.integerProperty;
|
||||
|
||||
class HsManagedWebspaceHostingAssetValidator extends HsEntityValidator<HsHostingAssetEntity, HsHostingAssetType> {
|
||||
public HsManagedWebspaceHostingAssetValidator() {
|
||||
super(
|
||||
integerProperty("SSD").unit("GB").min(1).max(100).step(1).required(),
|
||||
integerProperty("HDD").unit("GB").min(0).max(250).step(10).optional(),
|
||||
integerProperty("Traffic").unit("GB").min(10).max(1000).step(10).required()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Reference in New Issue
Block a user