Skip to content

Fixes: Display manual case classification.#13880

Merged
KarnaiahPesula merged 2 commits intodevelopmentfrom
bugfix-manual-case-classification-fix
Mar 13, 2026
Merged

Fixes: Display manual case classification.#13880
KarnaiahPesula merged 2 commits intodevelopmentfrom
bugfix-manual-case-classification-fix

Conversation

@KarnaiahPesula
Copy link
Contributor

@KarnaiahPesula KarnaiahPesula commented Mar 13, 2026

Summary:
Displaying the manual classification, which has configured in disease level Changes:
Verifying the caseClassificationMode, if it's DISABLED, does nothing. For AUTOMATIC, display the automatic case classification in the table. For MANUAL, display the plain text box with the configured details.

Fixes # Display manual case classification.
Summary:
Displaying the manual classification, which has configured in disease level
Changes:
Verifying the caseClassificationMode, if it's DISABLED, does nothing.
For AUTOMATIC, display the automatic case classification in the table.
For MANUAL, display the plain text box with the configured details.

Summary by CodeRabbit

  • New Features

    • Added a case definition popup that displays disease-specific case definition text in the classification UI.
  • Improvements

    • Classification workflow now adapts to configuration: shows rules when automatic classification applies, otherwise presents manual case-definition flow.
  • Bug Fixes

    • Prevented errors when disease configuration is missing by safely handling absent configuration before accessing case definition.

Summary:
Displaying the manual classification, which has configured in disease level
Changes:
Verifying the caseClassificationMode, if it's DISABLED, does nothing.
For AUTOMATIC, display the automatic case classification in the table.
For MANUAL, display the plain text box with the configured details.
@KarnaiahPesula KarnaiahPesula requested a review from raulbob March 13, 2026 10:26
@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

📝 Walkthrough

Walkthrough

CaseDataForm now shows classification UI conditionally based on disease configuration and calculation mode: if automatic classification is enabled and data exists it shows the rules/info button; otherwise it exposes a manual case-definition button that opens a popup with the disease's case definition HTML. Backend null-check prevents NPE when fetching case definition text.

Changes

Cohort / File(s) Summary
UI: Case classification flow
sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java
Replaced unconditional classification rules button with mode-aware conditional logic. Added manual case-definition flow: renders a button that opens a popup showing disease-specific case definition HTML. Updated imports (e.g., CaseClassificationCalculationMode, VerticalLayout, PersonReferenceDto).
Backend: safe config access
sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java
Guarded retrieval of case definition text by checking for null DiseaseConfiguration and returning null when absent to avoid potential NPEs.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • obinna-h-n
  • raulbob
  • roldy

Poem

🐰 I hopped through code to lend a clue,
A button shifts from old to new,
If auto sleeps, a manual gate,
Pops up the rules — concise and straight,
I nibble bugs and bounce anew.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description covers the feature intent but lacks the required issue number reference and has formatting issues with duplicate sections. Add the specific GitHub issue number after 'Fixes #' and clean up the duplicate summary/changes sections for clarity.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: enabling display of manual case classification, which matches the core functionality added in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix-manual-case-classification-fix
📝 Coding Plan
  • Generate coding plan for human review comments

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

@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: 2

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

1367-1373: Reuse the fetched classification mode instead of querying config twice.

Line [1372] re-calls getCaseClassificationCalculationMode(disease) although Line [1367] already has the value. This is avoidable facade churn during form init.

