feat(servers): permitir tipos vindos do banco

- remove enums fixos de tipo, aplicação e dbType
- atualiza DTOs, controller e repositório para lidar com strings normalizadas
- normaliza e registra tipos durante criação e importação em massa
master
Artur Oliveira 2025-12-16 18:09:40 -03:00
parent bba78772db
commit a43fc58ff7
8 changed files with 89 additions and 80 deletions

View File

@ -3,9 +3,6 @@ package com.hitcommunications.servermanager.controllers;
import com.hitcommunications.servermanager.model.dtos.BulkServerImportResponse; import com.hitcommunications.servermanager.model.dtos.BulkServerImportResponse;
import com.hitcommunications.servermanager.model.dtos.NewServerDTO; import com.hitcommunications.servermanager.model.dtos.NewServerDTO;
import com.hitcommunications.servermanager.model.dtos.ServerDTO; import com.hitcommunications.servermanager.model.dtos.ServerDTO;
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.services.ServersService; import com.hitcommunications.servermanager.services.ServersService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponse;
@ -72,14 +69,14 @@ public class ServersController {
@GetMapping("/type/{type}") @GetMapping("/type/{type}")
@Operation(summary = "Lista servidores por tipo.") @Operation(summary = "Lista servidores por tipo.")
@ApiResponse(responseCode = "200", description = "Lista retornada.") @ApiResponse(responseCode = "200", description = "Lista retornada.")
public ResponseEntity<List<ServerDTO>> getByType(@PathVariable ServersType type) { public ResponseEntity<List<ServerDTO>> getByType(@PathVariable String type) {
return ResponseEntity.ok().body(serversService.getByType(type)); return ResponseEntity.ok().body(serversService.getByType(type));
} }
@GetMapping("/type") @GetMapping("/type")
@Operation(summary = "Conta servidores agrupando por tipo.") @Operation(summary = "Conta servidores agrupando por tipo.")
@ApiResponse(responseCode = "200", description = "Mapa retornado.") @ApiResponse(responseCode = "200", description = "Mapa retornado.")
public ResponseEntity<Map<ServersType, Integer>> countAllByType() { public ResponseEntity<Map<String, Integer>> countAllByType() {
return ResponseEntity.ok().body(serversService.countAllByType()); return ResponseEntity.ok().body(serversService.countAllByType());
} }
@ -96,7 +93,7 @@ public class ServersController {
@GetMapping("/application/{application}") @GetMapping("/application/{application}")
@Operation(summary = "Lista servidores por aplicação.") @Operation(summary = "Lista servidores por aplicação.")
@ApiResponse(responseCode = "200", description = "Lista retornada.") @ApiResponse(responseCode = "200", description = "Lista retornada.")
public ResponseEntity<List<ServerDTO>> getByApplication(@PathVariable Applications application) { public ResponseEntity<List<ServerDTO>> getByApplication(@PathVariable String application) {
return ResponseEntity.ok().body(serversService.getByApplication(application)); return ResponseEntity.ok().body(serversService.getByApplication(application));
} }
@ -105,9 +102,9 @@ public class ServersController {
@ApiResponse(responseCode = "200", description = "Resultados retornados.") @ApiResponse(responseCode = "200", description = "Resultados retornados.")
public ResponseEntity<List<ServerDTO>> getAll( public ResponseEntity<List<ServerDTO>> getAll(
@RequestParam(value = "query", required = false) String query, @RequestParam(value = "query", required = false) String query,
@RequestParam(value = "type", required = false) ServersType type, @RequestParam(value = "type", required = false) String type,
@RequestParam(value = "application", required = false) Applications application, @RequestParam(value = "application", required = false) String application,
@RequestParam(value = "dbType", required = false) DatabaseType dbType @RequestParam(value = "dbType", required = false) String dbType
) { ) {
return ResponseEntity.ok().body(serversService.search(query, type, application, dbType)); return ResponseEntity.ok().body(serversService.search(query, type, application, dbType));
} }

View File

@ -1,8 +1,5 @@
package com.hitcommunications.servermanager.model.dtos; package com.hitcommunications.servermanager.model.dtos;
import com.hitcommunications.servermanager.model.enums.Applications;
import com.hitcommunications.servermanager.model.enums.DatabaseType;
import com.hitcommunications.servermanager.model.enums.ServersType;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
@ -12,9 +9,8 @@ public record NewServerDTO(
@NotNull Integer port, @NotNull Integer port,
@NotBlank String user, @NotBlank String user,
@NotBlank String password, @NotBlank String password,
@NotNull ServersType type, @NotBlank String type,
@NotNull Applications application, @NotBlank String application,
@NotNull DatabaseType dbType @NotBlank String dbType
) { ) {
} }

View File

@ -1,9 +1,5 @@
package com.hitcommunications.servermanager.model.dtos; package com.hitcommunications.servermanager.model.dtos;
import com.hitcommunications.servermanager.model.enums.Applications;
import com.hitcommunications.servermanager.model.enums.DatabaseType;
import com.hitcommunications.servermanager.model.enums.ServersType;
import java.sql.Timestamp; import java.sql.Timestamp;
public record ServerDTO( public record ServerDTO(
@ -13,9 +9,9 @@ public record ServerDTO(
Integer port, Integer port,
String user, String user,
String password, String password,
ServersType type, String type,
Applications application, String application,
DatabaseType dbType, String dbType,
Timestamp createdAt, Timestamp createdAt,
Timestamp updatedAt Timestamp updatedAt
) { ) {

View File

@ -1,12 +0,0 @@
package com.hitcommunications.servermanager.model.enums;
public enum Applications {
ASTERISK,
HITMANAGER,
HITMANAGER_V2,
OMNIHIT,
HITPHONE,
CDR,
FUNCIONALIDADE,
VOICEMAIL
}

View File

@ -1,12 +0,0 @@
package com.hitcommunications.servermanager.model.enums;
public enum DatabaseType {
MYSQL,
POSTGRESQL,
SQLSERVER,
ORACLE,
REDIS,
MONGODB,
MARIADB,
NONE
}

View File

@ -1,7 +0,0 @@
package com.hitcommunications.servermanager.model.enums;
public enum ServersType {
PRODUCTION,
HOMOLOGATION,
DATABASE
}

View File

@ -8,16 +8,12 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import com.hitcommunications.servermanager.model.Servers; import com.hitcommunications.servermanager.model.Servers;
import com.hitcommunications.servermanager.model.enums.Applications;
import com.hitcommunications.servermanager.model.enums.DatabaseType;
import com.hitcommunications.servermanager.model.enums.ServersType;
public interface ServersRepository extends JpaRepository<Servers, String> { public interface ServersRepository extends JpaRepository<Servers, String> {
Optional<Servers> findByName(String name); Optional<Servers> findByName(String name);
List<Servers> findByType(ServersType type); List<Servers> findByType(String type);
List<Servers> findByApplication(Applications application); List<Servers> findByApplication(String application);
Optional<Servers> findByIpAndPort(String ip, Integer port); Optional<Servers> findByIpAndPort(String ip, Integer port);
Integer countAllByType(ServersType type); Integer countAllByType(String type);
@Query(value = """ @Query(value = """
select s.* from "server-manager".tab_servers s select s.* from "server-manager".tab_servers s

View File

@ -6,10 +6,10 @@ import com.hitcommunications.servermanager.model.dtos.BulkServerImportResponse;
import com.hitcommunications.servermanager.model.dtos.BulkServerImportResponse.FailedRow; import com.hitcommunications.servermanager.model.dtos.BulkServerImportResponse.FailedRow;
import com.hitcommunications.servermanager.model.dtos.NewServerDTO; import com.hitcommunications.servermanager.model.dtos.NewServerDTO;
import com.hitcommunications.servermanager.model.dtos.ServerDTO; import com.hitcommunications.servermanager.model.dtos.ServerDTO;
import com.hitcommunications.servermanager.model.enums.Applications; import com.hitcommunications.servermanager.model.enums.TypeCategory;
import com.hitcommunications.servermanager.model.enums.DatabaseType;
import com.hitcommunications.servermanager.model.enums.ServersType;
import com.hitcommunications.servermanager.repositories.ServersRepository; import com.hitcommunications.servermanager.repositories.ServersRepository;
import com.hitcommunications.servermanager.services.TypeOptionService;
import com.hitcommunications.servermanager.utils.TypeNormalizer;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -18,18 +18,20 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class ServersService { public class ServersService {
private final ServersMapper mapper; private final ServersMapper mapper;
private final ServersRepository repo; private final ServersRepository repo;
private final TypeOptionService typeOptionService;
public ServerDTO create(NewServerDTO createDTO) { public ServerDTO create(NewServerDTO createDTO) {
Servers entity = mapper.toEntity(createDTO); Servers entity = mapper.toEntity(createDTO);
applyNormalizedTypeData(entity, createDTO);
entity = repo.save(entity); entity = repo.save(entity);
return mapper.toDTO(entity); return mapper.toDTO(entity);
} }
@ -46,25 +48,34 @@ public class ServersService {
.orElseThrow(() -> new RuntimeException("Server not found with name: " + name)); .orElseThrow(() -> new RuntimeException("Server not found with name: " + name));
} }
public List<ServerDTO> getByType(ServersType type) { public List<ServerDTO> getByType(String type) {
return repo.findByType(type) String normalized = normalizeFilter(type, TypeCategory.SERVER_TYPE);
return repo.findByType(normalized)
.stream() .stream()
.map(mapper::toDTO) .map(mapper::toDTO)
.toList(); .toList();
} }
public Map<ServersType, Integer> countAllByType() { public Map<String, Integer> countAllByType() {
Map<ServersType, Integer> response = new HashMap<>(); Map<String, Integer> response = new LinkedHashMap<>();
for(ServersType type : ServersType.values()) { typeOptionService.list(TypeCategory.SERVER_TYPE).forEach(type -> {
response.put(type, repo.countAllByType(type)); response.put(type, repo.countAllByType(type));
} });
// Garantir que valores existentes, mas não registrados, também apareçam
repo.findAll().stream()
.map(Servers::getType)
.filter(type -> type != null && !response.containsKey(type))
.distinct()
.forEach(type -> response.put(type, repo.countAllByType(type)));
return response; return response;
} }
public List<ServerDTO> getByApplication(Applications application) { public List<ServerDTO> getByApplication(String application) {
return repo.findByApplication(application) String normalized = normalizeFilter(application, TypeCategory.APPLICATION);
return repo.findByApplication(normalized)
.stream() .stream()
.map(mapper::toDTO) .map(mapper::toDTO)
.toList(); .toList();
@ -91,6 +102,7 @@ public class ServersService {
processed++; processed++;
try { try {
registerTypeOptionsFromRow(columns);
NewServerDTO dto = toNewServerDTO(columns); NewServerDTO dto = toNewServerDTO(columns);
create(dto); create(dto);
succeeded++; succeeded++;
@ -125,13 +137,29 @@ public class ServersService {
Integer port = Integer.parseInt(columns[2]); Integer port = Integer.parseInt(columns[2]);
String user = columns[3]; String user = columns[3];
String password = columns[4]; String password = columns[4];
ServersType type = ServersType.valueOf(columns[5].toUpperCase()); String type = columns[5];
Applications application = Applications.valueOf(columns[6].toUpperCase()); String application = columns[6];
DatabaseType dbType = DatabaseType.valueOf(columns[7].toUpperCase()); String dbType = columns[7];
return new NewServerDTO(name, ip, port, user, password, type, application, dbType); return new NewServerDTO(name, ip, port, user, password, type, application, dbType);
} }
private void registerTypeOptionsFromRow(String[] columns) {
if (columns.length < 8) {
return;
}
registerTypeOption(TypeCategory.SERVER_TYPE, columns[5]);
registerTypeOption(TypeCategory.APPLICATION, columns[6]);
registerTypeOption(TypeCategory.DATABASE, columns[7]);
}
private void registerTypeOption(TypeCategory category, String value) {
if (value == null || value.isBlank()) {
return;
}
typeOptionService.register(category, value);
}
private boolean isHeaderRow(String[] columns) { private boolean isHeaderRow(String[] columns) {
if (columns.length < 8) { if (columns.length < 8) {
return false; return false;
@ -148,11 +176,11 @@ public class ServersService {
.toList(); .toList();
} }
public List<ServerDTO> search(String query, ServersType type, Applications application, DatabaseType dbType) { public List<ServerDTO> search(String query, String type, String application, String dbType) {
String normalizedQuery = (query == null || query.isBlank()) ? null : query.trim(); String normalizedQuery = (query == null || query.isBlank()) ? null : query.trim();
String typeFilter = type != null ? type.name() : null; String typeFilter = normalizeFilter(type, TypeCategory.SERVER_TYPE);
String applicationFilter = application != null ? application.name() : null; String applicationFilter = normalizeFilter(application, TypeCategory.APPLICATION);
String dbTypeFilter = dbType != null ? dbType.name() : null; String dbTypeFilter = normalizeFilter(dbType, TypeCategory.DATABASE);
return repo.search(normalizedQuery, typeFilter, applicationFilter, dbTypeFilter) return repo.search(normalizedQuery, typeFilter, applicationFilter, dbTypeFilter)
.stream() .stream()
@ -165,6 +193,7 @@ public class ServersService {
.orElseThrow(() -> new RuntimeException("Server not found with id: " + id)); .orElseThrow(() -> new RuntimeException("Server not found with id: " + id));
mapper.partialUpdate(updateDTO, entity); mapper.partialUpdate(updateDTO, entity);
applyNormalizedTypeData(entity, updateDTO);
entity = repo.save(entity); entity = repo.save(entity);
return mapper.toDTO(entity); return mapper.toDTO(entity);
} }
@ -176,4 +205,30 @@ public class ServersService {
repo.deleteById(id); repo.deleteById(id);
} }
private void applyNormalizedTypeData(Servers entity, NewServerDTO dto) {
entity.setType(normalizeAndRegister(TypeCategory.SERVER_TYPE, dto.type()));
entity.setApplication(normalizeAndRegister(TypeCategory.APPLICATION, dto.application()));
entity.setDbType(normalizeAndRegister(TypeCategory.DATABASE, dto.dbType()));
}
private String normalizeFilter(String value, TypeCategory category) {
if (value == null || value.isBlank()) {
return null;
}
String normalized = TypeNormalizer.normalize(value);
if (normalized == null) {
return null;
}
typeOptionService.register(category, normalized);
return normalized;
}
private String normalizeAndRegister(TypeCategory category, String value) {
String normalized = TypeNormalizer.normalize(value);
if (normalized == null) {
throw new IllegalArgumentException("Valor inválido para " + category.name());
}
typeOptionService.register(category, normalized);
return normalized;
}
} }