Skip to content

Add ability to download transaction meter values as CSV#2044

Merged
goekay merged 1 commit into
masterfrom
727-log-file-for-metervalues
May 20, 2026
Merged

Add ability to download transaction meter values as CSV#2044
goekay merged 1 commit into
masterfrom
727-log-file-for-metervalues

Conversation

@goekay
Copy link
Copy Markdown
Member

@goekay goekay commented May 20, 2026

No description provided.

@goekay goekay linked an issue May 20, 2026 that may be closed by this pull request
@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Review Summary by Qodo

Add transaction meter values CSV download functionality

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add CSV download capability for transaction meter values
• Implement CsvMapper with Jackson dataformat-csv dependency
• Define MeterValues field ordering via @JsonPropertyOrder annotation
• Create new endpoint for downloading meter values as CSV file
Diagram
flowchart LR
  A["TransactionDetails.MeterValues"] -->|"@JsonPropertyOrder"| B["Field Ordering"]
  C["CsvMapper"] -->|"schema configuration"| D["CSV Serialization"]
  E["New Endpoint"] -->|"GET /transactions/details/{id}/meterValues.csv"| F["CSV Download"]
  D -->|"writes"| F
  B -->|"used by"| D

Loading

File Changes

1. src/main/java/de/rwth/idsg/steve/repository/dto/TransactionDetails.java ✨ Enhancement +11/-0

Add JSON property ordering to MeterValues class

• Added @JsonPropertyOrder import from Jackson annotations
• Applied @JsonPropertyOrder annotation to MeterValues inner class
• Defined field ordering: valueTimestamp, value, readingContext, format, measurand, location, unit,
 phase

src/main/java/de/rwth/idsg/steve/repository/dto/TransactionDetails.java


2. src/main/java/de/rwth/idsg/steve/service/TransactionService.java ✨ Enhancement +13/-0

Add CSV writing capability for meter values

• Added imports for CsvMapper and CsvSchema from Jackson dataformat-csv
• Initialized CsvMapper instance with module discovery
• Created CsvSchema for MeterValues class with header and null value configuration
• Implemented writeTransactionMeterValuesCSV() method to serialize meter values to CSV

src/main/java/de/rwth/idsg/steve/service/TransactionService.java


3. src/main/java/de/rwth/idsg/steve/web/controller/TransactionsReservationsController.java ✨ Enhancement +12/-0

Add REST endpoint for meter values CSV download

• Added new path constant TRANSACTIONS_DETAILS_METER_VALUES_CSV_PATH
• Created new @RequestMapping endpoint for CSV download
• Implemented getTransactionDetailsMeterValuesCsv() method with proper HTTP response headers
• Set Content-Disposition header for file download with transaction-specific filename

src/main/java/de/rwth/idsg/steve/web/controller/TransactionsReservationsController.java


View more (2)
4. pom.xml Dependencies +4/-0

Add Jackson CSV dataformat dependency

• Added new dependency jackson-dataformat-csv from tools.jackson.dataformat group

pom.xml


5. src/main/webapp/WEB-INF/views/data-man/transactionDetails.jsp ✨ Enhancement +4/-0

Add CSV download button to transaction details view

• Added form with GET method to new CSV download endpoint
• Included submit button labeled "Download CSV"
• Positioned download form above meter values table

src/main/webapp/WEB-INF/views/data-man/transactionDetails.jsp


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects Bot commented May 20, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2)

Grey Divider


Action required

1. Meter CSV leaks exception details 📘 Rule violation ⛨ Security
Description
The new CSV download endpoint does not handle not-found/serialization failures and will fall back to
the global MVC error page, which renders ${exception}/${exception.cause} to the client
(information leakage) instead of a client-safe error response.
Code

src/main/java/de/rwth/idsg/steve/web/controller/TransactionsReservationsController.java[R98-107]

Evidence
The checklist requires semantically correct exception handling and client-safe messages. The new
endpoint delegates to service code that can throw exceptions, which are handled by
GlobalControllerAdvice by passing the exception into the 00-error.jsp view where it is rendered
to clients.

src/main/java/de/rwth/idsg/steve/web/controller/TransactionsReservationsController.java[98-107]
src/main/java/de/rwth/idsg/steve/web/GlobalControllerAdvice.java[62-69]
src/main/webapp/WEB-INF/views/00-error.jsp[22-28]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `meterValues.csv` endpoint does not catch/translate expected errors (e.g., transaction not found) into client-safe responses, and the MVC global error view displays exception details to the user.