♻️ Proposed refactor
-			if (FacadeProvider.getConfigFacade().getCaseClassificationCalculationMode(disease).isAutomaticEnabled()
+			if (caseClassificationCalculationMode.isAutomaticEnabled()
 				&& diseaseClassificationExists()) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java` around
lines 1367 - 1373, The code fetches the case classification mode once into
caseClassificationCalculationMode but then calls
FacadeProvider.getConfigFacade().getCaseClassificationCalculationMode(disease)
again; replace the second call with the already-fetched variable
(caseClassificationCalculationMode) so the if uses
caseClassificationCalculationMode.isAutomaticEnabled() &&
diseaseClassificationExists(), avoiding the redundant config fetch and facade
churn in CaseDataForm.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java`:
- Around line 1545-1549: The backend method
DiseaseConfigurationFacadeEjb.getCaseDefinitionText currently calls
service.getDiseaseConfiguration(disease).getCaseDefinitionText() without
guarding for a null configuration; change it to first retrieve the configuration
into a local variable (or use Optional.map) and null-check it before calling
getCaseDefinitionText, or use service.getDiseaseConfiguration(disease).map(cfg
-> cfg.getCaseDefinitionText()).orElse(null) so the method returns null safely
when no configuration exists instead of throwing a NullPointerException.
- Around line 1555-1559: Replace the HTML rendering mode for the label showing
caseDefinitionText to avoid rendering raw HTML: locate the Label instance
suspectContent in CaseDataForm and change the call
suspectContent.setContentMode(ContentMode.HTML) to
suspectContent.setContentMode(ContentMode.TEXT) so the value from
caseDefinitionText is rendered as plain text before adding it to
classificationRulesLayout.

---

Nitpick comments:
In `@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java`:
- Around line 1367-1373: The code fetches the case classification mode once into
caseClassificationCalculationMode but then calls
FacadeProvider.getConfigFacade().getCaseClassificationCalculationMode(disease)
again; replace the second call with the already-fetched variable
(caseClassificationCalculationMode) so the if uses
caseClassificationCalculationMode.isAutomaticEnabled() &&
diseaseClassificationExists(), avoiding the redundant config fetch and facade
churn in CaseDataForm.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 91f95597-9a8c-4c4e-99ee-d0887f0df9e4

📥 Commits

Reviewing files that changed from the base of the PR and between 870fe72 and 61c66ad.

📒 Files selected for processing (1)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java

Comment on lines +1555 to +1559
Label suspectContent = new Label();
suspectContent.setContentMode(ContentMode.HTML);
suspectContent.setWidth(100, Unit.PERCENTAGE);
suspectContent.setValue(caseDefinitionText);
classificationRulesLayout.addComponent(suspectContent);
Copy link

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

🏁 Script executed:

# First, check if the file exists and examine the lines in question
head -1559 "sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java" | tail -20 | cat -n

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 1181


🏁 Script executed:

# Get more context around the flagged lines
sed -n '1540,1570p' "sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java" | cat -n

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 1730


🏁 Script executed:

# Search for where caseDefinitionText is defined/assigned
rg "caseDefinitionText" "sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java" -B 5 -A 2

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 1014


🏁 Script executed:

# Check for any sanitization or escaping functions in the file
rg "sanitize|escape|HTML\.escape" "sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java"

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 58


🏁 Script executed:

# Search for other ContentMode.HTML usages in this file to understand patterns
rg "ContentMode\.HTML" "sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java" -B 3 -A 3

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 2311


🏁 Script executed:

# Find the DiseaseConfigurationFacade implementation
find . -name "*DiseaseConfigurationFacade*" -type f | head -20

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 459


🏁 Script executed:

# Search for getCaseDefinitionText method definition
rg "getCaseDefinitionText" --type java -B 2 -A 10

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 14621


🏁 Script executed:

# Check if caseDefinitionText is stored in database and could be user-controlled
rg "caseDefinitionText" --type java -B 3 -A 3 | head -100

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 11482


🏁 Script executed:

# Look for any HTML sanitization utilities in the codebase
rg "sanitize|escapeHtml|HtmlUtils" --type java | head -30

Repository: SORMAS-Foundation/SORMAS-Project

Length of output: 2852


Change ContentMode.HTML to ContentMode.TEXT to prevent stored XSS.

The caseDefinitionText is editable by administrators through a RichTextArea in the disease configuration form and stored in the database without sanitization. Rendering it with ContentMode.HTML allows arbitrary HTML/JavaScript injection, creating a stored XSS vulnerability. Using ContentMode.TEXT will safely display the content as plain text.

Proposed fix
-			Label suspectContent = new Label();
-			suspectContent.setContentMode(ContentMode.HTML);
+			Label suspectContent = new Label();
+			suspectContent.setContentMode(ContentMode.TEXT);
 			suspectContent.setWidth(100, Unit.PERCENTAGE);
 			suspectContent.setValue(caseDefinitionText);
📝 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
Label suspectContent = new Label();
suspectContent.setContentMode(ContentMode.HTML);
suspectContent.setWidth(100, Unit.PERCENTAGE);
suspectContent.setValue(caseDefinitionText);
classificationRulesLayout.addComponent(suspectContent);
Label suspectContent = new Label();
suspectContent.setContentMode(ContentMode.TEXT);
suspectContent.setWidth(100, Unit.PERCENTAGE);
suspectContent.setValue(caseDefinitionText);
classificationRulesLayout.addComponent(suspectContent);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java` around
lines 1555 - 1559, Replace the HTML rendering mode for the label showing
caseDefinitionText to avoid rendering raw HTML: locate the Label instance
suspectContent in CaseDataForm and change the call
suspectContent.setContentMode(ContentMode.HTML) to
suspectContent.setContentMode(ContentMode.TEXT) so the value from
caseDefinitionText is rendered as plain text before adding it to
classificationRulesLayout.

Summary:
Displaying the manual classification, which has configured in disease level
Changes:
Verifying the caseClassificationMode, if it's DISABLED, does nothing.
For AUTOMATIC, display the automatic case classification in the table.
For MANUAL, display the plain text box with the configured details.
@sormas-vitagroup
Copy link
Contributor

Copy link

@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.

🧹 Nitpick comments (1)
sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java (1)

446-448: Avoid double invocation of service.getDiseaseConfiguration(disease).

The null-guard correctly prevents the NPE, but the service method is called twice. Store the result in a local variable to avoid redundant lookups and potential TOCTOU issues.

♻️ Proposed refactor
 public String getCaseDefinitionText(Disease disease) {
-	return service.getDiseaseConfiguration(disease) == null ? null : service.getDiseaseConfiguration(disease).getCaseDefinitionText();
+	DiseaseConfiguration configuration = service.getDiseaseConfiguration(disease);
+	return configuration == null ? null : configuration.getCaseDefinitionText();
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java`
around lines 446 - 448, In getCaseDefinitionText, avoid calling
service.getDiseaseConfiguration(disease) twice: call
service.getDiseaseConfiguration(disease) once, store the result in a local
variable (e.g., diseaseConfig), check it for null, and then return
diseaseConfig.getCaseDefinitionText() or null; this removes the redundant lookup
and prevents a potential TOCTOU window.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java`:
- Around line 446-448: In getCaseDefinitionText, avoid calling
service.getDiseaseConfiguration(disease) twice: call
service.getDiseaseConfiguration(disease) once, store the result in a local
variable (e.g., diseaseConfig), check it for null, and then return
diseaseConfig.getCaseDefinitionText() or null; this removes the redundant lookup
and prevents a potential TOCTOU window.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 356bc39a-dcf3-46ce-a2e4-4692fbe99420

📥 Commits

Reviewing files that changed from the base of the PR and between 61c66ad and c5ccf33.

📒 Files selected for processing (1)
  • sormas-backend/src/main/java/de/symeda/sormas/backend/disease/DiseaseConfigurationFacadeEjb.java

@sormas-vitagroup
Copy link
Contributor

@KarnaiahPesula KarnaiahPesula merged commit 938bb9a into development Mar 13, 2026
8 of 10 checks passed
@KarnaiahPesula KarnaiahPesula deleted the bugfix-manual-case-classification-fix branch March 13, 2026 11:27
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.

3 participants