diff --git a/src/main/java/org/springframework/samples/petclinic/featureflag/aspect/FeatureToggleAspect.java b/src/main/java/org/springframework/samples/petclinic/featureflag/aspect/FeatureToggleAspect.java index e69471b92..00554ac82 100644 --- a/src/main/java/org/springframework/samples/petclinic/featureflag/aspect/FeatureToggleAspect.java +++ b/src/main/java/org/springframework/samples/petclinic/featureflag/aspect/FeatureToggleAspect.java @@ -46,6 +46,7 @@ public class FeatureToggleAspect { } // Check if feature is enabled + logger.debug("Checking feature toggle '{}' with context '{}'", flagKey, context); boolean isEnabled = featureFlagService.isFeatureEnabled(flagKey, context); logger.debug("Feature toggle '{}' check: enabled={}, context={}", flagKey, isEnabled, context); diff --git a/src/main/java/org/springframework/samples/petclinic/featureflag/controller/FeatureFlagController.java b/src/main/java/org/springframework/samples/petclinic/featureflag/controller/FeatureFlagController.java index aa1d0a2b1..992d80b5f 100644 --- a/src/main/java/org/springframework/samples/petclinic/featureflag/controller/FeatureFlagController.java +++ b/src/main/java/org/springframework/samples/petclinic/featureflag/controller/FeatureFlagController.java @@ -106,7 +106,7 @@ public class FeatureFlagController { } /** - * POST /api/feature-flags/{flagKey}/toggle Toggle a feature flag on/off + * POST /feature-flags/{flagKey}/toggle Toggle a feature flag on/off */ @PostMapping("/{flagKey}/toggle") public ResponseEntity toggleFlag(@PathVariable String flagKey) { @@ -130,7 +130,7 @@ public class FeatureFlagController { } /** - * GET /api/feature-flags/check/{flagKey} Check if a feature is enabled (simple check + * GET /feature-flags/check/{flagKey} Check if a feature is enabled (simple check * without context) */ @GetMapping("/check/{flagKey}") diff --git a/src/main/java/org/springframework/samples/petclinic/featureflag/service/FeatureFlagService.java b/src/main/java/org/springframework/samples/petclinic/featureflag/service/FeatureFlagService.java index 319b1a239..92bad1c8a 100644 --- a/src/main/java/org/springframework/samples/petclinic/featureflag/service/FeatureFlagService.java +++ b/src/main/java/org/springframework/samples/petclinic/featureflag/service/FeatureFlagService.java @@ -106,6 +106,9 @@ public class FeatureFlagService { case PERCENTAGE: return evaluatePercentage(flag, context); + + case GLOBAL_DISABLE: + return false; default: logger.warn("Unknown flag type for '{}': {}", flag.getFlagKey(), flag.getFlagType()); @@ -121,7 +124,8 @@ public class FeatureFlagService { logger.debug("Whitelist flag '{}' requires context, got null/empty", flag.getFlagKey()); return false; } - + logger.debug("Whitelist flag '{}' - checking if context '{}' is in whitelist: {}", flag.getFlagKey(), context, + flag.getWhitelist()); boolean inWhitelist = flag.getWhitelist().contains(context.trim()); logger.debug("Whitelist flag '{}' for context '{}': {}", flag.getFlagKey(), context, inWhitelist); return inWhitelist; diff --git a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java b/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java index a70851969..ab4564bf6 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java @@ -22,6 +22,7 @@ import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import org.springframework.samples.petclinic.featureflag.annotation.FeatureToggle; import org.springframework.samples.petclinic.featureflag.service.FeatureFlagService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -90,13 +91,27 @@ class OwnerController { } @GetMapping("/owners/find") - public String initFindForm() { + public String initFindForm(Model model) { + model.addAttribute("owner", new Owner()); + + boolean ownerSearchEnabled = + featureFlagService.isFeatureEnabled("OWNER_SEARCH", null); + + model.addAttribute("ownerSearchEnabled", ownerSearchEnabled); return "owners/findOwners"; } + @FeatureToggle( + key = "OWNER_SEARCH", + disabledMessage = "Owner search is restricted", + disabledRedirect = "/owners/find" + ) @GetMapping("/owners") public String processFindForm(@RequestParam(defaultValue = "1") int page, Owner owner, BindingResult result, Model model) { + + + // allow parameterless GET request for /owners to return all records String lastName = owner.getLastName(); if (lastName == null) { @@ -176,6 +191,8 @@ class OwnerController { // displaying add pet button based on feature toggle boolean addNewPetEnabled = featureFlagService.isFeatureEnabled("ADD_NEW_PET","addNewPetEnabled"); + boolean addVisitEnabled = featureFlagService.isFeatureEnabled("ADD_VISIT","addVisitEnabled"); + mav.addObject("addVisitEnabled", addVisitEnabled); mav.addObject("addNewPetEnabled", addNewPetEnabled); return mav; } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java b/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java index cc3e3ce1a..a415d8f0f 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java @@ -18,6 +18,7 @@ package org.springframework.samples.petclinic.owner; import java.util.Map; import java.util.Optional; +import org.springframework.samples.petclinic.featureflag.annotation.FeatureToggle; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.WebDataBinder; @@ -81,6 +82,7 @@ class VisitController { // Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is // called + @FeatureToggle(key = "ADD_VISIT", disabledMessage = "Adding visits is currently disabled", disabledRedirect = "/owners/{ownerId}") @GetMapping("/owners/{ownerId}/pets/{petId}/visits/new") public String initNewVisitForm() { return "pets/createOrUpdateVisitForm"; @@ -88,6 +90,7 @@ class VisitController { // Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is // called + @FeatureToggle(key = "ADD_VISIT", disabledMessage = "Adding visits is currently disabled", disabledRedirect = "/owners/{ownerId}") @PostMapping("/owners/{ownerId}/pets/{petId}/visits/new") public String processNewVisitForm(@ModelAttribute Owner owner, @PathVariable int petId, @Valid Visit visit, BindingResult result, RedirectAttributes redirectAttributes) { diff --git a/src/main/resources/db/mysql/data.sql b/src/main/resources/db/mysql/data.sql index ac50e4f77..b132c6d33 100644 --- a/src/main/resources/db/mysql/data.sql +++ b/src/main/resources/db/mysql/data.sql @@ -65,14 +65,14 @@ VALUES ('ADD_VISIT', 'Controls whether users can add new visits for pets', 'SIMP -- 3. WHITELIST flag: Owner Search (only specific users can search) INSERT IGNORE INTO feature_flags (flag_key, description, flag_type, enabled, percentage, created_at, updated_at) -VALUES ('OWNER_SEARCH', 'Controls who can search for owners', 'WHITELIST', TRUE, NULL, NOW(), NOW()); +VALUES ('OWNER_SEARCH', 'Controls who can search for owners', 'SIMPLE', TRUE, NULL, NOW(), NOW()); -- Add whitelist items for owner-search (example user contexts) -INSERT IGNORE INTO feature_flag_whitelist (feature_flag_id, whitelist) -SELECT id, 'admin' FROM feature_flags WHERE flag_key = 'OWNER_SEARCH'; +-- INSERT IGNORE INTO feature_flag_whitelist (feature_flag_id, whitelist) +-- SELECT id, 'admin' FROM feature_flags WHERE flag_key = 'OWNER_SEARCH'; -INSERT IGNORE INTO feature_flag_whitelist (feature_flag_id, whitelist) -SELECT id, 'Ramprakash' FROM feature_flags WHERE flag_key = 'OWNER_SEARCH'; +-- INSERT IGNORE INTO feature_flag_whitelist (feature_flag_id, whitelist) +-- SELECT id, 'Ramprakash' FROM feature_flags WHERE flag_key = 'OWNER_SEARCH'; -- 4. PERCENTAGE flag: New UI Theme (gradually roll out to 50% of users) INSERT IGNORE INTO feature_flags (flag_key, description, flag_type, enabled, percentage, created_at, updated_at) diff --git a/src/main/resources/templates/owners/findOwners.html b/src/main/resources/templates/owners/findOwners.html index 703351c7d..3a43e1ac0 100644 --- a/src/main/resources/templates/owners/findOwners.html +++ b/src/main/resources/templates/owners/findOwners.html @@ -20,13 +20,14 @@ -
+
Add Owner + diff --git a/src/main/resources/templates/owners/ownerDetails.html b/src/main/resources/templates/owners/ownerDetails.html index 1f298533f..19f49b03c 100644 --- a/src/main/resources/templates/owners/ownerDetails.html +++ b/src/main/resources/templates/owners/ownerDetails.html @@ -70,7 +70,7 @@ Edit Pet - Add Visit + Add Visit