Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Repository Guidelines

## Project Structure & Module Organization
This repository is a Spring Boot backend (`java.version=21`) built with Maven.

- `src/main/java/hbp/mip`: application code.
- `src/main/java/hbp/mip/configurations`: security, persistence, OpenAPI, and web filters.
- `src/main/java/hbp/mip/{algorithm,datamodel,experiment,user}`: feature modules (API, service, repository/DAO, DTOs).
- `src/main/java/hbp/mip/utils`: shared helpers and exception handling.
- `src/main/resources`: runtime config (`application.yml`, `log4j2.yml`) and Flyway migrations in `db/migration`.
- `config/`: container templated config (`application.tmpl`) and static runtime assets.
- `.github/workflows`: release image publishing and mirror automation.

## Build, Test, and Development Commands
- `mvn clean package`: compile and build `target/platform-backend.jar`.
- `mvn spring-boot:run`: run locally using `src/main/resources/application.yml`.
- `mvn test`: run test phase (also useful as a smoke check when no tests are present).
- `docker build -t hbpmip/platform-backend:testing .`: build container image.
- `pre-commit run --all-files`: run repository hooks (whitespace, YAML/JSON checks, JSON formatting).

Local development expects PostgreSQL (default `127.0.0.1:5433/portal`) and reachable external services configured in `application.yml`.

## Coding Style & Naming Conventions
- Follow existing Java style: 4-space indentation, clear constructor injection, and minimal field mutability (`final` where possible).
- Keep package names lowercase under `hbp.mip`.
- Use established type suffixes: `*API` (controllers), `*Service`, `*Repository`, `*DAO`, `*DTO`.
- Preserve current logging approach (`hbp.mip.utils.Logger` + Log4j2 config).
- Keep migration filenames in Flyway format: `V{number}__Description.sql`.

## Testing Guidelines
There is currently no committed `src/test/java` tree. For new functionality:

- Add unit/integration tests under `src/test/java`, mirroring production packages.
- Name tests `*Test` (unit) and `*IT` (integration).
- Run `mvn test` before opening a PR.
- For DB changes, verify migrations apply cleanly against a local PostgreSQL instance.

## Commit & Pull Request Guidelines
Recent history follows Conventional Commit style (for example: `fix(user): ...`, `chore(build): ...`, `refactor(...): ...`).

- Use `type(scope): short imperative summary`.
- Keep commits focused and atomic.
- In PRs, include: purpose, linked issue, config/env changes, migration impact, and validation steps run (`mvn test`, local run, or Docker build as relevant).
- If API behavior changes, include example request/response snippets.
23 changes: 21 additions & 2 deletions src/main/java/hbp/mip/datamodel/DataModelService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.google.gson.reflect.TypeToken;
import hbp.mip.utils.ClaimUtils;
import hbp.mip.utils.Exceptions.InternalServerError;
import hbp.mip.utils.Exceptions.NoAuthorizedPathologiesException;
import hbp.mip.utils.Exceptions.NoPathologiesAvailableException;
import hbp.mip.utils.HTTPUtil;
import hbp.mip.utils.JsonConverters;
import hbp.mip.utils.Logger;
Expand Down Expand Up @@ -37,11 +39,26 @@ public DataModelService(ClaimUtils claimUtils) {
public List<DataModelDTO> getDataModels(Authentication authentication, Logger logger) {

List<DataModelDTO> allDataModelDTOS = getAggregatedDataModelDTOs(logger);
if (allDataModelDTOS.isEmpty()) {
logger.warn("No pathologies are available for this federation.");
throw new NoPathologiesAvailableException("No pathologies are available for this federation.");
}

if (!authenticationIsEnabled) {
return allDataModelDTOS;
}
return claimUtils.getAuthorizedDataModels(logger, authentication, allDataModelDTOS);

List<DataModelDTO> authorizedDataModels =
claimUtils.getAuthorizedDataModels(logger, authentication, allDataModelDTOS);

if (authorizedDataModels.isEmpty()) {
logger.warn("User does not have access to any federation pathology.");
throw new NoAuthorizedPathologiesException(
"You do not have access to any of the pathologies in this federation."
);
}

return authorizedDataModels;
}

private List<DataModelDTO> getAggregatedDataModelDTOs(Logger logger) {
Expand All @@ -55,7 +72,9 @@ private List<DataModelDTO> getAggregatedDataModelDTOs(Logger logger) {
try {
StringBuilder response = new StringBuilder();
HTTPUtil.sendGet(exaflowAttributesUrl, response);
exaflowDataModelAttributes = JsonConverters.convertJsonStringToObject(response.toString(), pathologyAttributesType);
Map<String, DataModelAttributes> convertedResponse =
JsonConverters.convertJsonStringToObject(response.toString(), pathologyAttributesType);
exaflowDataModelAttributes = convertedResponse != null ? convertedResponse : Collections.emptyMap();
} catch (Exception e) {
logger.error("Could not fetch exaflow dataModels' metadata: " + e.getMessage());
throw new InternalServerError(e.getMessage());
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/hbp/mip/utils/ControllerExceptionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,34 @@ public ResponseEntity<Object> handleUnauthorizedException(UnauthorizedException
return new ResponseEntity<>(message, HttpStatus.UNAUTHORIZED);
}

@ExceptionHandler(NoAuthorizedPathologiesException.class)
public ResponseEntity<Object> handleNoAuthorizedPathologiesException(
NoAuthorizedPathologiesException ex,
WebRequest request
) {
ErrorMessage message = new ErrorMessage(
HttpStatus.FORBIDDEN.value(),
new Date(),
ex.getMessage(),
request.getDescription(false));

return new ResponseEntity<>(message, HttpStatus.FORBIDDEN);
}

@ExceptionHandler(NoPathologiesAvailableException.class)
public ResponseEntity<Object> handleNoPathologiesAvailableException(
NoPathologiesAvailableException ex,
WebRequest request
) {
ErrorMessage message = new ErrorMessage(
HttpStatus.NOT_FOUND.value(),
new Date(),
ex.getMessage(),
request.getDescription(false));

return new ResponseEntity<>(message, HttpStatus.NOT_FOUND);
}

@ExceptionHandler(NoContent.class)
public ResponseEntity<Void> handleNoContent(NoContent nc, WebRequest request) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package hbp.mip.utils.Exceptions;

public class NoAuthorizedPathologiesException extends RuntimeException {

public NoAuthorizedPathologiesException(String msg) {
super(msg);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package hbp.mip.utils.Exceptions;

public class NoPathologiesAvailableException extends RuntimeException {

public NoPathologiesAvailableException(String msg) {
super(msg);
}
}
Loading