Skip to content

Conversation

@SashaPog
Copy link
Contributor

@SashaPog SashaPog commented Nov 17, 2025

Issue
9272

Summary by CodeRabbit

  • Refactor
    • Centralized configuration into unified property components for remote services, OpenAI, Google, Azure, and security settings to improve consistency and reliability.
  • Stability / Validation
    • Added runtime validation and clear error messages for critical environment properties (addresses, API keys, timeouts, tokens), reducing misconfiguration issues at startup.
  • Chores / Tests
    • Expanded unit tests covering new property components and related flows to improve confidence in configuration handling.

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

Walkthrough

This pull request centralizes environment-backed configuration by introducing multiple property components (RemoteWebClientProperties, GoogleProperties, OpenAiProperties, AzureProperties, SecurityProperties) and replaces scattered @Value injections across controllers, services, and clients with constructor-injected property beans; tests updated to mock and assert the new getters.

Changes

Cohort / File(s) Summary
New Property Classes
service-api/src/main/java/greencity/properties/RemoteWebClientProperties.java, service-api/src/main/java/greencity/properties/GoogleProperties.java, service-api/src/main/java/greencity/properties/OpenAiProperties.java, service-api/src/main/java/greencity/properties/AzureProperties.java, service-api/src/main/java/greencity/properties/SecurityProperties.java
Added Spring components that read from Environment, validate required keys in @PostConstruct, expose getters that throw IllegalStateException and log errors when properties are missing.
Property Class Tests
service-api/src/test/java/greencity/properties/*PropertiesTest.java
Added unit tests (Mockito + LogCaptor) for each new properties class covering success, missing-property exceptions, and validation logging.
Error Message Constants
service-api/src/main/java/greencity/constant/ErrorMessage.java
Added ~15 new public static final String constants for "not set" error messages referenced by property classes.
Controllers — migrate @Value → properties
core/src/main/java/greencity/controller/EcoNewsController.java, core/src/main/java/greencity/controller/HabitAssignController.java, core/src/main/java/greencity/webcontroller/ManagementController.java, core/src/main/java/greencity/webcontroller/ManagementEventController.java
Removed direct @Value fields, injected relevant property beans (RemoteWebClientProperties, GoogleProperties, OpenAiProperties) and updated usages to call bean getters.
Services / Clients — migrate @Value → properties
service-api/src/main/java/greencity/client/RestClient.java, service-api/src/main/java/greencity/client/config/UserRemoteClientConfig.java, service/src/main/java/greencity/service/DatabaseBackupServiceImpl.java, service/src/main/java/greencity/service/NotificationServiceImpl.java, service/src/main/java/greencity/service/OpenAIServiceImpl.java, service/src/main/java/greencity/config/GoogleApiConfiguration.java, service/src/main/java/greencity/security/jwt/JwtTool.java
Replaced multiple @Value-injected fields with constructor-injected property beans and updated code to use getters (server addresses, timeouts, API keys, system email, JWT settings). Some constructors/signatures changed accordingly.
Test updates for callers
core/src/test/java/..., service-api/src/test/java/..., service/src/test/java/...
Tests updated to mock new property beans (RemoteWebClientProperties, OpenAiProperties, AzureProperties, GoogleProperties, SecurityProperties) and stub their getters instead of using ReflectionTestUtils or @Value.
New/Updated tests and helpers
service-api/pom.xml, core/src/main/resources/application.properties
Added logcaptor test dependency and added spring.cloud.azure.keyvault.secret.property-sources[0].refresh-interval=15m to application.properties.
Minor removals
service/src/main/java/greencity/service/CommentServiceImpl.java
Removed unused @Value("${client.address}") field.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Prop as Property Bean
    participant Env as Environment
    participant Caller as Controller/Service

    App->>Prop: constructor injection
    activate Prop
    Prop->>Prop: `@PostConstruct` validateProperties()
    Prop->>Env: getProperty(key)
    alt value present
        Env-->>Prop: value
        Prop->>Prop: log info (validated)
    else missing
        Env-->>Prop: null
        Prop->>Prop: log error
        Prop-->>Prop: throw IllegalStateException
    end
    deactivate Prop

    Caller->>Prop: call getter()
    activate Prop
    Prop->>Env: getProperty(key)
    alt value present
        Env-->>Prop: value
        Prop-->>Caller: return value
    else missing
        Env-->>Prop: null
        Prop-->>Caller: throw IllegalStateException
    end
    deactivate Prop
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~40 minutes

Areas to focus on during review:

  • Constructor/signature changes (RestClient, JwtTool, OpenAIServiceImpl, UserRemoteClientConfig) — ensure all injection points and bean wiring are updated.
  • Validation logic in new property classes — confirm accurate keys, error messages and that thrown exceptions/ log messages match expectations.
  • Tests updated to mock property beans — verify every test stubs the required getters used by the class under test.
  • Any places that previously relied on raw string fields (URLs, timeouts, emails) to ensure getters are applied consistently and no string concatenation regressions exist.

Poem

🌱 Configs once scattered like leaves in wind,

Beans now gather each key from within.
At startup they check, log, and stand tall,
So services and controllers won't fall.
Central, tidy, validated—order for all.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.05% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: migrating to automatic secret refresh from Azure Key Vault. It directly reflects the main objective of centralizing configuration management through new properties classes and updating components to use them.
✨ 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/9272/automatic-secret-refresh-from-azure

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example:

"Create a concise high-level summary as a bullet-point list. Then include a Markdown table showing lines added and removed by each contributing author."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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

🧹 Nitpick comments (11)
core/src/main/resources/application.properties (1)

2-2: Verify that the 15-minute refresh interval aligns with operational requirements.

The default refresh interval for Azure Key Vault secrets is 30 minutes, and can be configured via spring.cloud.azure.keyvault.secret.property-sources[].refresh-interval. This change reduces it to 15 minutes, which will increase the frequency of API calls to Azure Key Vault.

Consider whether this interval:

  • Is appropriate for your application's secret rotation cadence and cost implications
  • Should remain hardcoded or be externalized to an environment variable (consistent with other configuration in this file like ${KEY_VAULT_ENDPOINT}, ${DATASOURCE_URL}, etc.)

If the 15-minute interval is specifically chosen for security or compliance requirements, a brief comment in the configuration would help future maintainers understand the rationale.

If you want this to be environment-specific, consider externalizing it:

-spring.cloud.azure.keyvault.secret.property-sources[0].refresh-interval=15m
+spring.cloud.azure.keyvault.secret.property-sources[0].refresh-interval=${AZURE_KEYVAULT_REFRESH_INTERVAL:15m}

This approach would allow different environments to override the default if needed.

service/src/test/java/greencity/service/DataBaseBackupServiceImplTest.java (1)

34-44: Consider consistency in property injection approach.

While the PR refactors Azure properties to use AzureProperties, these datasource properties still use @Value annotations. For consistency, consider whether these should also be moved to a centralized properties class.

core/src/main/java/greencity/controller/EcoNewsController.java (1)

226-226: Consider using a constant for the "enabled" string and add null safety.

The string literal "enabled" is a magic value that could be defined as a constant. Additionally, consider null safety if getRelevance() might return null.

Apply this improvement:

-boolean isRelevanceEnabled = openAiProperties.getRelevance().equals("enabled");
+boolean isRelevanceEnabled = "enabled".equalsIgnoreCase(
+    openAiProperties.getRelevance());

Alternatively, define a constant:

private static final String RELEVANCE_ENABLED = "enabled";

// Then use:
boolean isRelevanceEnabled = RELEVANCE_ENABLED.equalsIgnoreCase(
    openAiProperties.getRelevance());

The equalsIgnoreCase with the constant on the left prevents NPE if getRelevance() returns null.

service-api/src/test/java/greencity/client/RestClientTest.java (1)

27-102: Good adaptation to RemoteWebClientProperties; consider narrowing LENIENT strictness

The constructor wiring and stubbing of RemoteWebClientProperties look correct and keep existing URL and system email expectations aligned with the new configuration bean.

One minor suggestion: class-level @MockitoSettings(strictness = Strictness.LENIENT) can hide accidental unused stubs over time. If feasible, you might prefer the default strictness and mark only specific stubs as lenient (e.g., via lenient().when(...)) in tests that truly need it. This keeps the suite a bit safer while still supporting shared setup.

service-api/src/main/java/greencity/properties/AzureProperties.java (1)

1-48: Azure properties component is consistent and clear (only tiny Javadoc nit)

This class cleanly follows the shared pattern for property beans: fail-fast validation in @PostConstruct, specific ErrorMessage use, and no caching so callers always read the latest Environment values. That aligns well with the PR’s configuration refactor.

Only an optional polish: the Javadoc line * Сlass for retrieving... appears to use a non-Latin “C”; you may want to correct it to Class for readability.

service-api/src/main/java/greencity/properties/OpenAiProperties.java (1)

1-41: OpenAI properties wiring looks good; fix small log message typo

The configuration access and validation logic here are consistent with the other property beans and give clear failure modes when required values are missing.

There is a minor typo in the success log message:

log.info("All OpneAi properties validated successfully.");

Consider correcting "OpneAi" to "OpenAi" (or "OpenAI") to keep logs clean and searchable.

service-api/src/main/java/greencity/properties/SecurityProperties.java (1)

1-42: Security properties handling is appropriate; minor naming polish

The fail-fast validation of JWT secret and access token expiration is a good fit for security-sensitive configuration, and the pattern is consistent with the other property beans.

Minor nit: the local variable in getJwtAccessTokenExpiration() is named accesssTokenExpiration (three s characters). Renaming it to accessTokenExpiration would tidy up the code, though it doesn’t affect behavior.

service-api/src/main/java/greencity/client/RestClient.java (2)

16-17: Centralizing RestClient configuration via RemoteWebClientProperties looks solid

Injecting RemoteWebClientProperties and wiring it through the constructor is a clean way to centralize remote endpoint and system email config, and it aligns well with the rest of the PR. This should make future changes to server addresses or system email much easier and safer.

As a small polish-only follow‑up, consider tightening the Javadoc wording (fixing typos like Environmet / creat and naming it RemoteWebClientProperties rather than RemoteWebClient) to keep documentation clear for future maintainers.

Also applies to: 51-54, 66-78, 79-89


91-122: Property-driven URLs and system-email based JWT creation look correct and consistent

All usages of the new properties are wired consistently:

  • UBS calls use getGreencityUbsServerAddress() (e.g., notifications endpoint) while all other calls use getGreencityUserServerAddress(), which matches the intent of the methods.
  • Every previously hard-coded/user-address field access has been replaced by remoteWebClientProperties across user lookup, management, notifications, and scheduled email methods.
  • setHeader() now falls back to a JWT generated with remoteWebClientProperties.getSystemEmailAddress(), tying token creation into the new config source as intended.

This is a good, low-risk refactor that improves configurability and prepares the client for dynamic property updates. If you want to reduce repetition later, you could introduce small helpers like userServiceBaseUrl() / ubsServiceBaseUrl() to wrap the repeated getGreencityUserServerAddress() / getGreencityUbsServerAddress() calls, but that’s purely a readability/DRY improvement and not required for correctness.

Also applies to: 130-383, 390-409, 424-430

service-api/src/main/java/greencity/constant/ErrorMessage.java (1)

256-270: New configuration error messages are clear; consider minor style alignment

The added *_NOT_SET constants nicely standardize error handling for missing configuration (server addresses, timeouts, Azure connection, JWT/OpenAI/Google keys, etc.) and will make startup failures and logs much more understandable.

For consistency with existing messages, you might optionally:

  • Capitalize the first word (e.g., "Greencity server address not set."), and
  • Ensure punctuation/casing matches the surrounding messages.

This is purely cosmetic; the current texts are functionally fine.

service-api/src/main/java/greencity/properties/RemoteWebClientProperties.java (1)

36-97: Getter implementations are straightforward; consider small safety and maintainability tweaks

The individual getters correctly:

  • Read each property from Environment using the expected key.
  • Guard against missing/empty values (StringUtils.hasText for strings, null checks for integers).
  • Log and throw IllegalStateException with the corresponding ErrorMessage constant when required values aren’t provided.

A couple of optional refinements you might consider:

  • Extract the property keys into private static final String constants (e.g., GREENCITY_SERVER_ADDRESS_KEY = "address"). This reduces string duplication and the risk of typos if these keys are reused elsewhere.
  • For getConnectionTimeout() and getResponseTimeout(), you may want to validate that the values are positive (and perhaps within a reasonable upper bound) to catch misconfigurations earlier.
  • The variable name systemEmailAddres has a minor typo; renaming it to systemEmailAddress will improve readability.

Functionally this class looks correct and it cleanly encapsulates the new configuration surface for remote web clients.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 36ffcb2 and 53dfda4.

📒 Files selected for processing (35)
  • core/src/main/java/greencity/controller/EcoNewsController.java (3 hunks)
  • core/src/main/java/greencity/controller/HabitAssignController.java (3 hunks)
  • core/src/main/java/greencity/webcontroller/ManagementController.java (3 hunks)
  • core/src/main/java/greencity/webcontroller/ManagementEventController.java (5 hunks)
  • core/src/main/resources/application.properties (1 hunks)
  • core/src/test/java/greencity/controller/EcoNewsControllerTest.java (3 hunks)
  • core/src/test/java/greencity/controller/HabitAssignControllerTest.java (2 hunks)
  • core/src/test/java/greencity/webcontroller/ManagementControllerTest.java (3 hunks)
  • core/src/test/java/greencity/webcontroller/ManagementEventControllerTest.java (2 hunks)
  • service-api/pom.xml (1 hunks)
  • service-api/src/main/java/greencity/client/RestClient.java (20 hunks)
  • service-api/src/main/java/greencity/client/config/UserRemoteClientConfig.java (2 hunks)
  • service-api/src/main/java/greencity/constant/ErrorMessage.java (1 hunks)
  • service-api/src/main/java/greencity/properties/AzureProperties.java (1 hunks)
  • service-api/src/main/java/greencity/properties/GoogleProperties.java (1 hunks)
  • service-api/src/main/java/greencity/properties/OpenAiProperties.java (1 hunks)
  • service-api/src/main/java/greencity/properties/RemoteWebClientProperties.java (1 hunks)
  • service-api/src/main/java/greencity/properties/SecurityProperties.java (1 hunks)
  • service-api/src/main/java/greencity/security/jwt/JwtTool.java (5 hunks)
  • service-api/src/test/java/greencity/client/RestClientTest.java (4 hunks)
  • service-api/src/test/java/greencity/client/UserRemoteClientConfigTest.java (3 hunks)
  • service-api/src/test/java/greencity/properties/AzurePropertiesTest.java (1 hunks)
  • service-api/src/test/java/greencity/properties/GooglePropertiesTest.java (1 hunks)
  • service-api/src/test/java/greencity/properties/OpenAiPropertiesTest.java (1 hunks)
  • service-api/src/test/java/greencity/properties/RemoteWebClientPropertiesTest.java (1 hunks)
  • service-api/src/test/java/greencity/properties/SecurityPropertiesTest.java (1 hunks)
  • service-api/src/test/java/greencity/security/jwt/JwtToolTest.java (2 hunks)
  • service/src/main/java/greencity/config/GoogleApiConfiguration.java (2 hunks)
  • service/src/main/java/greencity/service/CommentServiceImpl.java (0 hunks)
  • service/src/main/java/greencity/service/DatabaseBackupServiceImpl.java (3 hunks)
  • service/src/main/java/greencity/service/NotificationServiceImpl.java (3 hunks)
  • service/src/main/java/greencity/service/OpenAIServiceImpl.java (4 hunks)
  • service/src/test/java/greencity/service/DataBaseBackupServiceImplTest.java (2 hunks)
  • service/src/test/java/greencity/service/NotificationServiceImplTest.java (2 hunks)
  • service/src/test/java/greencity/service/OpenAIServiceImplTest.java (4 hunks)
💤 Files with no reviewable changes (1)
  • service/src/main/java/greencity/service/CommentServiceImpl.java
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-06-27T09:17:13.475Z
Learnt from: RostyslavZadyraichuk
Repo: ita-social-projects/GreenCity PR: 8681
File: service/src/main/java/greencity/service/OpenAIServiceImpl.java:162-184
Timestamp: 2025-06-27T09:17:13.475Z
Learning: In the GreenCity project's OpenAIServiceImpl, the user RostyslavZadyraichuk prefers a fail-fast approach for response parsing using try-catch blocks to handle NullPointerException and ClassCastException, converting them to domain-specific OpenAIResponseException. This approach avoids redundant null checks and follows the principle that exceptions should be exceptional, maintaining cleaner code.

Applied to files:

  • core/src/main/java/greencity/controller/EcoNewsController.java
  • core/src/test/java/greencity/controller/EcoNewsControllerTest.java
  • service/src/test/java/greencity/service/OpenAIServiceImplTest.java
  • service/src/main/java/greencity/service/OpenAIServiceImpl.java
📚 Learning: 2025-04-30T21:07:48.800Z
Learnt from: ChernenkoVitaliy
Repo: ita-social-projects/GreenCity PR: 8372
File: core/src/main/java/greencity/controller/ExportSettingsController.java:0-0
Timestamp: 2025-04-30T21:07:48.800Z
Learning: The GreenCity application has a custom Pageable configuration that sets default values (page 0, size 20) when not explicitly specified, making PageableDefault annotation unnecessary.

Applied to files:

  • core/src/main/java/greencity/controller/EcoNewsController.java
  • core/src/main/java/greencity/webcontroller/ManagementEventController.java
  • core/src/main/java/greencity/controller/HabitAssignController.java
  • service-api/src/main/java/greencity/client/RestClient.java
📚 Learning: 2025-08-22T15:53:22.505Z
Learnt from: RostyslavZadyraichuk
Repo: ita-social-projects/GreenCity PR: 8931
File: dao/src/main/java/greencity/repository/EcoNewsRelevanceRepo.java:12-22
Timestamp: 2025-08-22T15:53:22.505Z
Learning: When limiting JPQL query results to a fixed number (like "last 10 items"), use Pageable parameter with PageRequest.of(0, N) instead of JPQL LIMIT clause, which is not supported and causes runtime exceptions.

Applied to files:

  • core/src/main/java/greencity/controller/EcoNewsController.java
  • core/src/main/java/greencity/controller/HabitAssignController.java
📚 Learning: 2025-03-13T10:15:35.344Z
Learnt from: ChernenkoVitaliy
Repo: ita-social-projects/GreenCity PR: 8234
File: service/src/main/java/greencity/service/ExportSettingsServiceImpl.java:48-53
Timestamp: 2025-03-13T10:15:35.344Z
Learning: The ExportSettingsServiceImpl.getEnvironmentVariables method is designed to return all environment variables, and filtering is not required as the feature is secured through Spring Security and secretKey validation.

Applied to files:

  • service-api/src/main/java/greencity/properties/SecurityProperties.java
📚 Learning: 2025-06-27T08:41:16.994Z
Learnt from: RostyslavZadyraichuk
Repo: ita-social-projects/GreenCity PR: 8681
File: service/src/main/java/greencity/scheduler/EcoNewsGenerationJob.java:19-26
Timestamp: 2025-06-27T08:41:16.994Z
Learning: In the GreenCity project, the user RostyslavZadyraichuk prefers to handle retry logic and error handling at the service layer (OpenAIService) rather than adding additional error handling at the job level (EcoNewsGenerationJob). The OpenAIService already implements comprehensive retry logic with MAX_REQUEST_ATTEMPTS.

Applied to files:

  • core/src/test/java/greencity/controller/EcoNewsControllerTest.java
📚 Learning: 2025-03-14T16:22:58.043Z
Learnt from: maks741
Repo: ita-social-projects/GreenCity PR: 8244
File: service/src/main/java/greencity/service/UserNotificationServiceImpl.java:78-123
Timestamp: 2025-03-14T16:22:58.043Z
Learning: In UserNotificationServiceImpl, the use of .limit(2L * page.getPageSize()) when merging notifications from GreenCity and UBS is intentional. This ensures that all notifications from both sources can be accommodated without losing any data during the merging process.

Applied to files:

  • service-api/src/main/java/greencity/client/RestClient.java
📚 Learning: 2025-01-13T20:48:48.731Z
Learnt from: KostashchukIryna
Repo: ita-social-projects/GreenCity PR: 8022
File: core/src/main/resources/templates/core/header.html:23-25
Timestamp: 2025-01-13T20:48:48.731Z
Learning: In the GreenCity application, the logout endpoint "/management/logout" is configured to use GET method in SecurityConfig, which is the intended behavior for this application.

Applied to files:

  • core/src/main/java/greencity/webcontroller/ManagementController.java
🧬 Code graph analysis (10)
core/src/test/java/greencity/webcontroller/ManagementControllerTest.java (1)
core/src/test/java/greencity/TestConst.java (1)
  • TestConst (3-16)
service-api/src/main/java/greencity/properties/SecurityProperties.java (4)
service-api/src/main/java/greencity/properties/RemoteWebClientProperties.java (1)
  • Component (18-98)
service-api/src/main/java/greencity/properties/AzureProperties.java (1)
  • Component (18-48)
service-api/src/main/java/greencity/properties/GoogleProperties.java (1)
  • Component (11-41)
service-api/src/main/java/greencity/properties/OpenAiProperties.java (1)
  • Component (11-41)
service-api/src/test/java/greencity/properties/AzurePropertiesTest.java (4)
service-api/src/test/java/greencity/properties/GooglePropertiesTest.java (1)
  • ExtendWith (17-106)
service-api/src/test/java/greencity/properties/OpenAiPropertiesTest.java (1)
  • ExtendWith (17-97)
service-api/src/test/java/greencity/properties/RemoteWebClientPropertiesTest.java (1)
  • ExtendWith (17-216)
service-api/src/test/java/greencity/properties/SecurityPropertiesTest.java (1)
  • ExtendWith (17-102)
service-api/src/main/java/greencity/properties/OpenAiProperties.java (4)
service-api/src/main/java/greencity/properties/RemoteWebClientProperties.java (1)
  • Component (18-98)
service-api/src/main/java/greencity/properties/AzureProperties.java (1)
  • Component (18-48)
service-api/src/main/java/greencity/properties/GoogleProperties.java (1)
  • Component (11-41)
service-api/src/main/java/greencity/properties/SecurityProperties.java (1)
  • Component (11-42)
service-api/src/main/java/greencity/properties/AzureProperties.java (4)
service-api/src/main/java/greencity/properties/RemoteWebClientProperties.java (1)
  • Component (18-98)
service-api/src/main/java/greencity/properties/GoogleProperties.java (1)
  • Component (11-41)
service-api/src/main/java/greencity/properties/OpenAiProperties.java (1)
  • Component (11-41)
service-api/src/main/java/greencity/properties/SecurityProperties.java (1)
  • Component (11-42)
service-api/src/main/java/greencity/properties/RemoteWebClientProperties.java (2)
service/src/main/java/greencity/service/NotificationServiceImpl.java (1)
  • Slf4j (48-414)
service-api/src/main/java/greencity/client/RestClient.java (1)
  • Component (48-456)
service-api/src/main/java/greencity/properties/GoogleProperties.java (4)
service-api/src/main/java/greencity/properties/RemoteWebClientProperties.java (1)
  • Component (18-98)
service-api/src/main/java/greencity/properties/AzureProperties.java (1)
  • Component (18-48)
service-api/src/main/java/greencity/properties/OpenAiProperties.java (1)
  • Component (11-41)
service-api/src/main/java/greencity/properties/SecurityProperties.java (1)
  • Component (11-42)
service-api/src/test/java/greencity/properties/GooglePropertiesTest.java (4)
service-api/src/test/java/greencity/properties/AzurePropertiesTest.java (1)
  • ExtendWith (17-105)
service-api/src/test/java/greencity/properties/OpenAiPropertiesTest.java (1)
  • ExtendWith (17-97)
service-api/src/test/java/greencity/properties/RemoteWebClientPropertiesTest.java (1)
  • ExtendWith (17-216)
service-api/src/test/java/greencity/properties/SecurityPropertiesTest.java (1)
  • ExtendWith (17-102)
service-api/src/test/java/greencity/properties/OpenAiPropertiesTest.java (4)
service-api/src/test/java/greencity/properties/AzurePropertiesTest.java (1)
  • ExtendWith (17-105)
service-api/src/test/java/greencity/properties/GooglePropertiesTest.java (1)
  • ExtendWith (17-106)
service-api/src/test/java/greencity/properties/RemoteWebClientPropertiesTest.java (1)
  • ExtendWith (17-216)
service-api/src/test/java/greencity/properties/SecurityPropertiesTest.java (1)
  • ExtendWith (17-102)
service-api/src/test/java/greencity/properties/RemoteWebClientPropertiesTest.java (4)
service-api/src/test/java/greencity/properties/AzurePropertiesTest.java (1)
  • ExtendWith (17-105)
service-api/src/test/java/greencity/properties/GooglePropertiesTest.java (1)
  • ExtendWith (17-106)
service-api/src/test/java/greencity/properties/OpenAiPropertiesTest.java (1)
  • ExtendWith (17-97)
service-api/src/test/java/greencity/properties/SecurityPropertiesTest.java (1)
  • ExtendWith (17-102)
⏰ 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). (1)
  • GitHub Check: build
🔇 Additional comments (26)
service/src/main/java/greencity/config/GoogleApiConfiguration.java (2)

20-21: Clean delegation to property accessor.

The method correctly delegates API key retrieval to googleProperties.getGoogleApiKey(), maintaining the same functionality while benefiting from centralized property management. This allows the GoogleProperties class to handle validation, potential caching, or secret refresh logic transparently.


4-12: Verification confirmed—no issues found. All changes are sound.

The investigation confirms that GoogleProperties is properly configured as a Spring @Component and includes robust validation in getGoogleApiKey(). The method validates against null/empty values and throws IllegalStateException with a meaningful error message if the property is missing. Additionally, @PostConstruct ensures validation runs immediately upon bean initialization, catching configuration issues early.

The constructor injection pattern in GoogleApiConfiguration is correctly implemented and aligns perfectly with the centralized property management approach that enables future Azure Key Vault integration. The refactoring maintains clean, testable code while improving the architecture.

core/src/main/java/greencity/controller/EcoNewsController.java (1)

70-70: LGTM!

Good refactoring from @Value injection to constructor-injected property class. This improves testability and centralizes configuration management.

core/src/test/java/greencity/controller/EcoNewsControllerTest.java (1)

105-105: LGTM!

Reducing visibility from public to package-private for the setUp method is appropriate. The @BeforeEach annotation doesn't require public visibility.

core/src/test/java/greencity/webcontroller/ManagementControllerTest.java (1)

30-31: LGTM!

Excellent implementation of the property mock. The RemoteWebClientProperties mock is properly configured in the test, providing the expected server address value. This is a good pattern for other test files to follow.

Also applies to: 62-63

service-api/src/test/java/greencity/client/UserRemoteClientConfigTest.java (1)

33-34: LGTM!

Excellent and comprehensive mock setup. All required properties from RemoteWebClientProperties are properly configured:

  • Server address
  • Connection timeout
  • Response timeout
  • System email address

This is a great reference for how the property mocks should be configured in test files.

Also applies to: 57-61

service-api/src/test/java/greencity/security/jwt/JwtToolTest.java (1)

50-54: LGTM! Clean refactor to use SecurityProperties mock.

The migration from ReflectionTestUtils to mocking SecurityProperties is a cleaner approach that better reflects production dependency injection. The test setup now explicitly documents the required property values through the mock configuration.

service/src/test/java/greencity/service/NotificationServiceImplTest.java (1)

82-83: LGTM! Mock added to support refactored service.

The RemoteWebClientProperties mock correctly supports the NotificationServiceImpl's refactored dependency injection pattern. The test setup remains clean and focused.

core/src/main/java/greencity/controller/HabitAssignController.java (2)

66-66: LGTM! Clean dependency injection pattern.

The RemoteWebClientProperties field follows proper constructor injection via Lombok's @requiredargsconstructor. This centralizes configuration management as intended by the PR.


745-751: Code validation is properly implemented.

Verification confirms that RemoteWebClientProperties includes a @PostConstruct validateProperties() method that explicitly validates the client.address property at application startup. The getClientAddress() method checks that the property is non-empty and throws IllegalStateException with a descriptive error if missing. This prevents runtime failures when the endpoint constructs the redirect URL. The implementation is also covered by comprehensive unit tests confirming both success and failure scenarios.

service/src/main/java/greencity/service/NotificationServiceImpl.java (2)

61-61: LGTM! Proper dependency injection.

The RemoteWebClientProperties field is correctly injected via constructor, following the established pattern in this PR.


407-413: LGTM! URL construction updated correctly.

The createBaseLink method now uses remoteWebClientProperties.getClientAddress() consistently for both notification types. The conditional logic for EVENT_COMMENT vs. default notifications remains intact.

core/src/main/java/greencity/webcontroller/ManagementController.java (1)

47-59: LGTM! Redirect logic correctly updated.

The login method now uses remoteWebClientProperties.getGreencityUserServerAddress() to construct the redirect URL, properly centralizing the configuration.

service/src/main/java/greencity/service/DatabaseBackupServiceImpl.java (2)

42-42: LGTM! Proper dependency injection.

The AzureProperties field follows the correct constructor injection pattern with final modifier.


162-179: No action required—Azure properties are already validated at startup.

Verification confirms that AzureProperties correctly implements startup validation through a @PostConstruct method that validates both azure.connection.string and azure.container.name properties. Both getters throw IllegalStateException with descriptive error messages if properties are missing, ensuring fail-fast behavior. Comprehensive unit tests verify this validation logic works as expected. The code in DatabaseBackupServiceImpl is safe to use these properties.

service-api/src/test/java/greencity/properties/RemoteWebClientPropertiesTest.java (1)

1-216: LGTM! Comprehensive test coverage.

The test class provides thorough coverage of RemoteWebClientProperties:

  • All seven getters are tested for both success and failure paths
  • Validation logic is tested for success and failure scenarios
  • LogCaptor properly verifies error and info logs
  • Test structure is consistent with other property test classes in the PR

The tests follow good practices with clear arrange-act-assert patterns and meaningful assertions.

service/src/test/java/greencity/service/OpenAIServiceImplTest.java (1)

69-76: LGTM! Consistent refactor to use OpenAiProperties mock.

The test setup correctly migrates from ReflectionTestUtils to mocking OpenAiProperties for the API key, aligning with the broader PR pattern. The @MockitoSettings(strictness = Strictness.LENIENT) annotation is appropriate for this test suite's complexity. Other properties remain set via ReflectionTestUtils, which is acceptable as they may not be externalized in the current scope.

service-api/src/main/java/greencity/properties/GoogleProperties.java (1)

1-41: Consistent Google properties validation component

This class fits neatly into the shared properties pattern: constructor-injected Environment, @PostConstruct validation, and clear error signaling via specific ErrorMessage constants. The behavior is straightforward and matches the intended refactor away from scattered @Value usage.

service-api/src/main/java/greencity/security/jwt/JwtTool.java (1)

9-9: LGTM! Clean migration to centralized properties.

The refactoring successfully replaces scattered @Value annotations with dependency injection of SecurityProperties, improving maintainability and testability. All usages correctly delegate to the properties bean.

Also applies to: 39-39, 45-49, 85-85, 91-91, 102-102, 170-170

service/src/main/java/greencity/service/OpenAIServiceImpl.java (1)

10-10: LGTM! Consistent property migration.

The migration from direct @Value injection to OpenAiProperties aligns with the centralized configuration pattern. All API key references properly delegate to the properties bean.

Also applies to: 50-50, 52-62, 237-242, 258-270

core/src/main/java/greencity/webcontroller/ManagementEventController.java (1)

17-18: LGTM! Controller properly refactored to use centralized properties.

The migration from @Value annotations to RemoteWebClientProperties and GoogleProperties improves configuration management. All usages are correctly updated throughout the controller methods.

Also applies to: 91-92, 129-129, 193-195, 245-248

service-api/src/main/java/greencity/client/config/UserRemoteClientConfig.java (1)

15-15: LGTM! WebClient configuration properly centralized.

All configuration values (base URL, timeouts, system email) are now sourced from RemoteWebClientProperties, eliminating scattered @Value annotations and improving maintainability.

Also applies to: 38-38, 42-55, 57-70

service-api/src/test/java/greencity/properties/GooglePropertiesTest.java (1)

1-106: LGTM! Comprehensive test coverage.

The test class provides thorough coverage of GoogleProperties behavior, including success cases, missing property exceptions, and logging validation. The structure is consistent with other property test classes in the PR.

service-api/src/test/java/greencity/properties/SecurityPropertiesTest.java (1)

1-102: LGTM! Well-structured security property tests.

The test class provides comprehensive coverage of SecurityProperties, including token key and expiration validation. The structure is consistent with other property test classes, and all scenarios are properly tested.

service-api/src/test/java/greencity/properties/AzurePropertiesTest.java (1)

1-105: LGTM! Thorough Azure property testing.

The test class provides complete coverage of AzureProperties behavior, including connection string and container name validation. The testing approach is consistent with other property classes in this PR.

service-api/src/main/java/greencity/properties/RemoteWebClientProperties.java (1)

24-34: Fail-fast property validation is helpful; ensure all profiles define required keys

validateProperties() eagerly resolves all required properties at startup and fails fast with clear error messages if any are missing. That’s a good operational choice for critical configuration like base URLs, client address, timeouts, and system email, and it aligns with the new error constants.

Because this runs in @PostConstruct, any missing property will prevent the application context from starting. Please double-check that all active Spring profiles (including test and local dev) define these keys, otherwise some contexts may start failing unexpectedly.

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: 0

🧹 Nitpick comments (1)
service-api/src/main/java/greencity/properties/OpenAiProperties.java (1)

33-40: Consider using Boolean type for the relevance flag.

The property name greencity.relevance.enabled follows the convention for boolean flags, but the method returns a String. This creates ambiguity about valid values and requires string comparison in consuming code.

Consider refactoring to use a boolean type for type safety and clarity:

-public String getRelevance() {
-    String relevance = environment.getProperty("greencity.relevance.enabled");
-    if (!StringUtils.hasText(relevance)) {
-        log.error(ErrorMessage.RELEVANCE_NOT_SET);
-        throw new IllegalStateException(ErrorMessage.RELEVANCE_NOT_SET);
-    }
-    return relevance;
+public Boolean getRelevance() {
+    Boolean relevance = environment.getProperty("greencity.relevance.enabled", Boolean.class);
+    if (relevance == null) {
+        log.error(ErrorMessage.RELEVANCE_NOT_SET);
+        throw new IllegalStateException(ErrorMessage.RELEVANCE_NOT_SET);
+    }
+    return relevance;
}

This aligns with Spring Boot conventions where .enabled properties are typically boolean, and makes the intent clearer to maintainers.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 53dfda4 and 8942a71.

📒 Files selected for processing (9)
  • core/src/main/java/greencity/webcontroller/ManagementController.java (3 hunks)
  • core/src/test/java/greencity/controller/EcoNewsControllerTest.java (4 hunks)
  • core/src/test/java/greencity/controller/HabitAssignControllerTest.java (3 hunks)
  • core/src/test/java/greencity/webcontroller/ManagementEventControllerTest.java (2 hunks)
  • service-api/pom.xml (1 hunks)
  • service-api/src/main/java/greencity/client/RestClient.java (20 hunks)
  • service-api/src/main/java/greencity/properties/OpenAiProperties.java (1 hunks)
  • service-api/src/test/java/greencity/properties/OpenAiPropertiesTest.java (1 hunks)
  • service/src/test/java/greencity/service/DataBaseBackupServiceImplTest.java (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • service-api/pom.xml
  • service-api/src/test/java/greencity/properties/OpenAiPropertiesTest.java
  • service-api/src/main/java/greencity/client/RestClient.java
  • service/src/test/java/greencity/service/DataBaseBackupServiceImplTest.java
  • core/src/test/java/greencity/webcontroller/ManagementEventControllerTest.java
  • core/src/test/java/greencity/controller/HabitAssignControllerTest.java
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-06-27T09:17:13.475Z
Learnt from: RostyslavZadyraichuk
Repo: ita-social-projects/GreenCity PR: 8681
File: service/src/main/java/greencity/service/OpenAIServiceImpl.java:162-184
Timestamp: 2025-06-27T09:17:13.475Z
Learning: In the GreenCity project's OpenAIServiceImpl, the user RostyslavZadyraichuk prefers a fail-fast approach for response parsing using try-catch blocks to handle NullPointerException and ClassCastException, converting them to domain-specific OpenAIResponseException. This approach avoids redundant null checks and follows the principle that exceptions should be exceptional, maintaining cleaner code.

Applied to files:

  • core/src/test/java/greencity/controller/EcoNewsControllerTest.java
📚 Learning: 2025-06-27T08:41:16.994Z
Learnt from: RostyslavZadyraichuk
Repo: ita-social-projects/GreenCity PR: 8681
File: service/src/main/java/greencity/scheduler/EcoNewsGenerationJob.java:19-26
Timestamp: 2025-06-27T08:41:16.994Z
Learning: In the GreenCity project, the user RostyslavZadyraichuk prefers to handle retry logic and error handling at the service layer (OpenAIService) rather than adding additional error handling at the job level (EcoNewsGenerationJob). The OpenAIService already implements comprehensive retry logic with MAX_REQUEST_ATTEMPTS.

Applied to files:

  • core/src/test/java/greencity/controller/EcoNewsControllerTest.java
📚 Learning: 2025-01-13T20:48:48.731Z
Learnt from: KostashchukIryna
Repo: ita-social-projects/GreenCity PR: 8022
File: core/src/main/resources/templates/core/header.html:23-25
Timestamp: 2025-01-13T20:48:48.731Z
Learning: In the GreenCity application, the logout endpoint "/management/logout" is configured to use GET method in SecurityConfig, which is the intended behavior for this application.

Applied to files:

  • core/src/main/java/greencity/webcontroller/ManagementController.java
🧬 Code graph analysis (1)
service-api/src/main/java/greencity/properties/OpenAiProperties.java (4)
service-api/src/main/java/greencity/properties/RemoteWebClientProperties.java (1)
  • Component (18-98)
service-api/src/main/java/greencity/properties/AzureProperties.java (1)
  • Component (18-48)
service-api/src/main/java/greencity/properties/GoogleProperties.java (1)
  • Component (11-41)
service-api/src/main/java/greencity/properties/SecurityProperties.java (1)
  • Component (11-42)
⏰ 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). (1)
  • GitHub Check: build
🔇 Additional comments (7)
core/src/main/java/greencity/webcontroller/ManagementController.java (2)

15-15: Good implementation with final modifier.

The field is properly declared as private final, ensuring immutability and making the constructor injection contract explicit. This addresses previous feedback and aligns with best practices for dependency injection.


50-54: Code change is verified and approved.

The RemoteWebClientProperties.getGreencityUserServerAddress() method properly validates the configuration property on application startup via @PostConstruct, throwing an IllegalStateException if the property is missing or empty. The UriComponentsBuilder approach correctly handles URL construction with proper path appending, making the refactoring to centralized configuration a solid improvement.

service-api/src/main/java/greencity/properties/OpenAiProperties.java (3)

11-15: LGTM! Consistent pattern with other property classes.

The class structure follows the established pattern used in RemoteWebClientProperties, AzureProperties, GoogleProperties, and SecurityProperties. Using @Component with constructor injection via @RequiredArgsConstructor is clean and idiomatic.


17-22: LGTM! Fail-fast validation at startup.

The @PostConstruct validation ensures properties are validated when the bean is initialized, preventing runtime failures later. This matches the pattern used in other property classes.


24-31: LGTM! Proper validation and error handling.

The method correctly validates the property existence using StringUtils.hasText() and provides clear error messages. The pattern is consistent with other property accessor methods in the codebase.

core/src/test/java/greencity/controller/EcoNewsControllerTest.java (2)

22-22: LGTM! Mock field properly added.

The import and mock field for OpenAiProperties are correctly added to support the controller's new dependency.

Also applies to: 89-89


120-121: Mock configuration addresses the past review comment.

The openAiProperties.getRelevance() mock is now properly configured in the setUp() method, which resolves the concern raised in the previous review. All tests using relevance checks will now have the expected behavior.

Note: The mock returns "enabled" as a String, which is consistent with the current OpenAiProperties.getRelevance() API. If that method is refactored to return a Boolean (as suggested in the OpenAiProperties review), this test setup will need to be updated accordingly.

@sonarqubecloud
Copy link

@SashaPog SashaPog merged commit 21d9722 into dev Nov 17, 2025
4 checks passed
@SashaPog SashaPog deleted the feature/9272/automatic-secret-refresh-from-azure branch November 17, 2025 16:47
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.

5 participants