## Issue Context
For download endpoints, not-found should map to a 404-style response and error messages must be client-safe (no internal exception details).

## Fix Focus Areas
- src/main/java/de/rwth/idsg/steve/web/controller/TransactionsReservationsController.java[98-107]
- src/main/java/de/rwth/idsg/steve/web/GlobalControllerAdvice.java[62-69]
- src/main/webapp/WEB-INF/views/00-error.jsp[22-28]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. CSV formula injection 🐞 Bug ⛨ Security
Description
writeTransactionMeterValuesCSV exports raw string fields into a downloadable CSV without
neutralizing spreadsheet-formula prefixes, so values starting with '=', '+', '-' or '@' can execute
as formulas when opened in Excel/Sheets. This enables CSV injection from device/user-controlled
meter-value fields.
Code

src/main/java/de/rwth/idsg/steve/service/TransactionService.java[R74-77]

Evidence
The export writes the MeterValues list directly to CSV. Those MeterValues instances are built
from DB string columns without sanitization, and the JSP explicitly HTML-encodes the same fields
when rendering, indicating they’re treated as untrusted input in the UI.

src/main/java/de/rwth/idsg/steve/service/TransactionService.java[74-78]
src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java[230-245]
src/main/webapp/WEB-INF/views/data-man/transactionDetails.jsp[64-74]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The meter-values CSV export writes untrusted strings directly to CSV. Spreadsheet apps may interpret fields starting with `=`, `+`, `-`, or `@` as formulas, enabling CSV injection when users open the downloaded file.

### Issue Context
Meter-value fields (e.g., `readingContext`, `format`, `measurand`, `location`, `unit`, `phase`, and potentially `value`) originate from DB columns and are rendered as untrusted in the JSP via HTML encoding, but the CSV export path performs no equivalent neutralization.

### Fix
Before writing rows, sanitize all string fields that may be opened in spreadsheets:
- For any cell value whose first non-empty character is one of `= + - @`, prefix with a single quote `'` (or another agreed neutralization like leading tab) so Excel/Sheets treat it as literal text.
- Apply this to every exported string column, ideally via a small helper (`sanitizeForSpreadsheet(String)`), and map `MeterValues` into a sanitized DTO/copy prior to `seqWriter.writeAll(...)`.

### Fix Focus Areas
- src/main/java/de/rwth/idsg/steve/service/TransactionService.java[74-77]
- src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java[230-245]
- src/main/webapp/WEB-INF/views/data-man/transactionDetails.jsp[64-74]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. writeTransactionMeterValuesCSV null writer 📘 Rule violation ≡ Correctness
Description
writeTransactionMeterValuesCSV dereferences the externally supplied writer without validating it
for null, which can lead to a NullPointerException instead of a clear validation error.
Code

src/main/java/de/rwth/idsg/steve/service/TransactionService.java[R74-77]

Evidence
The checklist requires null/emptiness validation for externally supplied inputs before dereference.
The new method directly passes writer into writeValues(writer) with no null check.

src/main/java/de/rwth/idsg/steve/service/TransactionService.java[74-77]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`writeTransactionMeterValuesCSV(int transactionPk, Writer writer)` uses the provided `writer` without a null check, which can cause an NPE rather than a clear validation failure.

## Issue Context
Compliance requires validation of externally supplied inputs before dereference and failing fast with a clear error.

## Fix Focus Areas
- src/main/java/de/rwth/idsg/steve/service/TransactionService.java[74-77]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. CSV date format mismatch 🐞 Bug ≡ Correctness
Description
TransactionService creates a standalone CsvMapper without disabling WRITE_DATES_AS_TIMESTAMPS, so
MeterValues.valueTimestamp (Joda DateTime) is likely serialized as numeric timestamps instead of the
ISO-8601 format used by the app’s configured Jackson mapper. This produces inconsistent/breaking CSV
output for users/tools that expect the same timestamp representation as the JSON API/UI exports.
Code

src/main/java/de/rwth/idsg/steve/service/TransactionService.java[R61-65]

Evidence
The CSV mapper is created locally with default settings, while the app’s Jackson configuration
explicitly disables WRITE_DATES_AS_TIMESTAMPS (default true). Since MeterValues.valueTimestamp is a
Joda DateTime, this difference directly impacts the CSV output format.

