diff --git a/openex-model/pom.xml b/openex-model/pom.xml
index 04aec32176..4286ac3d48 100644
--- a/openex-model/pom.xml
+++ b/openex-model/pom.xml
@@ -13,6 +13,11 @@
OpenEx model
OpenEx model
+
+ 1.7
+ 1.18.26
+
+
org.springframework.boot
@@ -52,5 +57,16 @@
validation-api
${validation-api.version}
+
+ commons-validator
+ commons-validator
+ ${commons-validator.version}
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
diff --git a/openex-model/src/main/java/io/openex/annotation/Ipv4OrIpv6Constraint.java b/openex-model/src/main/java/io/openex/annotation/Ipv4OrIpv6Constraint.java
new file mode 100644
index 0000000000..dc4507f1c5
--- /dev/null
+++ b/openex-model/src/main/java/io/openex/annotation/Ipv4OrIpv6Constraint.java
@@ -0,0 +1,24 @@
+package io.openex.annotation;
+
+import io.openex.validator.Ipv4OrIpv6Validator;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import javax.validation.ReportAsSingleViolation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Target(FIELD)
+@Retention(RUNTIME)
+@Constraint(validatedBy = Ipv4OrIpv6Validator.class)
+@ReportAsSingleViolation
+public @interface Ipv4OrIpv6Constraint {
+ String message() default "must be ipv4 or ipv6";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+}
diff --git a/openex-model/src/main/java/io/openex/database/audit/ModelBaseListener.java b/openex-model/src/main/java/io/openex/database/audit/ModelBaseListener.java
index 5380c8f1d5..e502f103f7 100644
--- a/openex-model/src/main/java/io/openex/database/audit/ModelBaseListener.java
+++ b/openex-model/src/main/java/io/openex/database/audit/ModelBaseListener.java
@@ -45,6 +45,7 @@ void postUpdate(Object base) {
@PreRemove
void preRemove(Object base) {
Base instance = (Base) base;
- appPublisher.publishEvent(new BaseEvent(DATA_DELETE, instance, mapper));
+ BaseEvent event = new BaseEvent(DATA_DELETE, instance, mapper);
+ appPublisher.publishEvent(event);
}
}
diff --git a/openex-model/src/main/java/io/openex/database/model/System.java b/openex-model/src/main/java/io/openex/database/model/System.java
new file mode 100644
index 0000000000..07c99e9477
--- /dev/null
+++ b/openex-model/src/main/java/io/openex/database/model/System.java
@@ -0,0 +1,78 @@
+package io.openex.database.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import io.openex.annotation.Ipv4OrIpv6Constraint;
+import io.openex.database.audit.ModelBaseListener;
+import io.openex.helper.MultiIdDeserializer;
+import lombok.Getter;
+import lombok.Setter;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.time.Instant.now;
+
+@Getter
+@Setter
+@Entity
+@Table(name = "systems")
+@EntityListeners(ModelBaseListener.class)
+public class System implements Base {
+
+ public enum SYSTEM_TYPE {
+ ENDPOINT,
+ WEBSITE,
+ }
+
+ public enum OS_TYPE {
+ LINUX,
+ WINDOWS,
+ }
+
+ @Id
+ @Column(name = "system_id")
+ @GeneratedValue(generator = "UUID")
+ @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
+ @JsonProperty("system_id")
+ private String id;
+
+ @Column(name = "system_created_at")
+ @JsonProperty("system_created_at")
+ private Instant createdAt = now();
+
+ @Column(name = "system_updated_at")
+ @JsonProperty("system_updated_at")
+ private Instant updatedAt = now();
+
+ @Column(name = "system_name")
+ @JsonProperty("system_name")
+ private String name;
+
+ @Column(name = "system_type")
+ @JsonProperty("system_type")
+ @Enumerated(EnumType.STRING)
+ private SYSTEM_TYPE type;
+
+ @Ipv4OrIpv6Constraint
+ @Column(name = "system_ip")
+ @JsonProperty("system_ip")
+ private String ip;
+
+ @Column(name = "system_hostname")
+ @JsonProperty("system_hostname")
+ private String hostname;
+
+ @Column(name = "system_os")
+ @JsonProperty("system_os")
+ @Enumerated(EnumType.STRING)
+ private OS_TYPE os;
+
+ @ManyToMany(mappedBy = "systems", fetch = FetchType.LAZY)
+ @JsonSerialize(using = MultiIdDeserializer.class)
+ @JsonProperty("system_zones")
+ private List zones = new ArrayList<>();
+}
diff --git a/openex-model/src/main/java/io/openex/database/model/User.java b/openex-model/src/main/java/io/openex/database/model/User.java
index 5786c32316..d60717b111 100644
--- a/openex-model/src/main/java/io/openex/database/model/User.java
+++ b/openex-model/src/main/java/io/openex/database/model/User.java
@@ -218,7 +218,8 @@ public boolean isPlanner() {
@JsonProperty("user_is_observer")
public boolean isObserver() {
return isAdmin() || getGroups().stream()
- .mapToLong(group -> group.getGrants().size()).sum() > 0;
+ .flatMap(group -> group.getGrants().stream())
+ .anyMatch(grant -> Grant.GRANT_TYPE.OBSERVER.equals(grant.getName()));
}
@JsonProperty("user_is_manager")
diff --git a/openex-model/src/main/java/io/openex/database/model/Zone.java b/openex-model/src/main/java/io/openex/database/model/Zone.java
new file mode 100644
index 0000000000..d414335c2d
--- /dev/null
+++ b/openex-model/src/main/java/io/openex/database/model/Zone.java
@@ -0,0 +1,56 @@
+package io.openex.database.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import io.openex.annotation.Ipv4OrIpv6Constraint;
+import io.openex.database.audit.ModelBaseListener;
+import io.openex.helper.MultiIdDeserializer;
+import lombok.Getter;
+import lombok.Setter;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.time.Instant.now;
+
+@Getter
+@Setter
+@Entity
+@Table(name = "zones")
+@EntityListeners(ModelBaseListener.class)
+public class Zone implements Base {
+
+ @Id
+ @Column(name = "zone_id")
+ @GeneratedValue(generator = "UUID")
+ @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
+ @JsonProperty("zone_id")
+ private String id;
+
+ @Column(name = "zone_name")
+ @JsonProperty("zone_name")
+ private String name;
+
+ @Column(name = "zone_description")
+ @JsonProperty("zone_description")
+ private String description;
+
+ @Column(name = "zone_created_at")
+ @JsonProperty("zone_created_at")
+ private Instant createdAt = now();
+
+ @Column(name = "zone_updated_at")
+ @JsonProperty("zone_updated_at")
+ private Instant updatedAt = now();
+
+ @ManyToMany(fetch = FetchType.LAZY)
+ @JoinTable(name = "systems_zones",
+ joinColumns = @JoinColumn(name = "zone_id"),
+ inverseJoinColumns = @JoinColumn(name = "system_id"))
+ @JsonSerialize(using = MultiIdDeserializer.class)
+ @JsonProperty("zone_systems")
+ private List systems = new ArrayList<>();
+}
diff --git a/openex-model/src/main/java/io/openex/database/repository/SystemRepository.java b/openex-model/src/main/java/io/openex/database/repository/SystemRepository.java
new file mode 100644
index 0000000000..82d866fd00
--- /dev/null
+++ b/openex-model/src/main/java/io/openex/database/repository/SystemRepository.java
@@ -0,0 +1,8 @@
+package io.openex.database.repository;
+
+import io.openex.database.model.System;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface SystemRepository extends CrudRepository { }
diff --git a/openex-model/src/main/java/io/openex/database/repository/ZoneRepository.java b/openex-model/src/main/java/io/openex/database/repository/ZoneRepository.java
new file mode 100644
index 0000000000..45fa3cae1a
--- /dev/null
+++ b/openex-model/src/main/java/io/openex/database/repository/ZoneRepository.java
@@ -0,0 +1,8 @@
+package io.openex.database.repository;
+
+import io.openex.database.model.Zone;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ZoneRepository extends CrudRepository { }
diff --git a/openex-model/src/main/java/io/openex/validator/Ipv4OrIpv6Validator.java b/openex-model/src/main/java/io/openex/validator/Ipv4OrIpv6Validator.java
new file mode 100644
index 0000000000..df350e6fee
--- /dev/null
+++ b/openex-model/src/main/java/io/openex/validator/Ipv4OrIpv6Validator.java
@@ -0,0 +1,21 @@
+package io.openex.validator;
+
+import io.openex.annotation.Ipv4OrIpv6Constraint;
+import org.apache.commons.validator.routines.InetAddressValidator;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class Ipv4OrIpv6Validator implements ConstraintValidator {
+
+ @Override
+ public void initialize(Ipv4OrIpv6Constraint ip) {
+ }
+
+ @Override
+ public boolean isValid(String ip, ConstraintValidatorContext cxt) {
+ InetAddressValidator validator = InetAddressValidator.getInstance();
+ return validator.isValid(ip);
+ }
+
+}