Skip to content

Integrated Giardiasis and Cryptosporidiosis diseases into sormas#13624

Merged
KarnaiahPesula merged 3 commits into
developmentfrom
feature-13602-giardiasis-case-based-surveillance
Oct 15, 2025
Merged

Integrated Giardiasis and Cryptosporidiosis diseases into sormas#13624
KarnaiahPesula merged 3 commits into
developmentfrom
feature-13602-giardiasis-case-based-surveillance

Conversation

@KarnaiahPesula
Copy link
Copy Markdown
Contributor

@KarnaiahPesula KarnaiahPesula commented Oct 13, 2025

Fixes #

Summary by CodeRabbit

  • New Features
    • Added support for Giardiasis and Cryptosporidiosis; new exposure, transmission, infection source, symptom, hospitalization-duration and workplace fields; new sample materials and genotyping options.
  • UI
    • Updated EpiData, Exposure, Symptoms, Hospitalization and Case views; disease-aware visibility, new colors and a “Conclusion” heading.
  • Localization
    • Added captions and enum labels for all new fields and values.
  • Database
    • Schema extended to store new fields and history entries.

@KarnaiahPesula KarnaiahPesula linked an issue Oct 13, 2025 that may be closed by this pull request
3 tasks
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Oct 13, 2025

Walkthrough

Adds Giardiasis and Cryptosporidiosis across API, backend, UI, resources and DB. Introduces new enums, DTO/entity fields, UI form fields/visibility, i18n keys/styles, schema migrations, pathogen/genotype/sample updates, and case-classification rules; updates mappings and facade conversions accordingly.

Changes