src/main/java/de/rwth/idsg/steve/service/TransactionService.java[61-65]
src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java[217-226]
src/main/java/de/rwth/idsg/steve/repository/dto/TransactionDetails.java[50-68]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`TransactionService` builds its own `CsvMapper` and does not apply the application’s Jackson customizations (notably disabling `WRITE_DATES_AS_TIMESTAMPS`). As a result, `TransactionDetails.MeterValues.valueTimestamp` may be emitted as numeric timestamps in the CSV export.

### Issue Context
The application’s central Jackson configuration disables timestamp date output (default is true) to produce ISO-8601 strings. The new CSV mapper bypasses this configuration.

### Fix
Configure the CSV mapper consistently with the application Jackson configuration, e.g.:
- Disable `tools.jackson.databind.cfg.DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS` on the `CsvMapper` builder, and ensure the Joda module is registered (either via `findAndAddModules()` or explicitly).
- Optionally, prefer injecting/configuring a dedicated `CsvMapper` bean in configuration so serialization rules live in one place.

### Fix Focus Areas
- src/main/java/de/rwth/idsg/steve/service/TransactionService.java[61-65]
- src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java[217-226]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +98 to +107
@RequestMapping(value = TRANSACTIONS_DETAILS_METER_VALUES_CSV_PATH)
public void getTransactionDetailsMeterValuesCsv(@PathVariable("transactionPk") int transactionPk,
HttpServletResponse response) throws IOException {
String fileName = "transaction_%s_meter_values.csv".formatted(transactionPk);
String headerKey = "Content-Disposition";
String headerValue = "attachment; filename=\"%s\"".formatted(fileName);
response.setContentType("text/csv");
response.setHeader(headerKey, headerValue);
transactionService.writeTransactionMeterValuesCSV(transactionPk, response.getWriter());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Meter csv leaks exception details 📘 Rule violation ⛨ Security

The new CSV download endpoint does not handle not-found/serialization failures and will fall back to
the global MVC error page, which renders ${exception}/${exception.cause} to the client
(information leakage) instead of a client-safe error response.
Agent Prompt
## Issue description
The new `meterValues.csv` endpoint does not catch/translate expected errors (e.g., transaction not found) into client-safe responses, and the MVC global error view displays exception details to the user.

## Issue Context
For download endpoints, not-found should map to a 404-style response and error messages must be client-safe (no internal exception details).

## Fix Focus Areas
- src/main/java/de/rwth/idsg/steve/web/controller/TransactionsReservationsController.java[98-107]
- src/main/java/de/rwth/idsg/steve/web/GlobalControllerAdvice.java[62-69]
- src/main/webapp/WEB-INF/views/00-error.jsp[22-28]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +74 to +77
public void writeTransactionMeterValuesCSV(int transactionPk, Writer writer) {
try (var seqWriter = csvMapper.writer(schema).writeValues(writer)) {
seqWriter.writeAll(getDetails(transactionPk).getValues());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Csv formula injection 🐞 Bug ⛨ Security

writeTransactionMeterValuesCSV exports raw string fields into a downloadable CSV without
neutralizing spreadsheet-formula prefixes, so values starting with '=', '+', '-' or '@' can execute
as formulas when opened in Excel/Sheets. This enables CSV injection from device/user-controlled
meter-value fields.
Agent Prompt
### Issue description
The meter-values CSV export writes untrusted strings directly to CSV. Spreadsheet apps may interpret fields starting with `=`, `+`, `-`, or `@` as formulas, enabling CSV injection when users open the downloaded file.

### Issue Context
Meter-value fields (e.g., `readingContext`, `format`, `measurand`, `location`, `unit`, `phase`, and potentially `value`) originate from DB columns and are rendered as untrusted in the JSP via HTML encoding, but the CSV export path performs no equivalent neutralization.

### Fix
Before writing rows, sanitize all string fields that may be opened in spreadsheets:
- For any cell value whose first non-empty character is one of `= + - @`, prefix with a single quote `'` (or another agreed neutralization like leading tab) so Excel/Sheets treat it as literal text.
- Apply this to every exported string column, ideally via a small helper (`sanitizeForSpreadsheet(String)`), and map `MeterValues` into a sanitized DTO/copy prior to `seqWriter.writeAll(...)`.

### Fix Focus Areas
- src/main/java/de/rwth/idsg/steve/service/TransactionService.java[74-77]
- src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java[230-245]
- src/main/webapp/WEB-INF/views/data-man/transactionDetails.jsp[64-74]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@goekay goekay merged commit 9f2c6c0 into master May 20, 2026
41 checks passed
@goekay goekay deleted the 727-log-file-for-metervalues branch May 20, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Log file for metervalues

1 participant