Skip to content

Commit

Permalink
Merge pull request #38 from LabGraphTeam/release
Browse files Browse the repository at this point in the history
These changes improve the maintainability and robustness of the codebase.
  • Loading branch information
LeonardoMeireles55 authored Feb 9, 2025
2 parents eb1dd09 + e6f18e6 commit bd718b6
Show file tree
Hide file tree
Showing 23 changed files with 585 additions and 469 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
Expand All @@ -12,19 +13,19 @@

@Configuration
@OpenAPIDefinition
@Profile("!prod")
public class SpringDocConfiguration {
@Bean
OpenAPI customOpenAPI() {
return new OpenAPI()
.components(new Components().addSecuritySchemes("bearer-key",
new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer")
.bearerFormat("JWT")))
.info(new Info().title("QualityLab-Pro API").version("2.0").description(
"REST API for operations on analytical test specifications and internal "
+ "control data")
.contact(new Contact().name("Leonardo Meireles")
.email("[email protected]"))
.license(new License().name("Apache 2.0")
.url("http://labutilities/api/license")));
}
@Bean
OpenAPI customOpenAPI() {
return new OpenAPI().components(new Components().addSecuritySchemes("bearer-key",
new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer")
.bearerFormat("JWT")))
.info(new Info().title("QualityLab-Pro API").version("2.0")
.description("REST API for operations on analytical test specifications and internal "
+ "control data")
.contact(new Contact().name("Leonardo Meireles")
.email("[email protected]"))
.license(new License().name("Apache 2.0").url(
"http://labutilities/api/license")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
import jakarta.validation.constraints.NotNull;
import leonardo.labutilities.qualitylabpro.entities.Analytic;


public record AnalyticsDTO(Long id,
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @NotNull LocalDateTime date,
@NotNull String level_lot, @NotNull String test_lot, @NotNull String name,
@NotNull String level, @NotNull Double value, @NotNull Double mean, @NotNull Double sd,
@NotNull String unit_value, String rules, String description) {

public AnalyticsDTO(Analytic analytic) {
this(analytic.getId(), analytic.getDate(), analytic.getLevelLot(), analytic.getTestLot(),
analytic.getName(), analytic.getLevel(), analytic.getValue(), analytic.getMean(),
analytic.getSd(), analytic.getUnitValue(), analytic.getRules(),
analytic.getDescription());

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Transient;
import leonardo.labutilities.qualitylabpro.dtos.analytics.AnalyticsDTO;
import leonardo.labutilities.qualitylabpro.utils.components.RulesValidatorComponent;
import leonardo.labutilities.qualitylabpro.utils.mappers.AnalyticMapper;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
Expand All @@ -36,42 +35,51 @@ public class Analytic extends RepresentationModel<Analytic> {
private String unitValue;
private String rules;
private String description;
@Transient
private RulesValidatorComponent rulesValidatorComponent;
// @Transient
// private RulesValidatorComponent rulesValidatorComponent;

public Analytic() {}

public Analytic(Long id, LocalDateTime date, String levelLot, String testLot, String name,
String level, double value, double mean, double sd, String unitValue, String rules,
String description, RulesValidatorComponent rulesValidatorComponent) {
this.id = id;
this.date = date;
this.levelLot = levelLot;
this.testLot = testLot;
this.name = name;
this.level = level;
this.value = value;
this.mean = mean;
this.sd = sd;
this.unitValue = unitValue;
this.rules = rules;
this.description = description;
this.rulesValidatorComponent = rulesValidatorComponent;
public Analytic(AnalyticsDTO values) {
AnalyticMapper.toNewEntity(values);
}

public Analytic(AnalyticsDTO values, RulesValidatorComponent rulesValidatorComponent) {
this.date = values.date();
this.levelLot = values.level_lot();
this.testLot = values.test_lot();
this.name = values.name();
this.level = values.level();
this.value = values.value();
this.mean = values.mean();
this.sd = values.sd();
this.unitValue = values.unit_value();
this.rulesValidatorComponent = rulesValidatorComponent;
rulesValidatorComponent.validator(this.value, this.mean, this.sd);
this.rules = rulesValidatorComponent.getRules();
this.description = rulesValidatorComponent.getDescription();
}
// public Analytic(AnalyticsDTO values, RulesValidatorComponent rulesValidatorComponent) {
// AnalyticMapper.toEntity(values, rulesValidatorComponent);
// }

// public Analytic(Long id, LocalDateTime date, String levelLot, String testLot, String name,
// String level, double value, double mean, double sd, String unitValue, String rules,
// String description, RulesValidatorComponent rulesValidatorComponent) {
// this.id = id;
// this.date = date;
// this.levelLot = levelLot;
// this.testLot = testLot;
// this.name = name;
// this.level = level;
// this.value = value;
// this.mean = mean;
// this.sd = sd;
// this.unitValue = unitValue;
// this.rules = rules;
// this.description = description;
// this.rulesValidatorComponent = rulesValidatorComponent;
// }

// public Analytic(AnalyticsDTO values, RulesValidatorComponent rulesValidatorComponent) {
// this.date = values.date();
// this.levelLot = values.level_lot();
// this.testLot = values.test_lot();
// this.name = values.name();
// this.level = values.level();
// this.value = values.value();
// this.mean = values.mean();
// this.sd = values.sd();
// this.unitValue = values.unit_value();
// this.rulesValidatorComponent = rulesValidatorComponent;
// rulesValidatorComponent.validator(this.value, this.mean, this.sd);
// this.rules = rulesValidatorComponent.getRules();
// this.description = rulesValidatorComponent.getDescription();
// }
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package leonardo.labutilities.qualitylabpro.services.analytics;

import static leonardo.labutilities.qualitylabpro.utils.blacklist.AnalyticsBlackList.BLACK_LIST;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
Expand All @@ -18,8 +17,10 @@
import leonardo.labutilities.qualitylabpro.dtos.analytics.GroupedResultsByLevelDTO;
import leonardo.labutilities.qualitylabpro.dtos.analytics.GroupedValuesByLevelDTO;
import leonardo.labutilities.qualitylabpro.dtos.analytics.MeanAndStdDeviationDTO;
import leonardo.labutilities.qualitylabpro.entities.Analytic;
import leonardo.labutilities.qualitylabpro.repositories.AnalyticsRepository;
import leonardo.labutilities.qualitylabpro.services.email.EmailService;
import leonardo.labutilities.qualitylabpro.utils.blacklist.AnalyticsBlackList;
import leonardo.labutilities.qualitylabpro.utils.components.ControlRulesValidators;
import leonardo.labutilities.qualitylabpro.utils.exception.CustomGlobalErrorHandling;
import leonardo.labutilities.qualitylabpro.utils.mappers.AnalyticMapper;
Expand All @@ -41,6 +42,9 @@ protected AbstractAnalyticHelperService(AnalyticsRepository analyticsRepository,
this.controlRulesValidators = controlRulesValidators;
}

// ABSTRACT METHODS
public abstract String convertLevel(String level);

// VALIDATION METHODS
private static void validateResultsNotEmpty(List<?> results, String message) {
if (results == null || results.isEmpty()) {
Expand All @@ -53,8 +57,8 @@ public boolean isAnalyticsNonExistent(AnalyticsDTO values) {
values.name());
}

private static boolean isRuleBroken(AnalyticsDTO analyticsDTO) {
String rules = analyticsDTO.rules();
private static boolean isRuleBroken(Analytic analytic) {
String rules = analytic.getRules();
return ("+3s".equals(rules) || "-3s".equals(rules) || "-2s".equals(rules)
|| "+2s".equals(rules));
}
Expand All @@ -67,9 +71,10 @@ public void ensureNameExists(String name) {
}


private static List<AnalyticsDTO> filterFailedRecords(List<AnalyticsDTO> persistedRecords) {
return persistedRecords.stream().filter(AbstractAnalyticHelperService::isRuleBroken)
.filter(analyticsDTO -> !BLACK_LIST.contains(analyticsDTO.name())).toList();
private static List<Analytic> filterFailedRecords(List<Analytic> persistedRecords) {
return persistedRecords.stream().filter(AbstractAnalyticHelperService::isRuleBroken).filter(
analyticsDTO -> !AnalyticsBlackList.BLACK_LIST.contains(analyticsDTO.getName()))
.toList();
}

@Async
Expand Down Expand Up @@ -210,18 +215,19 @@ public AnalyticsDTO findOneById(Long id) {
@Override
@CacheEvict(value = "analyticsByNameAndDateRange", allEntries = true)
public void saveNewAnalyticsRecords(List<AnalyticsDTO> valuesOfLevelsList) {

var newRecords = valuesOfLevelsList.stream().filter(this::isAnalyticsNonExistent)
.map(AnalyticMapper::toEntity).toList();
.map(AnalyticMapper::toNewEntity).toList();

if (newRecords.isEmpty()) {
log.warn("No new analytics records to save.");
throw new CustomGlobalErrorHandling.DataIntegrityViolationException();
}

List<AnalyticsDTO> persistedRecords = this.analyticsRepository.saveAll(newRecords).stream()
.map(AnalyticMapper::toRecord).toList();
List<Analytic> persistedRecords = this.analyticsRepository.saveAll(newRecords);

List<AnalyticsDTO> failedRecords = filterFailedRecords(persistedRecords);
List<AnalyticsDTO> failedRecords = filterFailedRecords(persistedRecords).stream()
.map(AnalyticMapper::toRecord).toList();

this.processFailedRecordsNotification(failedRecords);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import leonardo.labutilities.qualitylabpro.utils.exception.CustomGlobalErrorHandling;

@Service
public class BiochemistryAnalyticService extends AbstractAnalyticService {
public class BiochemistryAnalyticService extends AbstractAnalyticHelperService {

public BiochemistryAnalyticService(AnalyticsRepository analyticsRepository,
EmailService emailService, ControlRulesValidators controlRulesValidators) {
Expand All @@ -34,7 +34,7 @@ public List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String
this.convertLevel(level));
}

@Cacheable(value = "analyticsByNameLevelAndDateCache",
@Cacheable(value = "analyticsByNameLevelAndDate",
key = "{#name, #level, #dateStart, #dateEnd, #pageable.pageNumber, #pageable.pageSize}")
@Override
public List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import leonardo.labutilities.qualitylabpro.utils.exception.CustomGlobalErrorHandling;

@Service
public class CoagulationAnalyticService extends AbstractAnalyticService {
public class CoagulationAnalyticService extends AbstractAnalyticHelperService {

public CoagulationAnalyticService(AnalyticsRepository analyticsRepository,
EmailService emailService, ControlRulesValidators controlRulesValidators) {
Expand All @@ -34,7 +34,7 @@ public List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String
this.convertLevel(level));
}

@Cacheable(value = "analyticsByNameLevelAndDateCache",
@Cacheable(value = "analyticsByNameLevelAndDate",
key = "{#name, #level, #dateStart, #dateEnd, #pageable.pageNumber, #pageable.pageSize}")
@Override
public List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import leonardo.labutilities.qualitylabpro.utils.exception.CustomGlobalErrorHandling;

@Service
public class HematologyAnalyticService extends AbstractAnalyticService {
public class HematologyAnalyticService extends AbstractAnalyticHelperService {

public HematologyAnalyticService(AnalyticsRepository analyticsRepository,
EmailService emailService, ControlRulesValidators controlRulesValidators) {
Expand All @@ -34,7 +34,7 @@ public List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String
this.convertLevel(level));
}

@Cacheable(value = "analyticsByNameLevelAndDateCache",
@Cacheable(value = "analyticsByNameLevelAndDate",
key = "{#name, #level, #dateStart, #dateEnd, #pageable.pageNumber, #pageable.pageSize}")
@Override
public List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
import java.util.List;

public class AnalyticsBlackList {

public static final List<String> BLACK_LIST = List.of("%IMG", "#IMG, BAS%, BAS#");

private AnalyticsBlackList() {}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package leonardo.labutilities.qualitylabpro.utils.exception;

import lombok.Getter;
import org.springframework.http.HttpStatus;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.http.HttpStatus;
import lombok.Getter;

@Getter
public class ApiError {
Expand All @@ -31,6 +30,7 @@ public void setDetails(List<String> details) {
}

public void addValidationErrors(Map<String, String> validationErrors) {
validationErrors.forEach((field, message) -> this.details.add(field + ": " + message));
validationErrors
.forEach((field, errorMessage) -> this.details.add(field + ": " + errorMessage));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,18 +131,38 @@ public ResponseEntity<ApiError> handleUserNotFound(UserNotFoundException ex,
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(apiError);
}

@ExceptionHandler(EmailSendingException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseEntity<ApiError> handleEmailSendingError(EmailSendingException ex,
HttpServletRequest request) {
ApiError apiError = new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to send email",
request.getRequestURI());

log.error("Email sending failed at {}: {}", request.getRequestURI(), ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(apiError);
}

// Exception classes
public static class EmailSendingException extends RuntimeException {
public EmailSendingException(String message) {
super(message);
}

public EmailSendingException(String message, Throwable cause) {
super(message, cause);
}
}

public static class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException() {
super();
}


public ResourceNotFoundException(String message) {
super(message);
}
}


public static class PasswordNotMatchesException extends RuntimeException {
public PasswordNotMatchesException() {
super();
Expand Down
Loading

0 comments on commit bd718b6

Please sign in to comment.