Cohort / File(s) Summary
Core diseases & resources
sormas-api/.../Disease.java, sormas-api/.../i18n/Captions.java, sormas-api/.../i18n/Strings.java, sormas-api/src/main/resources/captions.properties, sormas-api/src/main/resources/enum.properties, sormas-api/src/main/resources/strings.properties, sormas-ui/.../CssStyles.java, sormas-ui/.../views/disease.scss
Adds GIARDIASIS and CRYPTOSPORIDIOSIS constants; new/renamed i18n keys; adds style/color classes for new diseases.
Exposure model & enums
API: sormas-api/.../exposure/* (AnimalLocation.java, InfectionSource.java, ModeOfTransmission.java, SwimmingLocation.java, TravelAccommodation.java, ExposureDto.java, ExposureType.java, TypeOfAnimal.java)
Backend: sormas-backend/.../exposure/Exposure.java, sormas-backend/.../epidata/EpiData*.java
UI: sormas-ui/.../exposure/ExposureForm.java, sormas-ui/.../epidata/EpiDataForm.java
Introduces travel/swimming/animal/location/mode/infection-source enums and many new Exposure/EpiData DTO/entity fields; adds ExposureType entries; updates mappings and UI visibility/gating.
Symptoms model & UI
sormas-api/.../symptoms/SymptomsDto.java, sormas-backend/.../symptoms/Symptoms.java, sormas-backend/.../symptoms/SymptomsFacadeEjb.java, sormas-ui/.../symptoms/SymptomsForm.java
Adds GIARDIASIS/CRYPTOSPORIDIOSIS-specific symptom fields (eggyBurps, weightLoss, bloating, reoccurrence, duration, overnightStayRequired, symptomCurrentStatus), DTO/entity mappings and UI layout/logic.
Hospitalization
sormas-api/.../hospitalization/HospitalizationDto.java, sormas-backend/.../hospitalization/Hospitalization.java, sormas-backend/.../hospitalization/HospitalizationFacadeEjb.java, sormas-ui/.../hospitalization/HospitalizationForm.java
Adds durationOfHospitalization field and constant, propagates mapping DTO↔entity, and updates UI (visibility, validation, auto-calc).
EpiData additions
sormas-api/.../epidata/EpiDataDto.java, sormas-backend/.../epidata/EpiData.java, sormas-backend/.../epidata/EpiDataFacadeEjb.java
Adds modeOfTransmission (+type) and infectionSource (+text) fields, DTO/entity accessors and mapping.
Person workplace
sormas-api/.../person/WorkPlace.java, sormas-api/.../person/PersonDto.java, sormas-backend/.../person/Person.java, sormas-backend/.../person/PersonFacadeEjb.java, sormas-ui/.../person/PersonEditForm.java
Introduces WorkPlace enum and workPlace/workPlaceText fields on Person DTO/entity, UI fields and dependent visibility; updates mappings.
Pathogen/genotype/sample types
sormas-api/.../sample/GenoTypeResult.java, sormas-api/.../sample/PathogenTestType.java, sormas-api/.../sample/PathogenTestDto.java, sormas-api/.../sample/SampleMaterial.java, sormas-ui/.../samples/PathogenTestForm.java, sormas-ui/.../samples/pathogentestlink/PathogenTestListEntry.java
Adds Cryptosporidium genotypes and new sample materials; broadens @diseases annotations across test types/materials; refactors UI test-handling to data-driven approach and updates GENOTYPING display.
Case classification & views
sormas-backend/.../caze/classification/CaseClassificationFacadeEjb.java, sormas-ui/.../caze/AbstractCaseView.java, sormas-ui/.../caze/CaseDataView.java
Adds Giardiasis and Cryptosporidiosis classification criteria (probable/confirmed) and integrates disease-aware UI visibility changes and immunization side-panel gating.
Field helper & UI utilities
sormas-ui/.../utils/FieldHelper.java, sormas-ui/.../utils/CssStyles.java
Adds disease-aware updateItems overload and maps new diseases to CSS classes.
DB schema & SQL
sormas-backend/src/main/resources/sql/sormas_schema.sql
Adds columns for new symptom/exposure/epi/hospitalization/person fields and history table changes; increments schema version.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as Forms (Symptoms/Exposure/EpiData/Hospitalization)
  participant Frontend as UI Logic
  participant Facade as FacadeEjb
  participant Entity as JPA Entity
  participant DB as Database

  User->>UI: Edit new disease fields (e.g., travelAccommodation, eggyBurps, durationOfHospitalization)
  UI->>Frontend: validate & collect DTO
  Frontend->>Facade: submit DTO
  Facade->>Entity: map DTO → Entity (new setters)
  Entity->>DB: persist (new columns)
  DB-->>Entity: ACK
  Entity-->>Facade: persisted entity
  Facade-->>Frontend: return DTO (mapping Entity → DTO)
  Frontend-->>UI: render values and adjust visibility
Loading
sequenceDiagram
  autonumber
  actor User
  participant SymptomsUI as SymptomsForm
  participant Nav as Navigator
  participant HospUI as HospitalizationForm

  User->>SymptomsUI: set OvernightStayRequired = YES
  SymptomsUI->>Nav: request navigation (listener)
  Nav->>HospUI: open HospitalizationForm with case context
  HospUI->>User: show hospitalization fields (incl. durationOfHospitalization)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Possibly related PRs

Suggested reviewers

  • obinna-h-n
  • raulbob

Poem

Hop hop — new constants now in view,
Giardiasis and Crypto hop into the queue.
Forms stretch out travel, swim and work,
Symptoms burp, durations do the math (no quirk).
DB grows fields and enums sing too — hooray, from this rabbit to you! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description remains the default template placeholder with only “Fixes #” and no issue number, summary, implementation details, or testing information. It fails to provide the required contextual information or complete any of the template’s sections. Without these details, reviewers cannot understand the scope or verify the changes. Please update the pull request description by specifying the related issue number after the “#”, adding a concise summary of the changes, detailing the implementation approach, and including any testing or validation steps. Ensure all required template sections are completed to satisfy the repository’s guidelines.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly captures the main change, namely the integration of Giardiasis and Cryptosporidiosis diseases into the system. It clearly reflects the primary objective of the pull request without extraneous details. The phrasing is concise, specific, and meaningful to readers scanning the repository history.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature-13602-giardiasis-case-based-surveillance

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java (1)

361-372: Guard duration calculation and clear when discharge removed

Negative durations can occur if dates are invalid/edited; also, clearing discharge should clear duration.

Apply this improvement:

-            // If the discharge date is set, the duration of hospitalization must be calculated based on admission and discharge date
-            if (hasDischargeDate && admissionDateField.getValue() != null) {
-                durationOfHospitalization.setValue("" + DateHelper.getDaysBetween(admissionDateField.getValue(), dischargeDateField.getValue()));
-            }
+            // Auto-calculate duration only when discharge >= admission; clear otherwise
+            if (hasDischargeDate && admissionDateField.getValue() != null) {
+                int days = DateHelper.getDaysBetween(admissionDateField.getValue(), dischargeDateField.getValue());
+                if (days >= 0) {
+                    durationOfHospitalization.setValue(Integer.toString(days));
+                } else {
+                    durationOfHospitalization.clear();
+                }
+            } else {
+                durationOfHospitalization.clear();
+            }

Additionally, consider recomputing on admissionDateField value changes when discharge is present.

🧹 Nitpick comments (14)
sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java (1)

182-201: Use a static EnumSet constant and audit other immunization/vaccination UIs.

Replace the inline List.of(Disease.GIARDIASIS, Disease.CRYPTOSPORIDIUM) with:

+ private static final Set<Disease> DISEASES_WITHOUT_IMMUNIZATION = 
+     EnumSet.of(Disease.GIARDIASIS, Disease.CRYPTOSPORIDIUM);
...
- if (!List.of(Disease.GIARDIASIS, Disease.CRYPTOSPORIDIUM).contains(caze.getDisease())) {
+ if (!DISEASES_WITHOUT_IMMUNIZATION.contains(caze.getDisease())) {

Then review and, if needed, apply the same guard in:

  • PersonSideComponentsElement.java
  • EventParticipantDataView.java
  • ContactDataView.java
sormas-api/src/main/java/de/symeda/sormas/api/exposure/TypeOfAnimal.java (1)

68-83: Clarify the visibility logic for BIRDS, GOAT, HORSE, and SHEEP.

These four animal types are annotated without hide = true, making them visible in the UI for Giardiasis and Cryptosporidium. Please verify:

  1. Why are BIRDS, GOAT, HORSE, and SHEEP visible while more epidemiologically significant animals like CATTLE, CAT, and DOG are either hidden or unannotated?
  2. Is there a specific public health or epidemiological rationale for this selection?
  3. Should the visibility be aligned with the actual transmission risk and reservoir significance for these diseases?

Inconsistent visibility may lead to suboptimal data collection during outbreak investigations.

sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)

659-670: Delegate to existing overload; avoid per-constant reflection and repeated checker creation

Reduce duplication and overhead by reusing updateItems(select, items, checkers, enumClass). Also handle null disease via getNoop().

-	public static void updateItems(Disease disease, AbstractSelect select, Class<? extends Enum> enumClass) {
-
-		List<? extends Enum> filteredValues = Arrays.stream(enumClass.getEnumConstants()).filter(value -> {
-			try {
-				java.lang.reflect.Field enumField = enumClass.getField(value.name());
-				return FieldVisibilityCheckers.withDisease(disease).isVisible(enumClass, enumField);
-			} catch (NoSuchFieldException e) {
-				return true;
-			}
-		}).collect(Collectors.toList());
-		FieldHelper.updateEnumData(select, filteredValues);
-	}
+	public static void updateItems(Disease disease, AbstractSelect select, Class<? extends Enum> enumClass) {
+		FieldVisibilityCheckers checkers =
+			disease != null ? FieldVisibilityCheckers.withDisease(disease) : FieldVisibilityCheckers.getNoop();
+		List<? extends Enum> items = Arrays.asList(enumClass.getEnumConstants());
+		updateItems(select, items, checkers, enumClass);
+	}
sormas-api/src/main/java/de/symeda/sormas/api/exposure/TravelAccommodation.java (1)

25-28: Minor style: import I18nProperties directly

Readability nit: add the import and call I18nProperties.getEnumCaption(this).

-	@Override
-	public String toString() {
-		return de.symeda.sormas.api.i18n.I18nProperties.getEnumCaption(this);
-	}
+	@Override
+	public String toString() {
+		return de.symeda.sormas.api.i18n.I18nProperties.getEnumCaption(this);
+	}

Alternatively:

+import de.symeda.sormas.api.i18n.I18nProperties;
@@
-		return de.symeda.sormas.api.i18n.I18nProperties.getEnumCaption(this);
+		return I18nProperties.getEnumCaption(this);
sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java (1)

170-173: Inconsistent @diseases annotation syntax.

The BIOPSY constant uses @Diseases({...}) without the value = parameter name, while the subsequently added constants INTESTINAL_FLUID (line 286-288) and DUODENUM_FLUID (line 290-292) use @Diseases(value = {...}).

Although both forms are valid Java syntax (the value name can be omitted when it's the only parameter), maintaining consistency improves readability.

Apply this diff to make the annotation style consistent:

-@Diseases({
-	Disease.GIARDIASIS,
-	Disease.CRYPTOSPORIDIUM })
+@Diseases(value = {
+	Disease.GIARDIASIS,
+	Disease.CRYPTOSPORIDIUM })
 BIOPSY,
sormas-api/src/main/java/de/symeda/sormas/api/hospitalization/HospitalizationDto.java (1)

117-121: Add bean validation to durationOfHospitalization

Guard against negative or unrealistic values with javax.validation. Example:

@@
-    @Diseases({
-        Disease.GIARDIASIS,
-        Disease.CRYPTOSPORIDIUM })
-    private Integer durationOfHospitalization;
+    @Diseases({
+        Disease.GIARDIASIS,
+        Disease.CRYPTOSPORIDIUM })
+    @javax.validation.constraints.Min(0)
+    private Integer durationOfHospitalization;
sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java (1)

210-212: Duration field: consider read-only or numeric validation

The value is derived; prevent manual edits or enforce numeric-only input.

Example options:

  • Make it read-only when auto-computed.
  • Add a simple digits-only validator to avoid non-numeric input.
sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureType.java (1)

24-51: Verify hide=true gating for Crypto/Giardia.

WORK, SPORT, VISIT, GATHERING, HABITATION, PERSONAL_SERVICES are hidden for GIARDIASIS/CRYPTOSPORIDIUM; TRAVEL and new exposures are visible. Confirm this is intentional UX (some contexts like WORK/HABITATION may still be relevant exposures for enteric diseases).

Also applies to: 56-59, 63-81

sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java (1)

1075-1081: Avoid Guava here; use EnumSet.of for enum membership.

ImmutableList just for contains adds an unnecessary dependency/allocation. EnumSet is idiomatic and faster.

-        if (ImmutableList.of(Disease.GIARDIASIS, Disease.CRYPTOSPORIDIUM).contains(disease)) {
+        if (java.util.EnumSet.of(Disease.GIARDIASIS, Disease.CRYPTOSPORIDIUM).contains(disease)) {

If Guava isn’t otherwise required in this module, drop the import.

sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java (3)

2667-2679: Use the defined constant in @DependantOn for consistency

Prefer the PARENT_TIME_OFF_WORK constant instead of the raw string.

-	@DependantOn("parentTimeOffWork")
+	@DependantOn(PARENT_TIME_OFF_WORK)

2519-2531: Mixed static vs qualified constants for country codes

This block mixes CountryHelper.COUNTRY_CODE_SWITZERLAND with statically imported COUNTRY_CODE_LUXEMBOURG. Pick one style for clarity (prefer qualified, like elsewhere in this class).


4558-4620: Add @order to new getters if import/export ordering matters

Most existing getters have @order to control template order. The newly added symptom accessors have none; add if required by import/export tooling.

sormas-backend/src/main/java/de/symeda/sormas/backend/exposure/Exposure.java (1)

752-798: Consider column sizing for free‑text fields

sexualExposureText, infectionSourceText, rawFoodContactText, symptomaticIndividualText currently have default VARCHAR length. If UI/DTO allow longer text, use @column(columnDefinition = "text") or set an explicit length to avoid truncation.

sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java (1)

392-412: Add validation (and possibly sensitivity) on new free‑text fields

sexualExposureText, infectionSourceText, rawFoodContactText, symptomaticIndividualText have no @SiZe constraints. Align with other text fields (e.g., CHARACTER_LIMIT_TEXT) and mark as @sensitivedata if they may contain PII.

-@Diseases(Disease.GIARDIASIS)
-private String sexualExposureText;
+@Diseases(Disease.GIARDIASIS)
+@Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong)
+@SensitiveData
+private String sexualExposureText;

-@Diseases({ Disease.GIARDIASIS, Disease.CRYPTOSPORIDIUM })
-private String infectionSourceText;
+@Diseases({ Disease.GIARDIASIS, Disease.CRYPTOSPORIDIUM })
+@Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong)
+@SensitiveData
+private String infectionSourceText;

-@Diseases({ Disease.CRYPTOSPORIDIUM })
-private String rawFoodContactText;
+@Diseases({ Disease.CRYPTOSPORIDIUM })
+@Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong)
+private String rawFoodContactText;

-@Diseases({ Disease.CRYPTOSPORIDIUM })
-private String symptomaticIndividualText;
+@Diseases({ Disease.CRYPTOSPORIDIUM })
+@Size(max = FieldConstraints.CHARACTER_LIMIT_TEXT, message = Validations.textTooLong)
+@SensitiveData
+private String symptomaticIndividualText;

Adjust @sensitivedata as appropriate for your privacy model.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1772743 and 6e3643a.

📒 Files selected for processing (41)
  • sormas-api/src/main/java/de/symeda/sormas/api/Disease.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/AnimalLocation.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java (8 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureType.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/InfectionSource.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/ModeOfTransmission.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/SwimmingLocation.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/TravelAccommodation.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/TypeOfAnimal.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/hospitalization/HospitalizationDto.java (4 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java (11 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/person/OccupationType.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/person/PersonDto.java (2 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/GenoTypeResult.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java (5 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java (3 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java (19 hunks)
  • sormas-api/src/main/resources/captions.properties (4 hunks)
  • sormas-api/src/main/resources/enum.properties (11 hunks)
  • sormas-api/src/main/resources/strings.properties (1 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java (3 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataFacadeEjb.java (2 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/exposure/Exposure.java (3 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/hospitalization/Hospitalization.java (3 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/hospitalization/HospitalizationFacadeEjb.java (2 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/Symptoms.java (2 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/SymptomsFacadeEjb.java (2 hunks)
  • sormas-backend/src/main/resources/sql/sormas_schema.sql (1 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java (3 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java (4 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposureForm.java (10 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java (9 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java (2 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (8 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java (13 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java (1 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1 hunks)
  • sormas-ui/src/main/webapp/VAADIN/themes/sormas/views/disease.scss (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (15)
sormas-api/src/main/java/de/symeda/sormas/api/exposure/ModeOfTransmission.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/i18n/I18nProperties.java (1)
  • I18nProperties (39-536)
sormas-api/src/main/java/de/symeda/sormas/api/exposure/TravelAccommodation.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/i18n/I18nProperties.java (1)
  • I18nProperties (39-536)
sormas-api/src/main/java/de/symeda/sormas/api/exposure/AnimalLocation.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/i18n/I18nProperties.java (1)
  • I18nProperties (39-536)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldvisibility/FieldVisibilityCheckers.java (1)
  • FieldVisibilityCheckers (30-176)
sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (1)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
sormas-api/src/main/java/de/symeda/sormas/api/exposure/SwimmingLocation.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/i18n/I18nProperties.java (1)
  • I18nProperties (39-536)
sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposureForm.java (1)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java (3)
sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java (1)
  • ControllerProvider (69-362)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
sormas-api/src/main/java/de/symeda/sormas/api/exposure/InfectionSource.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/i18n/I18nProperties.java (1)
  • I18nProperties (39-536)
sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java (3)
sormas-ui/src/main/java/de/symeda/sormas/ui/UiUtil.java (1)
  • UiUtil (17-146)
sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java (1)
  • FacadeProvider (127-594)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java (1)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
sormas-api/src/main/java/de/symeda/sormas/api/sample/GenoTypeResult.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/i18n/I18nProperties.java (1)
  • I18nProperties (39-536)
sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: SORMAS CI
  • GitHub Check: android app test (26)
  • GitHub Check: android app test (28)
  • GitHub Check: android app test (27)
🔇 Additional comments (61)
sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java (1)

17-17: LGTM!

The new imports are necessary for the disease-based guard logic introduced on line 183.

Also applies to: 23-23

sormas-api/src/main/java/de/symeda/sormas/api/person/OccupationType.java (1)

78-78: LGTM – “WORK_PLACE” is present in enum.properties, Java code, and database schema.

sormas-api/src/main/java/de/symeda/sormas/api/exposure/TypeOfAnimal.java (2)

18-20: LGTM! Required imports added.

The imports for Disease and Diseases annotation are correctly added to support the new disease annotations on the enum constants.


24-67: Resolve hiding of animal types per existing business rule
Animal-contact–related fields (and corresponding enum values) are intentionally hidden for Giardiasis and Cryptosporidium—as documented in ExposureForm.java (“Animal-contact-related fields are not relevant for Giardiasis and Cryptosporidium”, lines 356–357). No further changes required.

sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java (1)

530-533: LGTM! Disease color mappings added correctly.

The new switch cases for GIARDIASIS and CRYPTOSPORIDIUM follow the established pattern and naming convention. The implementation is consistent with existing disease color mappings.

sormas-api/src/main/java/de/symeda/sormas/api/person/PersonDto.java (2)

409-416: LGTM! Disease annotation expanded appropriately.

The addition of GIARDIASIS and CRYPTOSPORIDIUM to the entryDate field's @diseases annotation is consistent with the existing pattern and aligns with the PR's objective to integrate these diseases into the system.


420-427: LGTM! Consistent disease annotation update.

The livingStatus field's @diseases annotation has been appropriately extended with GIARDIASIS and CRYPTOSPORIDIUM, matching the same disease set as the entryDate field above. This maintains consistency across related demographic fields.

sormas-api/src/main/resources/strings.properties (1)

833-833: LGTM! Localization key added appropriately.

The new headingExposuresConclusion key follows the established naming convention for heading strings and provides a clear, concise label. The addition aligns with the exposure-related UI enhancements mentioned in the PR summary.

sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/SymptomsFacadeEjb.java (1)

242-250: Approve symptom mappings and migrations

All new symptom fields are mapped bi-directionally, defined in entity and DTO, and added via DB migrations.

sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataFacadeEjb.java (1)

178-193: Verified new exposure fields in entity, DTO, and DB migrations
All fields are present in Exposure.java/ExposureDto.java and corresponding columns are added for exposures and exposures_history in sormas_schema.sql.

sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java (1)

667-667: Approve constant addition
headingExposuresConclusion is defined in strings.properties (line 833) and used in ExposureForm (line 235); no further action required.

sormas-api/src/main/java/de/symeda/sormas/api/exposure/AnimalLocation.java (1)

19-30: LGTM; all AnimalLocation i18n keys are present in enum.properties

sormas-api/src/main/java/de/symeda/sormas/api/exposure/SwimmingLocation.java (1)

19-32: LGTM; i18n keys verified All SwimmingLocation enum values have corresponding entries in enum.properties.

sormas-api/src/main/java/de/symeda/sormas/api/exposure/InfectionSource.java (1)

19-29: LGTM — enum i18n keys present

All InfectionSource enum constants have corresponding entries in enum.properties.

sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java (1)

365-370: LGTM: Disease annotation expanded for health conditions.

The @diseases annotation correctly includes the new diseases (GIARDIASIS and CRYPTOSPORIDIUM) with the hide=true flag, maintaining consistency with the existing pattern.

sormas-api/src/main/java/de/symeda/sormas/api/exposure/ModeOfTransmission.java (1)

19-40: LGTM: Well-structured enum with proper localization.

The new ModeOfTransmission enum follows the established pattern in the codebase:

  • Comprehensive set of transmission mode constants
  • Proper toString() implementation using I18nProperties for localization
  • Consistent with other enum implementations in the API layer
sormas-api/src/main/java/de/symeda/sormas/api/Disease.java (1)

91-92: LGTM: New disease constants follow established pattern.

The GIARDIASIS and CRYPTOSPORIDIUM enum constants are correctly defined with parameters matching similar diseases (INVASIVE_PNEUMOCOCCAL_INFECTION, INVASIVE_MENINGOCOCCAL_INFECTION). The placement is logical.

sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java (3)

166-171: LGTM: Improved readability with single-line condition.

The hospitalization view visibility check is now more concise while maintaining the same logic.


186-194: LGTM: Therapy view exclusions correctly updated.

The logic properly excludes GIARDIASIS and CRYPTOSPORIDIUM from the therapy view, consistent with the PR objectives. The condition structure is clear and the comment accurately describes the exclusions.


204-223: LGTM: Clinical course view exclusions correctly updated.

The expanded disease exclusion list now includes GIARDIASIS, CRYPTOSPORIDIUM, IMI, and IPI with proper Luxembourg-specific handling. The comment on line 218 accurately describes the exclusion policy.

sormas-backend/src/main/java/de/symeda/sormas/backend/hospitalization/HospitalizationFacadeEjb.java (1)

95-95: LGTM: Bidirectional mapping for durationOfHospitalization added correctly.

The new durationOfHospitalization field is properly mapped in both fillOrBuildEntity (line 95) and toDto (line 172), following the established pattern for field mappings in this facade.

sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java (2)

427-435: LGTM: Entry date disease whitelist correctly expanded.

The disease list for Luxembourg entry date requirement now includes GIARDIASIS and CRYPTOSPORIDIUM, aligning with the PR objectives. The whitelist structure and logic remain consistent.


768-791: LGTM: Improved age parsing with new helper method.

The new parseApproximateAge helper method (lines 780-791) provides robust handling of age string parsing by:

  • Removing non-numeric characters before parsing
  • Handling null and empty strings safely
  • Catching NumberFormatException

The updated personCanBeEmancipated logic (lines 768-778) correctly uses this helper to handle cases where approximate age is provided as a string.

sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java (1)

243-252: Align @diseases on genoTypeResultText with genoTypeResult
genoTypeResultText’s @diseases only lists MEASLES whereas genoTypeResult includes MEASLES and CRYPTOSPORIDIUM—paired “Text” fields elsewhere mirror their enum counterparts. Confirm whether CRYPTOSPORIDIUM should be added to genoTypeResultText’s annotation.

sormas-api/src/main/resources/captions.properties (3)

651-651: LGTM! Caption for duration of hospitalization is clear and consistent.

The caption follows the existing naming convention and clearly specifies the unit (days), which aids user understanding.


1568-1582: LGTM! Exposure-related captions are clear and well-structured.

The new captions for travel accommodation, swimming locations, and transmission modes follow established naming patterns and provide clear descriptions for users.


2868-2870: No changes needed for suffix naming. The .CryptoGiardia and .giardiasis keys already match their constants and UI usage, reflecting a group vs specific disease distinction.

sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java (2)

286-292: New sample material types for intestinal parasites look appropriate.

The addition of INTESTINAL_FLUID and DUODENUM_FLUID with appropriate disease associations (CRYPTOSPORIDIUM and GIARDIASIS) is medically sound for diagnosing intestinal parasitic infections.

Note: These new constants do not include the hide = true parameter that many other constants use. Verify this is intentional—if these sample types should be visible by default for the new diseases, the current implementation is correct.


28-30: LGTM! Systematic addition of GIARDIASIS and CRYPTOSPORIDIUM to existing sample types.

The updates comprehensively add the new diseases to relevant sample material types while preserving existing disease associations and the hide = true parameters. The disease associations appear medically appropriate for each sample type.

Also applies to: 36-38, 43-45, 56-61, 64-70, 73-79, 81-86, 88-95, 98-102, 105-113, 115-122, 124-130, 132-140, 142-148, 150-158, 160-168, 175-181, 183-190, 192-198, 200-208, 210-217, 219-226, 228-233, 235-241, 252-256, 258-263, 265-271, 273-278, 280-284

sormas-backend/src/main/java/de/symeda/sormas/backend/hospitalization/Hospitalization.java (1)

61-61: LGTM! New hospitalization duration field follows existing patterns.

The addition of the durationOfHospitalization field is well-integrated:

  • Constant declaration follows the class naming convention
  • Field type (Integer) is consistent with similar fields like icuLengthOfStay
  • Getter/setter methods follow standard JavaBean conventions
  • No JPA annotations needed, consistent with other Integer fields in this entity

The field will support capturing hospitalization duration for GIARDIASIS and CRYPTOSPORIDIUM cases as indicated in the PR objectives.

Also applies to: 83-83, 258-264

sormas-api/src/main/java/de/symeda/sormas/api/hospitalization/HospitalizationDto.java (3)

64-65: Constant addition looks good

New DURATION_OF_HOSPITALIZATION constant is consistent with existing pattern.


80-94: Verify ICU gating for Giardiasis/Cryptosporidium

ICU-related fields are now gated for GIARDIASIS and CRYPTOSPORIDIUM. Clinically uncommon; please confirm product requirement/UI alignment to avoid surfacing irrelevant fields.

Also applies to: 100-108


274-280: Accessors LGTM

Getter/setter for durationOfHospitalization align with existing DTO style.

sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java (2)

482-500: IMI/IPI/Pertussis blocks: structure reads correctly

Refactors look consistent with existing pattern and helper usage.

Also applies to: 504-512, 514-533


702-704: Helper overloads LGTM

Overloads for caseData and symptom with addition parameter are consistent and improve readability.

Also applies to: 710-712

sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (3)

946-999: Visibility rules for CSM/IPI/IMI look coherent

The data-driven visibility with FieldHelper is consistent and readable.

Also applies to: 999-1015


1077-1109: Result field enable/disable vs TB read-only logic

You now disable testResultField for some disease/testType combos while TB/Lux flows toggle readOnly. Mixed disabled/readOnly states can be confusing.

Please verify UI behavior when both conditions overlap (e.g., switching between TB and IMI/IPI/Measles/Crypto test types) and consider standardizing on either disabled or readOnly for consistency.


37-39: Guava dependency usage: ImmutableList/ImmutableMap imports are fine; guava is declared in all modules with consistent version management.

sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposureForm.java (3)

390-399: Swimming location visibility scope

Requirement check: Should SWIMMING_LOCATION be shown for domestic swimming too? Currently only linked to INTERNATIONAL_SWIMMING.


356-364: Conditional animal-contact fields suppression for Giardia/Crypto

Hiding animal-contact fields for these diseases aligns with the new model. LGTM.


321-327: Verify Java compatibility settings List.of (Java 9+) is used at 321–327, 356–364, 421–426. Ensure your pom.xml sets the Maven compiler source/target (or <release>) to ≥ 9 (e.g., via <maven.compiler.source>, <maven.compiler.target>, or <release>).

sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java (4)

85-86: Layout update LGTM

Duration of hospitalization added to layout in a sensible position.


157-157: ICU start/end validators

Good addition; enforces chronological consistency.


159-169: RSV-like gating extended to Giardia/Crypto

ICU and related fields visibility adjusted; confirm with product owners that ICU is relevant for these diseases.

Also applies to: 176-180


235-245: Enabling dischargeDate when currently hospitalized = YES

Business check: If currently hospitalized is YES, discharge date and left-against-advice usually should be disabled.

sormas-api/src/main/resources/enum.properties (9)

920-923: GenoTypeResult i18n for Cryptosporidium species added correctly.

Keys match new enum constants and will render via I18nProperties.getEnumCaption.


952-957: InfectionSource captions: LGTM.

Complete set with “Not applicable” and “Other”.


1039-1053: ModeOfTransmission captions: LGTM.

Comprehensive and consistent with exposure model.


1445-1453: SwimmingLocation captions: LGTM.


1460-1466: TravelAccommodation captions: LGTM.


778-783: New ExposureType captions: LGTM.

Match enum names; phrasing is clear.


1319-1322: SampleMaterial additions: LGTM.

Terms look correct for GI/crypto workflows.


1580-1584: TypeOfAnimal additions: LGTM.


1092-1092: OccupationType.WORK_PLACE caption: verify intended semantics.

“Work Place” may overlap with existing “WORKING_PLACE” groups; ensure downstream filters/groupings don’t duplicate.

sormas-api/src/main/java/de/symeda/sormas/api/sample/GenoTypeResult.java (2)

26-98: Enum-level disease annotations and new Cryptosporidium genotypes: LGTM.

  • @diseases gating is consistent.
  • New constants align with i18n keys and domain usage.

One follow-up: if disease naming changes to CRYPTOSPORIDIOSIS, update annotations here accordingly.

Also applies to: 99-107


110-113: toString(): LGTM.

Delegation to I18nProperties ensures localized captions.

sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureType.java (1)

63-81: New exposure constants: LGTM.

Enums and gating align with added i18n keys.

sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java (2)

1095-1097: New visibility rules for weight-loss and duration: LGTM.

Shows WEIGHT_LOSS_AMOUNT when WEIGHT_LOSS=YES and DURATION_OF_SYMPTOMS when SYMPTOM_CURRENT_STATUS=YES. Matches expected UX.

Also applies to: 601-603


1074-1081: Verify i18n keys exist for new captions.

Captions.Symptoms_timeOffWorkOrSchool, Symptoms_timeOffWorkDays_giardiasis, Symptoms_otherComplications_CryptoGiardia, Symptoms_otherComplicationsText_CryptoGiardia must be defined in captions.properties.

sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java (1)

361-371: Verify dependency: swimmingLocation depends only on INTERNATIONAL_SWIMMING

Is the intent to capture locations only for international swimming? If locations are also relevant for domestic swimming, broaden the dependency to include DOMESTIC_SWIMMING as well.

Example approach (if supported by the framework): make it dependent on either flag or a parent "swimming" flag.

sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java (1)

232-235: GENOTYPING excludes GIARDIASIS — intentional?

Many adjacent test types include both GIARDIASIS and CRYPTOSPORIDIUM. GENOTYPING lists MEASLES and CRYPTOSPORIDIUM only. Verify if GIARDIASIS should be included for consistency.

Comment thread sormas-api/src/main/resources/enum.properties Outdated
Comment on lines +534 to 563
// Giardiasis
// FIXME: Check the case classification exposure criteria for giardiasis, its is wrong for now
probable = allOf(
xOf(
1,
symptom(SymptomsDto.DIARRHEA),
symptom(SymptomsDto.BLOATING),
symptom(SymptomsDto.ABDOMINAL_PAIN),
symptom(SymptomsDto.WEIGHT_LOSS)),
xOf(
1,
epiData(EpiDataDto.EXPOSURE_DETAILS_KNOWN),
exposure(ExposureDto.HANDLING_SAMPLES, ExposureType.FLOOD_EXPOSURE),
exposure(ExposureDto.HANDLING_SAMPLES, ExposureType.SYMPTOMATIC_CONTACT),
exposure(ExposureDto.HANDLING_SAMPLES, ExposureType.SEXUAL_CONTACT)));
confirmed = allOf(
xOf(1, (positiveTestResult(Disease.GIARDIASIS, PathogenTestType.MICROSCOPY, PathogenTestType.PCR_RT_PCR, PathogenTestType.CULTURE))));
addCriteria(Disease.GIARDIASIS, DateHelper.getDateZero(2020, 11, 6), null, probable, confirmed, null);

// Cryptosporidiosis
// FIXME: Check the case classification exposure criteria for cryptosporidiosis, its is wrong for now
probable = allOf(
caseData(CaseDataDto.EPIDEMIOLOGICAL_CONFIRMATION, YesNoUnknown.YES),
xOf(1, symptom(SymptomsDto.DIARRHEA), symptom(SymptomsDto.ABDOMINAL_PAIN)));
confirmed = allOf(
xOf(
1,
(positiveTestResult(Disease.CRYPTOSPORIDIUM, PathogenTestType.MICROSCOPY, PathogenTestType.PCR_RT_PCR, PathogenTestType.CULTURE))));
addCriteria(Disease.CRYPTOSPORIDIUM, DateHelper.getDateZero(2020, 11, 6), null, probable, confirmed, null);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Do not ship with FIXME; exposure criteria likely incorrect; verify enums and change date

  • FIXME present for both Giardiasis and Cryptosporidiosis probable criteria; please finalize rules before merge.
  • Exposure mapping seems off: using HANDLING_SAMPLES with ExposureType.FLOOD_EXPOSURE/SYMPTOMATIC_CONTACT/SEXUAL_CONTACT is suspicious (property vs type mismatch). Verify ExposureType actually contains FLOOD_EXPOSURE.
  • Consider adding notACase criteria like other diseases, or explicitly justify absence.
  • The changeDate passed is 2020-11-06; for newly added diseases this will affect getAllSince(changeDate). Set to a current effective date to ensure clients fetch these criteria.

Run to verify ExposureType values and locate any FLOOD_EXPOSURE usage:


🏁 Script executed:

#!/bin/bash
# Check ExposureType enum for expected constants
rg -nP '(?s)enum\s+ExposureType\b.*\{.*\}' -g '!**/target/**' -C2

# Find references to FLOOD_EXPOSURE/SYMPTOMATIC_CONTACT/SEXUAL_CONTACT in code
rg -n --heading 'FLOOD_EXPOSURE|SYMPTOMATIC_CONTACT|SEXUAL_CONTACT' -C2

Length of output: 1987


Comment thread sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposureForm.java Outdated
Comment on lines +1084 to +1094
overNightStayRequiredField.addValueChangeListener(e -> {
if (isListenerAction) {
final boolean isOvernightStayRequiredYes =
SymptomState.YES.equals(FieldHelper.getNullableSourceFieldValue(overNightStayRequiredField));
if (isOvernightStayRequiredYes) {
ControllerProvider.getCaseController().navigateToView(HospitalizationView.VIEW_NAME, caze.getUuid(), null);
}
}
isListenerAction = true;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Overnight-stay navigation won’t trigger on first user change (inverted guard).

The listener executes only after the first event because isListenerAction is set to true at the end. Result: selecting YES won’t navigate the first time. Also guard by context/caze.

Fix by removing the gate or initializing it before binding; prefer checking context and value directly.

Apply this diff:

-        overNightStayRequiredField.addValueChangeListener(e -> {
-            if (isListenerAction) {
-                final boolean isOvernightStayRequiredYes =
-                    SymptomState.YES.equals(FieldHelper.getNullableSourceFieldValue(overNightStayRequiredField));
-                if (isOvernightStayRequiredYes) {
-                    ControllerProvider.getCaseController().navigateToView(HospitalizationView.VIEW_NAME, caze.getUuid(), null);
-                }
-            }
-            isListenerAction = true;
-        });
+        overNightStayRequiredField.addValueChangeListener(e -> {
+            final boolean isOvernightStayRequiredYes =
+                SymptomState.YES.equals(FieldHelper.getNullableSourceFieldValue(overNightStayRequiredField));
+            if (isOvernightStayRequiredYes && symptomsContext == SymptomsContext.CASE && caze != null) {
+                ControllerProvider.getCaseController().navigateToView(HospitalizationView.VIEW_NAME, caze.getUuid(), null);
+            }
+        });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
overNightStayRequiredField.addValueChangeListener(e -> {
if (isListenerAction) {
final boolean isOvernightStayRequiredYes =
SymptomState.YES.equals(FieldHelper.getNullableSourceFieldValue(overNightStayRequiredField));
if (isOvernightStayRequiredYes) {
ControllerProvider.getCaseController().navigateToView(HospitalizationView.VIEW_NAME, caze.getUuid(), null);
}
}
isListenerAction = true;
});
overNightStayRequiredField.addValueChangeListener(e -> {
final boolean isOvernightStayRequiredYes =
SymptomState.YES.equals(FieldHelper.getNullableSourceFieldValue(overNightStayRequiredField));
if (isOvernightStayRequiredYes && symptomsContext == SymptomsContext.CASE && caze != null) {
ControllerProvider.getCaseController().navigateToView(HospitalizationView.VIEW_NAME, caze.getUuid(), null);
}
});
🤖 Prompt for AI Agents
In sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java around
lines 1084 to 1094, the value-change listener uses an inverted guard by checking
isListenerAction and then setting it to true at the end, which prevents the
navigation on the first user change; remove the isListenerAction gate (or set it
true before adding the listener) and instead directly check that caze/context is
non-null and that the new value equals SymptomState.YES, then call
ControllerProvider.getCaseController().navigateToView(HospitalizationView.VIEW_NAME,
caze.getUuid(), null) when appropriate; ensure you keep isListenerAction only if
it’s needed for suppressing programmatic events and initialize it correctly
before binding, otherwise delete it.

Comment on lines +588 to +595
.background-disease-cryptosporidium{
background-color: #9938ca;
fill: #9938ca;

&.background-darker {
background-color: #4b066a;
fill: #4b066a;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Fix class slug to match disease enum

All other disease styles follow the background-disease-{diseaseEnumSlug} pattern. The new disease is CRYPTOSPORIDIOSIS, so the generated class name will be background-disease-cryptosporidiosis. Because this block is named …-cryptosporidium, the UI will never pick up the intended color. Please rename the selector to background-disease-cryptosporidiosis (and keep the darker variant as well) so the styling is actually applied.

🤖 Prompt for AI Agents
In sormas-ui/src/main/webapp/VAADIN/themes/sormas/views/disease.scss around
lines 588 to 595, the CSS selector uses the wrong disease slug
".background-disease-cryptosporidium" which doesn't match the CRYPTOSPORIDIOSIS
enum; rename the selector to ".background-disease-cryptosporidiosis" and also
rename its darker variant to
".background-disease-cryptosporidiosis.background-darker" (preserve the same
color values) so the UI will pick up the correct styles.

@sormas-vitagroup
Copy link
Copy Markdown
Contributor

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java (1)

753-759: Unintended side effects: misuse of personCanBeEmancipated “change” flag.

updateLegalGuardianSection passes isEmancipatedChecked as the “change” flag, which can toggle isEmancipated during routine UI updates. The method should compute capability without mutating state here.

Use change=false in updateLegalGuardianSection; keep change=true only for the onEmancipatedChange path.

-        boolean isEmancipatedChecked = (isEmancipated != null) && (isEmancipated.getValue());
-        int approximateAge = getApproximateAgeInYears();
-        boolean canBeEmancipated = personCanBeEmancipated(approximateAge, isEmancipatedChecked);
+        boolean isEmancipatedChecked = (isEmancipated != null) && (isEmancipated.getValue());
+        int approximateAge = getApproximateAgeInYears();
+        // compute only; do not mutate here
+        boolean canBeEmancipated = personCanBeEmancipated(approximateAge, false);

Also applies to: 767-784

sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/Symptoms.java (1)

1871-1874: Use EnumType.STRING for otherComplications (pre‑existing issue)

This field persists as ORDINAL due to missing type, unlike the rest of the class. Switch to STRING to avoid fragile ordinal mapping.

-	@Enumerated
+	@Enumerated(EnumType.STRING)
 	public SymptomState getOtherComplications() {
 		return otherComplications;
 	}

Note: This predates this PR; fixing requires a DB migration to change column type.

♻️ Duplicate comments (6)
sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java (1)

1081-1090: Overnight-stay navigation won't trigger on first user change (inverted guard).

This issue was already flagged in a previous review. The listener executes only after the first event because isListenerAction is set to true at the end. Result: selecting YES won't navigate the first time.

As previously suggested, fix by removing the gate or initializing it before binding; prefer checking context and value directly:

-		overNightStayRequiredField.addValueChangeListener(e -> {
-			if (isListenerAction) {
-				final boolean isOvernightStayRequiredYes =
-					SymptomState.YES.equals(FieldHelper.getNullableSourceFieldValue(overNightStayRequiredField));
-				if (isOvernightStayRequiredYes) {
-					ControllerProvider.getCaseController().navigateToView(HospitalizationView.VIEW_NAME, caze.getUuid(), null);
-				}
-			}
-			isListenerAction = true;
-		});
+		overNightStayRequiredField.addValueChangeListener(e -> {
+			final boolean isOvernightStayRequiredYes =
+				SymptomState.YES.equals(FieldHelper.getNullableSourceFieldValue(overNightStayRequiredField));
+			if (isOvernightStayRequiredYes && symptomsContext == SymptomsContext.CASE && caze != null) {
+				ControllerProvider.getCaseController().navigateToView(HospitalizationView.VIEW_NAME, caze.getUuid(), null);
+			}
+		});
sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java (2)

534-554: Prior review concerns remain unaddressed.

The issues flagged in the previous review have not been resolved:

  1. FIXME comment (line 535): Still present and must be removed before merge.
  2. Exposure mapping (lines 545-551): Using ExposureDto.EXPOSURE_TYPE appears incorrect. The pattern elsewhere (e.g., line 207) uses specific fields like HANDLING_SAMPLES, PERCUTANEOUS, RISK_AREA, TYPE_OF_ANIMAL. Verify that EXPOSURE_TYPE is a valid ExposureDto field, or replace with appropriate property names.
  3. Stale changeDate (line 554): Hardcoded to 2020-11-06. For newly added diseases, set this to a current effective date so clients fetch the new criteria.
  4. Missing notACase criteria (line 554): Most diseases define notACase criteria. Document why it's intentionally omitted or add the criterion.

556-570: Prior review concerns remain unaddressed.

The issues flagged in the previous review have not been resolved:

  1. FIXME comment (line 557): Still present and must be removed before merge.
  2. Suspicious exposure property names (lines 563-565): ExposureDto.SYMPTOMATIC_INDIVIDUAL_TEXT and ExposureDto.SEXUAL_EXPOSURE_TEXT have a _TEXT suffix, suggesting they are text fields rather than boolean/enum fields typically used in classification criteria. Verify these are correct properties or replace with appropriate field names (e.g., comparing to pattern on line 207: ExposureDto.HANDLING_SAMPLES).
  3. Stale changeDate (line 570): Hardcoded to 2020-11-06. For newly added diseases, set this to a current effective date so clients fetch the new criteria.
  4. Missing notACase criteria (line 570): Most diseases define notACase criteria. Document why it's intentionally omitted or add the criterion.
sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposureForm.java (1)

380-389: Thanks for removing the duplicate SWIMMING_LOCATION rule.

Single registration remains; cleaner and functionally equivalent.

sormas-backend/src/main/java/de/symeda/sormas/backend/exposure/Exposure.java (1)

136-148: Mark new detail texts as SQL TEXT

These user-entered texts can exceed 255 chars. Align with existing “…Details” fields.

 public String getTravelAccommodationType() {
+	@Column(columnDefinition = "text")
 	public String getTravelAccommodationType() {
 		return travelAccommodationType;
 	}
@@
 public String getSwimmingLocationType() {
+	@Column(columnDefinition = "text")
 	public String getSwimmingLocationType() {
 		return swimmingLocationType;
 	}
@@
 public String getSexualExposureText() {
+	@Column(columnDefinition = "text")
 	public String getSexualExposureText() {
 		return sexualExposureText;
 	}
@@
 public String getRawFoodContactText() {
+	@Column(columnDefinition = "text")
 	public String getRawFoodContactText() {
 		return rawFoodContactText;
 	}
@@
 public String getSymptomaticIndividualText() {
+	@Column(columnDefinition = "text")
 	public String getSymptomaticIndividualText() {
 		return symptomaticIndividualText;
 	}

Confirm Liquibase/Flyway migrations set these columns to TEXT and enums to VARCHAR with names.

#!/bin/bash
rg -n -C2 'travelAccommodation(Type)?|swimmingLocation(Type)?|sexualExposureText|rawFoodContact(Text)?|symptomaticIndividualText' sormas-backend/src/main/resources -g '!**/target/**'

Note: Previous feedback about missing @Enumerated on internationalSwimming/domesticSwimming is resolved here.

Also applies to: 661-753

sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/Symptoms.java (1)

2173-2189: LGTM: enum annotations added for overnightStayRequired and bloating

Previous review’s missing @Enumerated(EnumType.STRING) is now correctly applied.

🧹 Nitpick comments (19)
sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java (1)

182-201: Consider using a static Set for the disease exclusion check.

The logic correctly excludes GIARDIASIS and CRYPTOSPORIDIOSIS from the immunization UI. However, List.of(...).contains(...) creates a new list on each view initialization.

For minor performance improvement and clearer intent, consider extracting to a static constant:

+	private static final Set<Disease> DISEASES_WITHOUT_IMMUNIZATION = 
+		Set.of(Disease.GIARDIASIS, Disease.CRYPTOSPORIDIOSIS);
+
 	if (UiUtil.permitted(FeatureType.IMMUNIZATION_MANAGEMENT, UserRight.IMMUNIZATION_VIEW)) {
 		// Immunizations are not shown for Giardiasis and Cryptosporidiosis
-		if (!List.of(Disease.GIARDIASIS, Disease.CRYPTOSPORIDIOSIS).contains(caze.getDisease())) {
+		if (!DISEASES_WITHOUT_IMMUNIZATION.contains(caze.getDisease())) {

Add the Set import:

 import java.util.List;
+import java.util.Set;

This provides O(1) lookup and avoids repeated allocation, though the impact is minor given the small size.

sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java (2)

166-171: Hospitalization tab hidden for all Port Health users — confirm intent

Adding !UiUtil.isPortHealthUser() blocks Port Health users from seeing hospitalization even for non-POE cases. Previously only unreferred POE cases were excluded. Is this intended? If not, drop this clause.

Possible fix if unintended:

- if (UiUtil.enabled(FeatureType.VIEW_TAB_CASES_HOSPITALIZATION) && !caze.checkIsUnreferredPortHealthCase() && !UiUtil.isPortHealthUser()) {
+ if (UiUtil.enabled(FeatureType.VIEW_TAB_CASES_HOSPITALIZATION) && !caze.checkIsUnreferredPortHealthCase()) {

186-194: Simplify disease checks; fix typo; verify JDK baseline

  • Replace List.of(Disease.MEASLES).contains(...) with direct equality.
  • Use EnumSet.of(...) for enums instead of List.of(...).
  • Fix comment: “Gradiastis” → “Giardiasis”.
  • If you keep List.of, ensure the project targets Java 9+.
-               && (!(FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)
-                   && List.of(Disease.MEASLES).contains(caze.getDisease())))
-               && !List.of(Disease.GIARDIASIS, Disease.CRYPTOSPORIDIOSIS).contains(caze.getDisease())) {
-               // Therapy view is not available for Luxembourg for Measles cases and for all Gradiastis & Cryptosporidiosis cases.
+               && !(FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)
+                   && caze.getDisease() == Disease.MEASLES)
+               && !EnumSet.of(Disease.GIARDIASIS, Disease.CRYPTOSPORIDIOSIS).contains(caze.getDisease())) {
+               // Therapy view is not available for Luxembourg for Measles cases and for all Giardiasis & Cryptosporidiosis cases.
sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java (1)

173-173: Typo: clustorTypeTF → clusterTypeTF.

Small rename improves readability.

-        TextField clustorTypeTF = addField(EpiDataDto.CLUSTER_TYPE_TEXT);
+        TextField clusterTypeTF = addField(EpiDataDto.CLUSTER_TYPE_TEXT);

Also update its usages below.

sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java (1)

469-471: Make WORK_PLACE_TEXT required when WORK_PLACE = OTHER.

Currently only visibility changes. Align UX with other “OTHER + details” patterns by requiring text when shown.

 FieldHelper.setVisibleWhen(getFieldGroup(), PersonDto.WORK_PLACE_TEXT, PersonDto.WORK_PLACE, WorkPlace.OTHER, true);
+FieldHelper.setRequiredWhen(
+    getFieldGroup(),
+    PersonDto.WORK_PLACE,
+    Collections.singletonList(PersonDto.WORK_PLACE_TEXT),
+    Collections.singletonList(WorkPlace.OTHER));

Also applies to: 535-536

sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposureForm.java (1)

387-389: SWIMMING_LOCATION should be visible when domestic OR international swimming is YES.

Currently tied only to INTERNATIONAL_SWIMMING. Show location for either selection.

 FieldHelper.setVisibleWhen(getFieldGroup(), ExposureDto.SWIMMING_LOCATION, ExposureDto.INTERNATIONAL_SWIMMING, YesNoUnknown.YES, true);
+FieldHelper.setVisibleWhen(getFieldGroup(), ExposureDto.SWIMMING_LOCATION, ExposureDto.DOMESTIC_SWIMMING, YesNoUnknown.YES, true);
 FieldHelper.setVisibleWhen(getFieldGroup(), ExposureDto.SWIMMING_LOCATION_TYPE, ExposureDto.SWIMMING_LOCATION, SwimmingLocation.OTHER, true);

Also applies to: 124-127, 268-275

sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java (1)

142-144: Fallback when GenoTypeResult is null

Avoid empty result label; fall back to testResultText (or testResult).

-} else if (testType == PathogenTestType.GENOTYPING) {
-    resultText = StringUtils.abbreviate((pathogenTest.getGenoTypeResult() != null ? pathogenTest.getGenoTypeResult().toString() : ""), 125);
+} else if (testType == PathogenTestType.GENOTYPING) {
+    String fallback = StringUtils.defaultIfBlank(pathogenTest.getTestResultText(),
+        DataHelper.toStringNullable(pathogenTest.getTestResult()));
+    String value = pathogenTest.getGenoTypeResult() != null ? pathogenTest.getGenoTypeResult().toString() : fallback;
+    resultText = StringUtils.abbreviate(value, 125);
sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java (1)

170-174: Confirm i18n keys and apply hide flags

  • Default keys for BIOPSY, INTESTINAL_FLUID and DUODENUM_FLUID exist in enum.properties (lines 1318–1320); language-specific .properties fall back to these.
  • If these should be hidden in most UIs, update annotations as below:
 @Diseases(value = {
     Disease.GIARDIASIS,
     Disease.CRYPTOSPORIDIOSIS }, hide = true)
 BIOPSY,
@@
 @Diseases(value = {
     Disease.CRYPTOSPORIDIOSIS }, hide = true)
 INTESTINAL_FLUID,
@@
 @Diseases(value = {
     Disease.GIARDIASIS }, hide = true)
 DUODENUM_FLUID,
sormas-backend/src/main/java/de/symeda/sormas/backend/person/Person.java (1)

909-911: Consider adding a length constraint for consistency.

While not strictly required, consider adding a @Column annotation with a length constraint to getWorkPlaceText() for consistency with similar text fields in this class (e.g., getOtherSalutation() at line 273, getBirthName() at line 283).

Example:

+	@Column(length = CHARACTER_LIMIT_DEFAULT)
 	public String getWorkPlaceText() {
 		return workPlaceText;
 	}

Note: This is optional, as several other detail fields like getEducationDetails() and getOccupationDetails() also lack explicit length constraints.

sormas-backend/src/main/resources/sql/sormas_schema.sql (4)

14672-14678: Align column names to existing camelCase conventions

Several new columns deviate from camelCase and “...Text” casing used elsewhere. Suggest renaming before merge to avoid long‑term inconsistency in entities/DTOs/mappers and i18n keys.

Apply this diff to normalize names across main and history tables:

-alter table exposures add column if not exists animallocation varchar(255);
-alter table exposures add column if not exists domesticswimming varchar(255);
-alter table exposures add column if not exists internationalswimming varchar(255);
-alter table exposures add column if not exists sexualexposuretext varchar(255);
-alter table exposures add column if not exists rawfoodcontact varchar(255);
-alter table exposures add column if not exists rawfoodcontacttext varchar(255);
-alter table exposures add column if not exists symptomaticindividualtext varchar(255);
+alter table exposures add column if not exists animalLocation varchar(255);
+alter table exposures add column if not exists domesticSwimming varchar(255);
+alter table exposures add column if not exists internationalSwimming varchar(255);
+alter table exposures add column if not exists sexualExposureText varchar(255);
+alter table exposures add column if not exists rawFoodContact varchar(255);
+alter table exposures add column if not exists rawFoodContactText varchar(255);
+alter table exposures add column if not exists symptomaticIndividualText varchar(255);

-alter table epidata add column if not exists infectionSourcetext varchar(255);
+alter table epidata add column if not exists infectionSourceText varchar(255);

-ALTER TABLE person ADD COLUMN IF NOT EXISTS workplacetext varchar(255);
+ALTER TABLE person ADD COLUMN IF NOT EXISTS workplaceText varchar(255);

-alter table exposures_history add column if not exists animallocation varchar(255);
-alter table exposures_history add column if not exists domesticswimming varchar(255);
-alter table exposures_history add column if not exists internationalswimming varchar(255);
-alter table exposures_history add column if not exists sexualexposuretext varchar(255);
+alter table exposures_history add column if not exists animalLocation varchar(255);
+alter table exposures_history add column if not exists domesticSwimming varchar(255);
+alter table exposures_history add column if not exists internationalSwimming varchar(255);
+alter table exposures_history add column if not exists sexualExposureText varchar(255);

-alter table epidata_history add column if not exists infectionSourcetext varchar(255);
+alter table epidata_history add column if not exists infectionSourceText varchar(255);

-alter table exposures_history add column if not exists rawfoodcontact varchar(255);
-alter table exposures_history add column if not exists rawfoodcontacttext varchar(255);
-alter table exposures_history add column if not exists symptomaticindividualtext varchar(255);
+alter table exposures_history add column if not exists rawFoodContact varchar(255);
+alter table exposures_history add column if not exists rawFoodContactText varchar(255);
+alter table exposures_history add column if not exists symptomaticIndividualText varchar(255);

-ALTER TABLE person_history ADD COLUMN IF NOT EXISTS workplacetext varchar(255);
+ALTER TABLE person_history ADD COLUMN IF NOT EXISTS workplaceText varchar(255);

Also applies to: 14700-14703, 14708-14710, 14684-14686, 14707-14713


14675-14678: Increase length for free‑text fields (avoid truncation)

“...text/Text” fields are likely free text; 255 chars is tight. Prefer 1024 or TEXT.

-alter table exposures add column if not exists sexualexposuretext varchar(255);
-alter table exposures add column if not exists rawfoodcontacttext varchar(255);
-alter table exposures add column if not exists symptomaticindividualtext varchar(255);
-alter table epidata add column if not exists infectionSourcetext varchar(255);
-ALTER TABLE person ADD COLUMN IF NOT EXISTS workplacetext varchar(255);
+alter table exposures add column if not exists sexualExposureText varchar(1024);
+alter table exposures add column if not exists rawFoodContactText varchar(1024);
+alter table exposures add column if not exists symptomaticIndividualText varchar(1024);
+alter table epidata add column if not exists infectionSourceText varchar(1024);
+ALTER TABLE person ADD COLUMN IF NOT EXISTS workplaceText varchar(1024);

-alter table exposures_history add column if not exists sexualexposuretext varchar(255);
-alter table epidata_history add column if not exists infectionSourcetext varchar(255);
-alter table exposures_history add column if not exists rawfoodcontacttext varchar(255);
-alter table exposures_history add column if not exists symptomaticindividualtext varchar(255);
-ALTER TABLE person_history ADD COLUMN IF NOT EXISTS workplacetext varchar(255);
+alter table exposures_history add column if not exists sexualExposureText varchar(1024);
+alter table epidata_history add column if not exists infectionSourceText varchar(1024);
+alter table exposures_history add column if not exists rawFoodContactText varchar(1024);
+alter table exposures_history add column if not exists symptomaticIndividualText varchar(1024);
+ALTER TABLE person_history ADD COLUMN IF NOT EXISTS workplaceText varchar(1024);

Also applies to: 14684-14686, 14703-14703, 14707-14710, 14713-14713


14662-14666: Add CHECK constraints and column comments for units on numeric durations/amounts

Prevent negative values and document units (days/kg). Low effort, high integrity.

 -- integers added above
+-- Enforce non-negative values
+alter table symptoms
+  add constraint chk_symptoms_weightLossAmount_nonneg
+    check (weightLossAmount is null or weightLossAmount >= 0);
+alter table symptoms
+  add constraint chk_symptoms_durationOfSymptoms_nonneg
+    check (durationOfSymptoms is null or durationOfSymptoms >= 0);
+alter table hospitalization
+  add constraint chk_hosp_duration_nonneg
+    check (durationOfHospitalization is null or durationOfHospitalization >= 0);
+alter table symptoms_history
+  add constraint chk_symptoms_hist_duration_nonneg
+    check (durationOfSymptoms is null or durationOfSymptoms >= 0);
+alter table hospitalization_history
+  add constraint chk_hosp_hist_duration_nonneg
+    check (durationOfHospitalization is null or durationOfHospitalization >= 0);
+
+-- Document units
+comment on column symptoms.weightLossAmount is 'Weight loss amount (kg)';
+comment on column symptoms.durationOfSymptoms is 'Duration of symptoms (days)';
+comment on column hospitalization.durationOfHospitalization is 'Duration of hospitalization (days)';
+comment on column symptoms_history.durationOfSymptoms is 'Duration of symptoms (days)';
+comment on column hospitalization_history.durationOfHospitalization is 'Duration of hospitalization (days)';

Also applies to: 14679-14679, 14693-14693, 14711-14711


14668-14671: Consider indexing if these new fields are used in filters/search

If UI/API filters on travel/swimming/modeOfTransmission/infectionSource/workplace become common, add selective indexes to avoid slow queries.

Would you confirm typical query patterns? If needed, I can propose concrete partial indexes (e.g., on epidata(modeOfTransmission), person(workplace)).

Also applies to: 14681-14683, 14685-14686, 14696-14699, 14704-14707, 14712-14713

sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java (1)

234-245: Don’t enable discharge date when “currently hospitalized” = YES

This invites invalid state. Enable discharge only when not currently hospitalized.

Apply:

-        FieldHelper.setEnabledWhen(
-            currentlyHospitalizedField,
-            Arrays.asList(YesNoUnknown.YES),
-            Arrays.asList(
-                admissionDateField,
-                dischargeDateField,
-                leftAgainstAdviceField,
-                durationOfHospitalization,
-                hospitalizationReason,
-                otherHospitalizationReason),
-            true);
+        FieldHelper.setEnabledWhen(
+            currentlyHospitalizedField,
+            Arrays.asList(YesNoUnknown.YES),
+            Arrays.asList(
+                admissionDateField,
+                leftAgainstAdviceField,
+                hospitalizationReason,
+                otherHospitalizationReason),
+            true);

Then add (outside this hunk):

FieldHelper.setEnabledWhen(
    currentlyHospitalizedField,
    Arrays.asList(YesNoUnknown.NO, YesNoUnknown.UNKNOWN),
    Arrays.asList(dischargeDateField),
    true);
sormas-api/src/main/resources/enum.properties (1)

620-623: Short label for Cryptosporidiosis is too long

Use a concise short form, e.g., “Crypto”, to match list UIs.

-Disease.Short.CRYPTOSPORIDIOSIS=Cryptosporidiosis
+Disease.Short.CRYPTOSPORIDIOSIS=Crypto
sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java (1)

118-126: Add length constraint to infectionSourceText

Align with other text fields to prevent overly long inputs.

-    @Diseases({
-        Disease.GIARDIASIS,
-        Disease.CRYPTOSPORIDIOSIS })
-    private String infectionSourceText;
+    @Diseases({
+        Disease.GIARDIASIS,
+        Disease.CRYPTOSPORIDIOSIS })
+    @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
+    private String infectionSourceText;
sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/Symptoms.java (2)

2139-2145: Annotate weightLossAmount column type for consistency

Temperature uses float4. Apply same to weightLossAmount to avoid dialect-dependent types.

-	public Float getWeightLossAmount() {
+	@Column(columnDefinition = "float4")
+	public Float getWeightLossAmount() {
 		return weightLossAmount;
 	}

2156-2162: Validate durationOfSymptoms is non‑negative

Add Bean Validation to prevent negative values.

-	public Integer getDurationOfSymptoms() {
+	@javax.validation.constraints.Min(0)
+	public Integer getDurationOfSymptoms() {
 		return durationOfSymptoms;
 	}

If you prefer imports, add:

import javax.validation.constraints.Min;

and then use @min(0).

sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java (1)

2695-2700: Consider adding validation for numeric symptom fields.

The new numeric fields (weightLossAmount as Float and durationOfSymptoms as Integer) lack validation constraints. While this is consistent with other numeric fields in the codebase (e.g., bloodPressureDiastolic), adding basic validation could improve data quality:

  • weightLossAmount: Consider @Min(0) since weight loss amounts cannot be negative
  • durationOfSymptoms: Consider @Min(0) and potentially @Max for a reasonable upper bound

Also applies to: 2707-2711

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e3643a and 9c0599f.

📒 Files selected for processing (38)
  • sormas-api/src/main/java/de/symeda/sormas/api/Disease.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java (2 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java (4 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java (8 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureType.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/TypeOfAnimal.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/hospitalization/HospitalizationDto.java (4 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java (13 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/person/PersonDto.java (5 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/person/WorkPlace.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/GenoTypeResult.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java (5 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java (3 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java (20 hunks)
  • sormas-api/src/main/resources/captions.properties (7 hunks)
  • sormas-api/src/main/resources/enum.properties (12 hunks)
  • sormas-api/src/main/resources/strings.properties (1 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java (3 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiData.java (3 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataFacadeEjb.java (4 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/exposure/Exposure.java (3 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/person/Person.java (3 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java (2 hunks)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/symptoms/Symptoms.java (2 hunks)
  • sormas-backend/src/main/resources/sql/sormas_schema.sql (1 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java (3 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java (4 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java (6 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposureForm.java (10 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java (9 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java (6 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (9 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/samples/pathogentestlink/PathogenTestListEntry.java (1 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java (13 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java (1 hunks)
  • sormas-ui/src/main/webapp/VAADIN/themes/sormas/views/disease.scss (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • sormas-ui/src/main/webapp/VAADIN/themes/sormas/views/disease.scss
  • sormas-api/src/main/java/de/symeda/sormas/api/Disease.java
  • sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiDataFacadeEjb.java
  • sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestDto.java
  • sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/TypeOfAnimal.java
  • sormas-api/src/main/java/de/symeda/sormas/api/person/PersonDto.java
🧰 Additional context used
🧬 Code graph analysis (13)
sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java (1)
  • FacadeProvider (127-594)
sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java (2)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java (1)
  • DependingOnFeatureType (47-934)
sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java (3)
sormas-ui/src/main/java/de/symeda/sormas/ui/ControllerProvider.java (1)
  • ControllerProvider (69-362)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
sormas-api/src/main/java/de/symeda/sormas/api/sample/GenoTypeResult.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/i18n/I18nProperties.java (1)
  • I18nProperties (39-536)
sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposureForm.java (2)
sormas-api/src/main/java/de/symeda/sormas/api/i18n/I18nProperties.java (1)
  • I18nProperties (39-536)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java (5)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java (1)
  • FacadeProvider (127-594)
sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldaccess/UiFieldAccessCheckers.java (1)
  • UiFieldAccessCheckers (21-93)
sormas-api/src/main/java/de/symeda/sormas/api/utils/fieldvisibility/FieldVisibilityCheckers.java (1)
  • FieldVisibilityCheckers (30-176)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java (3)
sormas-ui/src/main/java/de/symeda/sormas/ui/UiUtil.java (1)
  • UiUtil (17-146)
sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java (1)
  • FacadeProvider (127-594)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java (1)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (2)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java (1)
  • FacadeProvider (127-594)
sormas-api/src/main/java/de/symeda/sormas/api/person/WorkPlace.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/i18n/I18nProperties.java (1)
  • I18nProperties (39-536)
sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java (1)
sormas-api/src/main/java/de/symeda/sormas/api/CountryHelper.java (1)
  • CountryHelper (22-45)
sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java (1)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: SORMAS CI
  • GitHub Check: android app test (28)
  • GitHub Check: android app test (27)
  • GitHub Check: android app test (26)
  • GitHub Check: Lint Code Base
🔇 Additional comments (40)
sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataView.java (1)

17-17: LGTM!

The new imports are necessary for the disease-based immunization guard and are correctly placed.

Also applies to: 23-23

sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java (7)

44-44: LGTM! Imports are used appropriately.

The Guava ImmutableList import (line 44) is used for disease checking on line 1072, and the ControllerProvider/HospitalizationView imports (lines 97-98) are used for navigation logic on line 1086.

Also applies to: 97-98


1071-1078: LGTM! Disease-specific customization is correctly implemented.

Using ImmutableList.of() for the disease check is appropriate here. The caption changes and visibility adjustments for Giardiasis and Cryptosporidiosis are correctly applied.


1092-1093: LGTM! Conditional visibility rules are correctly configured.

The visibility dependencies are appropriate:

  • WEIGHT_LOSS_AMOUNT is shown only when WEIGHT_LOSS is YES
  • DURATION_OF_SYMPTOMS is shown only when SYMPTOM_CURRENT_STATUS is YES

This follows the same pattern used elsewhere in the form (lines 814-832).


270-281: LGTM! Consistent heading style upgrade.

The symptom group headings are consistently upgraded from H4 to H3, making them more prominent in the UI. This improves visual hierarchy.


503-508: LGTM! New symptom fields are properly integrated.

The new symptom fields (BLOATING, REOCCURRENCE, WEIGHT_LOSS, WEIGHT_LOSS_AMOUNT, EGGY_BURPS, SYMPTOM_CURRENT_STATUS, OVERNIGHT_STAY_REQUIRED, DURATION_OF_SYMPTOMS) are:

  • Added to the form (lines 503-508, 598-599)
  • Included in the unconditional symptom list (lines 798-805)
  • Configured with appropriate visibility rules (lines 1092-1093)

This ensures they're properly handled by form actions like "Clear All" and "Set Empty to No/Unknown" buttons.

Also applies to: 598-599, 798-805


151-180: LGTM! Layout and visibility updates support new disease features.

The layout modifications (lines 151-180) properly structure the clinical presentation section with the new two-column symptom block and additional rows for SYMPTOM_CURRENT_STATUS and DURATION_OF_SYMPTOMS.

The skin rash date visibility logic (lines 576-578) correctly checks for Luxembourg configuration using isConfiguredServer().

Also applies to: 576-578


548-558: Rename typo and confirm logic

Apply this change:

--- a/sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java
+++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java
@@ -549,11 +549,11 @@
-           boolean isSymptamatic = !SymptomState.YES.equals(asymptomaticNOG.getNullableValue());
+           boolean isSymptomatic = !SymptomState.YES.equals(asymptomaticNOG.getNullableValue());
            editableAllowedFields()
              .stream()
              .filter(field -> !field.getId().equals(ASYMPTOMATIC))
              .forEach(field -> {
-               if (!isSymptamatic) {
+               if (!isSymptomatic) {
                   field.clear();
                 }
-               field.setEnabled(isSymptamatic);
-               onsetSymptom.setEnabled(isSymptamatic);
-               onsetDateField.setEnabled(isSymptamatic);
+               field.setEnabled(isSymptomatic);
+               onsetSymptom.setEnabled(isSymptomatic);
+               onsetDateField.setEnabled(isSymptomatic);
              });

A search across the codebase shows no remaining country-specific handling for asymptomatic; removal is safe.

sormas-backend/src/main/java/de/symeda/sormas/backend/caze/classification/CaseClassificationFacadeEjb.java (2)

350-532: LGTM! Formatting improvements enhance readability.

The multiline formatting applied to Measles, Invasive Meningococcal Infection, Invasive Pneumococcal Infection, and Pertussis classifications improves code readability without altering logic.


709-720: LGTM! Method signature formatting is consistent.

The multiline formatting applied to the caseData and symptom method overloads improves consistency with the rest of the codebase.

sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java (1)

365-371: HealthConditions hidden for GIARDIASIS/CRYPTOSPORIDIOSIS — confirm intent

hide = true hides HealthConditions for these diseases. Is that desired for the new case-based diseases? If they should remain visible, drop them from the hide list.

If visibility is intended, apply:

 @Diseases(value = {
   Disease.INVASIVE_MENINGOCOCCAL_INFECTION,
-  Disease.INVASIVE_PNEUMOCOCCAL_INFECTION,
-  Disease.GIARDIASIS,
-  Disease.CRYPTOSPORIDIOSIS }, hide = true)
+  Disease.INVASIVE_PNEUMOCOCCAL_INFECTION }, hide = true)
sormas-api/src/main/resources/strings.properties (1)

829-829: Good addition. Ensure locale parity and cleanup of the old key.

headingEpiConclusion = Conclusion is fine; please confirm other strings_*.properties include this key and that headingEpiCaseImport is fully removed.

Use the same script from the Strings.java comment to check repository-wide usages and translation bundle coverage.

sormas-ui/src/main/java/de/symeda/sormas/ui/person/PersonEditForm.java (1)

429-437: LGTM: Luxembourg entry-date diseases extended.

Adding GIARDIASIS and CRYPTOSPORIDIOSIS to the allowed list matches the new disease scope.

sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposureForm.java (1)

160-167: LGTM: disease-aware conclusion heading and constructor wiring.

Heading added and toggled per disease; constructor passes disease for gating. Looks consistent.

Also applies to: 227-231, 412-415

sormas-backend/src/main/java/de/symeda/sormas/backend/person/PersonFacadeEjb.java (1)

1041-1043: LGTM: DTO/entity mapping for WorkPlace fields.

toPersonDto and fillOrBuildEntity consistently propagate workPlace and workPlaceText.

Also applies to: 1819-1821

sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureType.java (1)

24-83: All ExposureType mappings use @Enumerated(EnumType.STRING); no ORDINAL fields found

sormas-backend/src/main/java/de/symeda/sormas/backend/epidata/EpiData.java (1)

64-69: LGTM on new Giardiasis/Cryptosporidiosis fields and enum imports

Enums are properly introduced and scoped.

sormas-api/src/main/java/de/symeda/sormas/api/person/WorkPlace.java (1)

20-31: LGTM — WorkPlace enum and i18n captions verified
i18n entries for SCHOOL, NURSERY, UNKNOWN and OTHER are present in enum.properties.

sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleMaterial.java (1)

48-55: Add GIARDIASIS and CRYPTOSPORIDIOSIS to @diseases of STOOL
STOOL is the primary material for both diseases; include them in the annotation.

-@Diseases(value = {
-    Disease.CORONAVIRUS,
-    Disease.RESPIRATORY_SYNCYTIAL_VIRUS,
-    Disease.INVASIVE_MENINGOCOCCAL_INFECTION,
-    Disease.INVASIVE_PNEUMOCOCCAL_INFECTION,
-    Disease.MEASLES }, hide = true)
+@Diseases(value = {
+    Disease.CORONAVIRUS,
+    Disease.RESPIRATORY_SYNCYTIAL_VIRUS,
+    Disease.INVASIVE_MENINGOCOCCAL_INFECTION,
+    Disease.INVASIVE_PNEUMOCOCCAL_INFECTION,
+    Disease.MEASLES,
+    Disease.GIARDIASIS,
+    Disease.CRYPTOSPORIDIOSIS }, hide = true)
 STOOL,

Verify UI visibility expectations for GIARDIASIS/CRYPTOSPORIDIOSIS sample materials.

sormas-api/src/main/resources/captions.properties (4)

651-651: LGTM!

The caption clearly indicates the field purpose and includes the unit of measurement (days).


1572-1584: LGTM!

The new exposure-related captions are clear, well-structured, and follow the existing naming conventions in the file.


1986-1987: LGTM!

The workplace captions follow the established pattern of having a main field and a text specification field.


2871-2873: LGTM!

The symptom-related captions are clear and properly scoped to the relevant diseases. The renaming of "otherClinicalPresentation" to "Other Symptoms" (line 2962) improves clarity for end users.

Also applies to: 2962-2963, 2979-2993

sormas-api/src/main/java/de/symeda/sormas/api/hospitalization/HospitalizationDto.java (4)

64-64: LGTM!

The constant declaration follows the established pattern in this DTO class.


80-108: LGTM!

Expanding the disease restrictions to include Giardiasis and Cryptosporidiosis for ICU-related fields is appropriate, as these diseases may require intensive care in severe cases.


117-120: LGTM!

The new field is properly typed as Integer and correctly restricted to the relevant diseases using the @Diseases annotation.


274-280: LGTM!

The accessor methods follow the standard JavaBean pattern consistent with other fields in the DTO.

sormas-backend/src/main/java/de/symeda/sormas/backend/person/Person.java (2)

66-66: LGTM!

The import is correctly placed alphabetically among other imports from the de.symeda.sormas.api.person package.


236-238: LGTM!

The field declarations are appropriate and the comment provides helpful context. The fields follow the established pattern in this entity class.

sormas-backend/src/main/resources/sql/sormas_schema.sql (1)

14715-14715: schema_version 593 is unique and sequential Confirmed only one INSERT of version 593 and it directly follows the INSERT for version 592.

sormas-api/src/main/java/de/symeda/sormas/api/sample/GenoTypeResult.java (1)

26-107: LGTM: disease‑scoped GenoTypeResult values

Annotations and new Cryptosporidium entries align with UI filtering and i18n. toString remains correct.

Also applies to: 110-113

sormas-api/src/main/resources/enum.properties (1)

920-923: LGTM: new GenoTypeResult captions

Captions for CRYPTOSPORIDIUM_* look correct and consistent.

sormas-api/src/main/java/de/symeda/sormas/api/epidata/EpiDataDto.java (1)

64-68: LGTM: new epi fields and accessors

New constants, fields, and getters/setters look consistent with validations and disease gating.

Also applies to: 107-117, 238-268

sormas-ui/src/main/java/de/symeda/sormas/ui/hospitalization/HospitalizationForm.java (1)

159-169: List.of is supported as project targets Java 11+.

Likely an incorrect or invalid review comment.

sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (1)

1078-1109: Confirm auto-positive behavior for IMI/IPI tests
Serogrouping, sequencing, and antibiotic-susceptibility tests may not semantically map to “positive” in all cases. Verify against domain specifications whether IMI/IPI test types should be auto-set to POSITIVE and disabled.

sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java (2)

1572-1577: New EpiData keys verified Backend model, API DTO, and captions.properties include the new infectionSource, infectionSourceText, modeOfTransmission, and modeOfTransmissionType keys.


1807-1807: Exposure additions verified — fields, enums, UI bindings, and DB migrations present

Exposure DTO and backend entity fields (TravelAccommodation, SwimmingLocation, AnimalLocation, YesNoUnknown and related String fields), UI bindings (ExposureForm, ExposuresField), captions, and DB migration entries exist and are consistent. Locations of key references: sormas-api/src/main/resources/captions.properties, sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java, sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java, sormas-backend/src/main/java/de/symeda/sormas/backend/exposure/Exposure.java, sormas-backend/src/main/resources/sql/sormas_schema.sql, sormas-ui/src/main/java/de/symeda/sormas/ui/exposure/ExposureForm.java and ExposuresField.java.

sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java (1)

2695-2700: LGTM - Previous issue resolved.

The weightLossAmount field now correctly includes @Diseases gating and @DependantOn(WEIGHT_LOSS) dependency as suggested in the previous review.

sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java (1)

346-388: LGTM - Dependency annotation correctly applied.

The swimmingLocation field at line 360 correctly uses @DependantOn(INTERNATIONAL_SWIMMING), ensuring it only appears when international swimming exposure is indicated.

sormas-api/src/main/java/de/symeda/sormas/api/sample/PathogenTestType.java (1)

27-235: LGTM - Disease annotations consistently expanded.

The PathogenTestType enum annotations have been systematically expanded to include GIARDIASIS and/or CRYPTOSPORIDIOSIS across relevant test types. The selective inclusion (e.g., GENOTYPING includes only CRYPTOSPORIDIOSIS but not GIARDIASIS, CULTURE includes only GIARDIASIS) appears intentional and appropriate for each test type's applicability to these diseases.

Comment thread sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java
String CaseHospitalization_admittedToHealthFacility = "CaseHospitalization.admittedToHealthFacility";
String CaseHospitalization_currentlyHospitalized = "CaseHospitalization.currentlyHospitalized";
String CaseHospitalization_dischargeDate = "CaseHospitalization.dischargeDate";
String CaseHospitalization_durationOfHospitalization = "CaseHospitalization.durationOfHospitalization";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Duration of hospitalization key: ensure backend/UI wiring and translations

Confirm that CaseHospitalization.durationOfHospitalization is implemented (DTO/entity/computed field) and translations are provided in all locales.


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Where is durationOfHospitalization used?
rg -n -C2 '\bdurationOfHospitalization\b'
# Check for translation key presence (properties files)
fd -t f -a -i 'messages.*\.properties' | xargs rg -n '^CaseHospitalization\.durationOfHospitalization\s*='

Length of output: 11088


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Find all caption property files (default and locale-specific)
files=$(find sormas-api/src/main/resources -type f -name 'captions*.properties' | sort)
echo "Caption property files:"
echo "$files"
# Check for key presence in each file
for file in $files; do
  echo "Checking $file"
  if grep -q '^CaseHospitalization\.durationOfHospitalization=' "$file"; then
    echo "  ✅ Key present"
  else
    echo "  ❌ Key missing"
  fi
done

Length of output: 7264


Add missing translations for CaseHospitalization.durationOfHospitalization in all locale‐specific files
The key is defined in captions.properties but absent from every captions_.properties under src/main/resources.

🤖 Prompt for AI Agents
In sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java around line
897 the key "CaseHospitalization.durationOfHospitalization" is declared but
translations are missing in all locale-specific resource files; add the
corresponding entry "CaseHospitalization.durationOfHospitalization=<appropriate
translation>" to each captions_<locale>.properties under src/main/resources,
ensuring the value is translated for each locale and that the key matches
exactly (no extra whitespace), then run a resource bundle check or build to
verify no missing-key warnings.

Comment on lines +2395 to 2397
String Person_workPlace = "Person.workPlace";
String Person_workPlaceText = "Person.workPlaceText";
String personAgeAndBirthdate = "personAgeAndBirthdate";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Person workPlace keys: verify model and UI

Confirm Person.workPlace(+Text) fields exist in Person entity/DTO/forms and migrations are included.


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C2 '\bworkPlace(Text)?\b' -- sormas-api sormas-backend sormas-ui
fd -t f -a -i '.*(changelog|migration).*\.(xml|sql)' | xargs rg -n -C2 -i 'person|workplace|workPlace'

Length of output: 278222


Add DB migration and UI integration for Person.workPlace/Text
Captions, entity and DTO fields are present, but:

  • No Liquibase changelog or SQL migration adds workPlace/workPlaceText columns to the Person table.
  • UI code does not reference these fields; person edit/view forms must bind and display them.

String Symptoms_bilateralCataracts = "Symptoms.bilateralCataracts";
String Symptoms_blackeningDeathOfTissue = "Symptoms.blackeningDeathOfTissue";
String Symptoms_bleedingVagina = "Symptoms.bleedingVagina";
String Symptoms_bloating = "Symptoms.bloating";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Symptoms keys: map to backend fields and clean up naming

  • Backend fields exist for: eggyBurps, weightLoss(+Amount), symptomCurrentStatus, durationOfSymptoms, reoccurrence, overnightStayRequired, bloating. Ensure all are bound to UI and exported/imported.
  • Naming: consider “recurrence” instead of “reoccurrence” (optional; would require broader change).
  • Duplicate/overlap: You have both symptomCurrentStatus and symptomStatus keys; confirm both are actually used to avoid dead keys.

Also applies to: 2909-2912, 3001-3003, 3011-3011, 3032-3032, 3053-3059, 3064-3077


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Check DTO and UI usage
rg -n -C2 '\b(eggyBurps|weightLossAmount|symptomCurrentStatus|durationOfSymptoms|reoccurrence|overnightStayRequired|bloating)\b' -- sormas-api sormas-backend sormas-ui
# Is symptomStatus used anywhere?
rg -n -C2 '\b(Captions\.Symptoms_symptomStatus|"Symptoms\.symptomStatus")\b'

Length of output: 27350


Remove unused Symptoms.symptomStatus i18n key

  • Symptoms.symptomStatus isn’t referenced anywhere; remove its entries from Captions.java and captions.properties.
  • Verified eggyBurps, weightLoss/(+Amount), symptomCurrentStatus, durationOfSymptoms, reoccurrence, overnightStayRequired, bloating are correctly bound across backend, API, and UI.
  • Optional: rename reoccurrence to recurrence for consistency.
🤖 Prompt for AI Agents
In sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java around line
2866, remove the unused i18n key entry for Symptoms.symptomStatus from
Captions.java and also delete the matching key/value from captions.properties;
search the codebase to confirm there are no remaining usages before removing,
and if you choose to apply the optional consistency change, rename any
occurrences of "reoccurrence" to "recurrence" across backend, API, UI and update
both Captions.java and captions.properties accordingly to keep keys and
references synchronized.

Comment on lines +205 to +222
EnumSet.of(FeatureType.VIEW_TAB_CASES_FOLLOW_UP, FeatureType.VIEW_TAB_CASES_CLINICAL_COURSE, FeatureType.CLINICAL_MANAGEMENT),
UserRight.CLINICAL_COURSE_VIEW)
&& !caze.checkIsUnreferredPortHealthCase()
&& !List
.of(
Disease.INVASIVE_MENINGOCOCCAL_INFECTION,
Disease.INVASIVE_PNEUMOCOCCAL_INFECTION,
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS)
.contains(caze.getDisease())
&& !(FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)
&& List.of(Disease.MEASLES).contains(caze.getDisease()))) {
// clinical course view is not available for Luxembourg for Measles cases,
// and for all other countries IMI & IPI cases.
// and for all other countries GIARDIASIS, Cryptosporidiosis, IMI & IPI cases.
menu.addView(
ClinicalCourseView.VIEW_NAME,
I18nProperties.getPrefixCaption(CaseDataDto.I18N_PREFIX, CaseDataDto.CLINICAL_COURSE),
params);
ClinicalCourseView.VIEW_NAME,
I18nProperties.getPrefixCaption(CaseDataDto.I18N_PREFIX, CaseDataDto.CLINICAL_COURSE),
params);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Clinical Course tab accidentally requires Follow-up feature — likely too strict

UiUtil.permitted(EnumSet.of(FOLLOW_UP, CLINICAL_COURSE, CLINICAL_MANAGEMENT), …) demands all features be enabled, hiding Clinical Course when Follow-up is disabled. Likely only VIEW_TAB_CASES_CLINICAL_COURSE (and optionally CLINICAL_MANAGEMENT) should gate this tab.

Also simplify disease checks as in the therapy block.

-            if (UiUtil.permitted(
-                EnumSet.of(FeatureType.VIEW_TAB_CASES_FOLLOW_UP, FeatureType.VIEW_TAB_CASES_CLINICAL_COURSE, FeatureType.CLINICAL_MANAGEMENT),
-                UserRight.CLINICAL_COURSE_VIEW)
+            if (UiUtil.permitted(
+                EnumSet.of(FeatureType.VIEW_TAB_CASES_CLINICAL_COURSE, FeatureType.CLINICAL_MANAGEMENT),
+                UserRight.CLINICAL_COURSE_VIEW)
                 && !caze.checkIsUnreferredPortHealthCase()
-                && !List
-                    .of(
-                        Disease.INVASIVE_MENINGOCOCCAL_INFECTION,
-                        Disease.INVASIVE_PNEUMOCOCCAL_INFECTION,
-                        Disease.GIARDIASIS,
-                        Disease.CRYPTOSPORIDIOSIS)
-                    .contains(caze.getDisease())
-                && !(FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)
-                    && List.of(Disease.MEASLES).contains(caze.getDisease()))) {
+                && !EnumSet.of(
+                        Disease.INVASIVE_MENINGOCOCCAL_INFECTION,
+                        Disease.INVASIVE_PNEUMOCOCCAL_INFECTION,
+                        Disease.GIARDIASIS,
+                        Disease.CRYPTOSPORIDIOSIS)
+                    .contains(caze.getDisease())
+                && !(FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)
+                    && caze.getDisease() == Disease.MEASLES)) {

Optionally, extract repeated conditions (e.g., Luxembourg+Measles) into local booleans for readability.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
EnumSet.of(FeatureType.VIEW_TAB_CASES_FOLLOW_UP, FeatureType.VIEW_TAB_CASES_CLINICAL_COURSE, FeatureType.CLINICAL_MANAGEMENT),
UserRight.CLINICAL_COURSE_VIEW)
&& !caze.checkIsUnreferredPortHealthCase()
&& !List
.of(
Disease.INVASIVE_MENINGOCOCCAL_INFECTION,
Disease.INVASIVE_PNEUMOCOCCAL_INFECTION,
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS)
.contains(caze.getDisease())
&& !(FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)
&& List.of(Disease.MEASLES).contains(caze.getDisease()))) {
// clinical course view is not available for Luxembourg for Measles cases,
// and for all other countries IMI & IPI cases.
// and for all other countries GIARDIASIS, Cryptosporidiosis, IMI & IPI cases.
menu.addView(
ClinicalCourseView.VIEW_NAME,
I18nProperties.getPrefixCaption(CaseDataDto.I18N_PREFIX, CaseDataDto.CLINICAL_COURSE),
params);
ClinicalCourseView.VIEW_NAME,
I18nProperties.getPrefixCaption(CaseDataDto.I18N_PREFIX, CaseDataDto.CLINICAL_COURSE),
params);
if (UiUtil.permitted(
EnumSet.of(FeatureType.VIEW_TAB_CASES_CLINICAL_COURSE, FeatureType.CLINICAL_MANAGEMENT),
UserRight.CLINICAL_COURSE_VIEW)
&& !caze.checkIsUnreferredPortHealthCase()
&& !EnumSet.of(
Disease.INVASIVE_MENINGOCOCCAL_INFECTION,
Disease.INVASIVE_PNEUMOCOCCAL_INFECTION,
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS)
.contains(caze.getDisease())
&& !(FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)
&& caze.getDisease() == Disease.MEASLES)) {
// clinical course view is not available for Luxembourg for Measles cases,
// and for all other countries GIARDIASIS, Cryptosporidiosis, IMI & IPI cases.
menu.addView(
ClinicalCourseView.VIEW_NAME,
I18nProperties.getPrefixCaption(CaseDataDto.I18N_PREFIX, CaseDataDto.CLINICAL_COURSE),
params);
🤖 Prompt for AI Agents
sormas-ui/src/main/java/de/symeda/sormas/ui/caze/AbstractCaseView.java around
lines 205-222: the current UiUtil.permitted call requires FOLLOW_UP as well as
CLINICAL_COURSE which incorrectly hides the Clinical Course tab when Follow-up
is disabled; change the permitted check to require only
VIEW_TAB_CASES_CLINICAL_COURSE (and keep CLINICAL_MANAGEMENT if intended)
instead of including FOLLOW_UP, simplify the disease exclusion check by using a
single List.of(...).contains(caze.getDisease()) for the multiple diseases, and
extract the Luxembourg+Measles condition into a small boolean for readability
before combining conditions to decide whether to add the ClinicalCourseView.

Comment on lines +135 to +142
ExposuresField exposuresField = addField(
EpiDataDto.EXPOSURES,
new ExposuresField(
disease,
FieldVisibilityCheckers.withDisease(disease)
.add(new CountryFieldVisibilityChecker(FacadeProvider.getConfigFacade().getCountryLocale())),
UiFieldAccessCheckers.getDefault(false, FacadeProvider.getConfigFacade().getCountryLocale()),
true));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Pseudonymization mismatch in access checkers (may expose PII).

UiFieldAccessCheckers.getDefault is called with isPseudonymized=false while the form has an isPseudonymized flag and ExposuresField is set accordingly. This can grant access to personal/sensitive fields when the form is pseudonymized.

Switch to the form’s isPseudonymized value.

-                UiFieldAccessCheckers.getDefault(false, FacadeProvider.getConfigFacade().getCountryLocale()),
+                UiFieldAccessCheckers.getDefault(isPseudonymized, FacadeProvider.getConfigFacade().getCountryLocale()),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ExposuresField exposuresField = addField(
EpiDataDto.EXPOSURES,
new ExposuresField(
disease,
FieldVisibilityCheckers.withDisease(disease)
.add(new CountryFieldVisibilityChecker(FacadeProvider.getConfigFacade().getCountryLocale())),
UiFieldAccessCheckers.getDefault(false, FacadeProvider.getConfigFacade().getCountryLocale()),
true));
ExposuresField exposuresField = addField(
EpiDataDto.EXPOSURES,
new ExposuresField(
disease,
FieldVisibilityCheckers.withDisease(disease)
.add(new CountryFieldVisibilityChecker(FacadeProvider.getConfigFacade().getCountryLocale())),
UiFieldAccessCheckers.getDefault(isPseudonymized, FacadeProvider.getConfigFacade().getCountryLocale()),
true));
🤖 Prompt for AI Agents
In sormas-ui/src/main/java/de/symeda/sormas/ui/epidata/EpiDataForm.java around
lines 135 to 142, the call to UiFieldAccessCheckers.getDefault currently passes
a hardcoded false for the pseudonymization flag which can grant access to PII
when the form is pseudonymized; update that call to pass the form's
isPseudonymized flag (the instance variable or getter used by this form) so
ExposuresField receives the correct pseudonymization setting and access checks
honor the form's pseudonymization state.

Comment on lines +210 to 213
final TextField durationOfHospitalization = addField(HospitalizationDto.DURATION_OF_HOSPITALIZATION, TextField.class);
durationOfHospitalization.setVisible(false);

FieldHelper.setEnabledWhen(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make durationOfHospitalization derived (read‑only) and keep it in sync

Duration is computed; users shouldn’t edit it. Also, recalc/clear on both admission/discharge changes to avoid stale values.

Apply:

-        final TextField durationOfHospitalization = addField(HospitalizationDto.DURATION_OF_HOSPITALIZATION, TextField.class);
-        durationOfHospitalization.setVisible(false);
+        final TextField durationOfHospitalization = addField(HospitalizationDto.DURATION_OF_HOSPITALIZATION, TextField.class);
+        durationOfHospitalization.setVisible(false);
+        durationOfHospitalization.setReadOnly(true);
-                descriptionField,
-                isolatedField,
-                leftAgainstAdviceField,
-                hospitalizationReason,
-                icuLengthOfStayField,
-                durationOfHospitalization,
-                otherHospitalizationReason),
+                descriptionField,
+                isolatedField,
+                leftAgainstAdviceField,
+                hospitalizationReason,
+                icuLengthOfStayField,
+                otherHospitalizationReason),
-                if (hasDischargeDate && admissionDateField.getValue() != null) {
-                    durationOfHospitalization.setValue("" + DateHelper.getDaysBetween(admissionDateField.getValue(), dischargeDateField.getValue()));
-                }
+                if (hasDischargeDate && admissionDateField.getValue() != null) {
+                    durationOfHospitalization.setReadOnly(false);
+                    durationOfHospitalization.setValue("" + DateHelper.getDaysBetween(admissionDateField.getValue(), dischargeDateField.getValue()));
+                    durationOfHospitalization.setReadOnly(true);
+                } else {
+                    durationOfHospitalization.setReadOnly(false);
+                    durationOfHospitalization.clear();
+                    durationOfHospitalization.setReadOnly(true);
+                }

Additionally (outside the shown ranges), also recalc on admission date changes:

admissionDateField.addValueChangeListener(e -> {
    if (dischargeDateField.getValue() != null && admissionDateField.getValue() != null) {
        durationOfHospitalization.setReadOnly(false);
        durationOfHospitalization.setValue("" + DateHelper.getDaysBetween(admissionDateField.getValue(), dischargeDateField.getValue()));
        durationOfHospitalization.setReadOnly(true);
    } else {
        durationOfHospitalization.setReadOnly(false);
        durationOfHospitalization.clear();
        durationOfHospitalization.setReadOnly(true);
    }
});

Also applies to: 217-233, 361-372

@sormas-vitagroup
Copy link
Copy Markdown
Contributor

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c0599f and 7a5c64c.

📒 Files selected for processing (2)
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java (8 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: android app test (28)
  • GitHub Check: android app test (27)
  • GitHub Check: android app test (26)
  • GitHub Check: SORMAS CI
  • GitHub Check: Lint Code Base
🔇 Additional comments (3)
sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java (3)

379-396: Previous review comments addressed.

All the text fields now have the required @Size and @SensitiveData annotations as requested in the previous review.


358-362: LGTM: Enum field follows established pattern.

The swimmingLocation enum field correctly omits @SensitiveData, consistent with other enum fields in this class. The @DependantOn(INTERNATIONAL_SWIMMING) annotation is appropriately used to conditionally show this field.


848-934: LGTM: Getters and setters correctly implemented.

All accessor methods follow the standard JavaBean naming convention and have appropriate return types and parameters matching their corresponding fields.

Comment on lines +346 to +350
@Diseases({
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS })
@SensitiveData
private TravelAccommodation travelAccommodation;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove @sensitivedata from enum field for consistency.

The travelAccommodation enum field has @SensitiveData, but other enum fields in this DTO (e.g., typeOfPlace, meansOfTransport, workEnvironment, gatheringType, habitationType, typeOfAnimal, animalCondition, animalContactType) do not. Enum selections are typically not marked as sensitive data unless they directly reveal private health information.

Apply this diff to align with the established pattern:

 @Diseases({
     Disease.GIARDIASIS,
     Disease.CRYPTOSPORIDIOSIS })
-@SensitiveData
 private TravelAccommodation travelAccommodation;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Diseases({
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS })
@SensitiveData
private TravelAccommodation travelAccommodation;
@Diseases({
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS })
private TravelAccommodation travelAccommodation;
🤖 Prompt for AI Agents
In sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java
around lines 346 to 350, the enum field travelAccommodation is annotated with
@SensitiveData while other enum fields in this DTO are not; remove the
@SensitiveData annotation from the travelAccommodation field to match the
established pattern for enum selections, leaving the @Diseases annotation intact
and ensuring no other annotations or imports are affected.

Comment on lines +352 to +356
@Diseases({
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS })
@Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
private String travelAccommodationType;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add @sensitivedata annotation to text field.

The travelAccommodationType String field is missing @SensitiveData, but all other String detail/type fields in this class (e.g., typeOfPlaceDetails, meansOfTransportDetails, protectiveMeasuresDetails, gatheringDetails, habitationDetails) have this annotation. This inconsistency affects how the data is handled for pseudonymization and privacy compliance.

Apply this diff to align with the established pattern:

 @Diseases({
     Disease.GIARDIASIS,
     Disease.CRYPTOSPORIDIOSIS })
+@SensitiveData
 @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
 private String travelAccommodationType;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Diseases({
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS })
@Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
private String travelAccommodationType;
@Diseases({
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS })
@SensitiveData
@Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
private String travelAccommodationType;
🤖 Prompt for AI Agents
In sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java
around lines 352-356, the String field travelAccommodationType is missing the
@SensitiveData annotation; add @SensitiveData above the field to match other
detail/type String fields, and if the annotation import is not present add the
appropriate import for SensitiveData so the class compiles.

Comment on lines +364 to +368
@Diseases({
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS })
@Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
private String swimmingLocationType;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add @sensitivedata annotation to text field.

The swimmingLocationType String field is missing @SensitiveData, but all other String detail/type fields in this class have this annotation for privacy compliance and pseudonymization.

Apply this diff to align with the established pattern:

 @Diseases({
     Disease.GIARDIASIS,
     Disease.CRYPTOSPORIDIOSIS })
+@SensitiveData
 @Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
 private String swimmingLocationType;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Diseases({
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS })
@Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
private String swimmingLocationType;
@Diseases({
Disease.GIARDIASIS,
Disease.CRYPTOSPORIDIOSIS })
@SensitiveData
@Size(max = FieldConstraints.CHARACTER_LIMIT_DEFAULT, message = Validations.textTooLong)
private String swimmingLocationType;
🤖 Prompt for AI Agents
In sormas-api/src/main/java/de/symeda/sormas/api/exposure/ExposureDto.java
around lines 364 to 368, the swimmingLocationType String field is missing the
@SensitiveData annotation used on other detail/type String fields; add the
@SensitiveData annotation directly above the field (keeping the existing
@Diseases and @Size annotations) so the field is treated as sensitive for
pseudonymization and privacy handling.

@sormas-vitagroup
Copy link
Copy Markdown
Contributor

@KarnaiahPesula KarnaiahPesula merged commit 4852720 into development Oct 15, 2025
6 of 14 checks passed
@KarnaiahPesula KarnaiahPesula deleted the feature-13602-giardiasis-case-based-surveillance branch October 15, 2025 11:26
@coderabbitai coderabbitai Bot mentioned this pull request Oct 15, 2025
@KarnaiahPesula KarnaiahPesula restored the feature-13602-giardiasis-case-based-surveillance branch October 15, 2025 13:31
@coderabbitai coderabbitai Bot mentioned this pull request Oct 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Modify Disease Enum for Giardiasis case based surveillance

3 participants