feat(types): tornar tipos configuráveis
- converte entidades de servidores para armazenar type/application/db como texto - adiciona modelo e API para registrar/listar TypeOptions com normalização - centraliza schema/data scripts para criar schema e seedar tipos e usuário padrãomaster
parent
ed247c423e
commit
6d5a64be89
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.hitcommunications.servermanager.controllers;
|
||||||
|
|
||||||
|
import com.hitcommunications.servermanager.model.enums.TypeCategory;
|
||||||
|
import com.hitcommunications.servermanager.services.TypeOptionService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/type-options")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "Type Options")
|
||||||
|
public class TypeOptionsController {
|
||||||
|
|
||||||
|
private final TypeOptionService typeOptionService;
|
||||||
|
|
||||||
|
@GetMapping("/{category}")
|
||||||
|
@Operation(summary = "Lista os valores disponíveis para um tipo de categoria (SERVER_TYPE, APPLICATION, DATABASE).")
|
||||||
|
public ResponseEntity<List<String>> list(@PathVariable TypeCategory category) {
|
||||||
|
return ResponseEntity.ok(typeOptionService.list(category));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,15 +5,10 @@ import java.sql.Timestamp;
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
|
||||||
import com.hitcommunications.servermanager.model.enums.Applications;
|
|
||||||
import com.hitcommunications.servermanager.model.enums.DatabaseType;
|
|
||||||
import com.hitcommunications.servermanager.model.enums.ServersType;
|
|
||||||
import com.hitcommunications.servermanager.utils.ServerIdGenerator;
|
import com.hitcommunications.servermanager.utils.ServerIdGenerator;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.EnumType;
|
|
||||||
import jakarta.persistence.Enumerated;
|
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
@ -51,17 +46,14 @@ public class Servers {
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false, length = 80)
|
||||||
@Enumerated(EnumType.STRING)
|
private String type;
|
||||||
private ServersType type;
|
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false, length = 80)
|
||||||
@Enumerated(EnumType.STRING)
|
private String application;
|
||||||
private Applications application;
|
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false, length = 80, name = "db_type")
|
||||||
@Enumerated(EnumType.STRING)
|
private String dbType;
|
||||||
private DatabaseType dbType;
|
|
||||||
|
|
||||||
@CreationTimestamp
|
@CreationTimestamp
|
||||||
private Timestamp createdAt;
|
private Timestamp createdAt;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.hitcommunications.servermanager.model;
|
||||||
|
|
||||||
|
import com.hitcommunications.servermanager.model.enums.TypeCategory;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "tab_type_options", schema = "server-manager", uniqueConstraints = {
|
||||||
|
@UniqueConstraint(columnNames = {"category", "value"})
|
||||||
|
})
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class TypeOption {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@Column(nullable = false, length = 32)
|
||||||
|
private TypeCategory category;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 80)
|
||||||
|
private String value;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.hitcommunications.servermanager.model.enums;
|
||||||
|
|
||||||
|
public enum TypeCategory {
|
||||||
|
SERVER_TYPE,
|
||||||
|
APPLICATION,
|
||||||
|
DATABASE
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.hitcommunications.servermanager.repositories;
|
||||||
|
|
||||||
|
import com.hitcommunications.servermanager.model.TypeOption;
|
||||||
|
import com.hitcommunications.servermanager.model.enums.TypeCategory;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface TypeOptionRepository extends JpaRepository<TypeOption, Long> {
|
||||||
|
Optional<TypeOption> findByCategoryAndValue(TypeCategory category, String value);
|
||||||
|
List<TypeOption> findAllByCategoryOrderByValueAsc(TypeCategory category);
|
||||||
|
}
|
||||||
|
|
@ -29,8 +29,6 @@ public class ServersService {
|
||||||
private final ServersRepository repo;
|
private final ServersRepository repo;
|
||||||
|
|
||||||
public ServerDTO create(NewServerDTO createDTO) {
|
public ServerDTO create(NewServerDTO createDTO) {
|
||||||
ensureUniqueIpAndPort(createDTO.ip(), createDTO.port(), null);
|
|
||||||
|
|
||||||
Servers entity = mapper.toEntity(createDTO);
|
Servers entity = mapper.toEntity(createDTO);
|
||||||
entity = repo.save(entity);
|
entity = repo.save(entity);
|
||||||
return mapper.toDTO(entity);
|
return mapper.toDTO(entity);
|
||||||
|
|
@ -166,8 +164,6 @@ public class ServersService {
|
||||||
Servers entity = repo.findById(id)
|
Servers entity = repo.findById(id)
|
||||||
.orElseThrow(() -> new RuntimeException("Server not found with id: " + id));
|
.orElseThrow(() -> new RuntimeException("Server not found with id: " + id));
|
||||||
|
|
||||||
ensureUniqueIpAndPort(updateDTO.ip(), updateDTO.port(), id);
|
|
||||||
|
|
||||||
mapper.partialUpdate(updateDTO, entity);
|
mapper.partialUpdate(updateDTO, entity);
|
||||||
entity = repo.save(entity);
|
entity = repo.save(entity);
|
||||||
return mapper.toDTO(entity);
|
return mapper.toDTO(entity);
|
||||||
|
|
@ -180,11 +176,4 @@ public class ServersService {
|
||||||
repo.deleteById(id);
|
repo.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureUniqueIpAndPort(String ip, Integer port, String currentServerId) {
|
|
||||||
repo.findByIpAndPort(ip, port).ifPresent(existingServer -> {
|
|
||||||
if (currentServerId == null || !existingServer.getId().equals(currentServerId)) {
|
|
||||||
throw new RuntimeException("Server already exists with IP: " + ip + " and port: " + port);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.hitcommunications.servermanager.services;
|
||||||
|
|
||||||
|
import com.hitcommunications.servermanager.model.TypeOption;
|
||||||
|
import com.hitcommunications.servermanager.model.enums.TypeCategory;
|
||||||
|
import com.hitcommunications.servermanager.repositories.TypeOptionRepository;
|
||||||
|
import com.hitcommunications.servermanager.utils.TypeNormalizer;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TypeOptionService {
|
||||||
|
|
||||||
|
private final TypeOptionRepository repository;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void register(TypeCategory category, String rawValue) {
|
||||||
|
String normalized = TypeNormalizer.normalize(rawValue);
|
||||||
|
if (normalized == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
repository.findByCategoryAndValue(category, normalized)
|
||||||
|
.orElseGet(() -> repository.save(
|
||||||
|
TypeOption.builder()
|
||||||
|
.category(category)
|
||||||
|
.value(normalized)
|
||||||
|
.build()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> list(TypeCategory category) {
|
||||||
|
return repository.findAllByCategoryOrderByValueAsc(category)
|
||||||
|
.stream()
|
||||||
|
.map(TypeOption::getValue)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.hitcommunications.servermanager.utils;
|
||||||
|
|
||||||
|
import java.text.Normalizer;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public final class TypeNormalizer {
|
||||||
|
|
||||||
|
private static final Pattern DIACRITICS = Pattern.compile("\\p{M}");
|
||||||
|
|
||||||
|
private TypeNormalizer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String normalize(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String trimmed = value.trim();
|
||||||
|
if (trimmed.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String normalized = Normalizer.normalize(trimmed, Normalizer.Form.NFD);
|
||||||
|
normalized = DIACRITICS.matcher(normalized).replaceAll("");
|
||||||
|
normalized = normalized.replaceAll("[^A-Za-z0-9_\\- ]", "");
|
||||||
|
normalized = normalized.replaceAll("\\s+", "_");
|
||||||
|
return normalized.toUpperCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ spring:
|
||||||
init:
|
init:
|
||||||
mode: always
|
mode: always
|
||||||
schema-locations: classpath:schema.sql
|
schema-locations: classpath:schema.sql
|
||||||
|
data-locations: classpath:data.sql
|
||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
|
url: jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,26 @@ INSERT INTO "server-manager".tab_users (
|
||||||
CURRENT_TIMESTAMP
|
CURRENT_TIMESTAMP
|
||||||
)
|
)
|
||||||
ON CONFLICT DO NOTHING;
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
INSERT INTO "server-manager".tab_type_options (id, category, value)
|
||||||
|
VALUES
|
||||||
|
(101, 'SERVER_TYPE', 'PRODUCTION'),
|
||||||
|
(102, 'SERVER_TYPE', 'HOMOLOGATION'),
|
||||||
|
(103, 'SERVER_TYPE', 'DATABASE'),
|
||||||
|
(201, 'APPLICATION', 'ASTERISK'),
|
||||||
|
(202, 'APPLICATION', 'HITMANAGER'),
|
||||||
|
(203, 'APPLICATION', 'HITMANAGER_V2'),
|
||||||
|
(204, 'APPLICATION', 'OMNIHIT'),
|
||||||
|
(205, 'APPLICATION', 'HITPHONE'),
|
||||||
|
(206, 'APPLICATION', 'CDR'),
|
||||||
|
(207, 'APPLICATION', 'FUNCIONALIDADE'),
|
||||||
|
(208, 'APPLICATION', 'VOICEMAIL'),
|
||||||
|
(301, 'DATABASE', 'MYSQL'),
|
||||||
|
(302, 'DATABASE', 'POSTGRESQL'),
|
||||||
|
(303, 'DATABASE', 'SQLSERVER'),
|
||||||
|
(304, 'DATABASE', 'ORACLE'),
|
||||||
|
(305, 'DATABASE', 'REDIS'),
|
||||||
|
(306, 'DATABASE', 'MONGODB'),
|
||||||
|
(307, 'DATABASE', 'MARIADB'),
|
||||||
|
(308, 'DATABASE', 'NONE')
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
CREATE SCHEMA IF NOT EXISTS "server-manager";
|
CREATE SCHEMA IF NOT EXISTS "server-manager";
|
||||||
|
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue