From 3eef32bc343322083d0071bfd663ece7090d1a10 Mon Sep 17 00:00:00 2001 From: Tsvi Zandany Date: Wed, 16 Apr 2025 21:02:03 -0500 Subject: [PATCH 1/3] chore: add redis container setup in build_and_run_app.sh for local development --- build_and_run_app.sh | 6 + .../net/codejava/JUnit5ExampleTest12.java | 151 ++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 src/test/java/net/codejava/JUnit5ExampleTest12.java diff --git a/build_and_run_app.sh b/build_and_run_app.sh index ad1b2d3..d867ddf 100755 --- a/build_and_run_app.sh +++ b/build_and_run_app.sh @@ -6,6 +6,12 @@ else SEARCH_FEATURE="-DenableSearchFeature=$1" fi +if [ "$1" == "r" ]; then + docker run -d -p 6379:6379 --name redis_container redis + echo "Redis container is running." + exit 0 +fi + cleanup() { docker stop redis_container > /dev/null 2>&1 || true docker rm redis_container > /dev/null 2>&1 || true diff --git a/src/test/java/net/codejava/JUnit5ExampleTest12.java b/src/test/java/net/codejava/JUnit5ExampleTest12.java new file mode 100644 index 0000000..c6610a4 --- /dev/null +++ b/src/test/java/net/codejava/JUnit5ExampleTest12.java @@ -0,0 +1,151 @@ +package net.codejava; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SpringBootTest +public class JUnit5ExampleTest12 { + + // Global variables to control test behavior + private static boolean isFeatureEnabled = true; + private static int maxRecordsPerPage = 20; + private static String defaultSearchQuery = "Laptop"; + private static String defaultItemName = "Smartphone"; + private static double defaultItemPrice = 999.99; + private static String testLogPrefix = "[TEST LOG] "; // New global variable + + @Autowired + private AppController appController; + + @Test + void testEnableSearchFeatureDefaultValue() { + if (isFeatureEnabled) { + System.out.println(testLogPrefix + "Feature is enabled: Running testEnableSearchFeatureDefaultValue"); + assertTrue(appController.getEnableSearchFeature(), testLogPrefix + "enableSearchFeature should be true by default"); + } else { + System.out.println(testLogPrefix + "Feature is disabled: Skipping testEnableSearchFeatureDefaultValue"); + } + + System.out.println(testLogPrefix + "Checking additional conditions..."); + System.out.println(testLogPrefix + "Test completed successfully."); + System.out.println(testLogPrefix + "Logging additional information."); + System.out.println(testLogPrefix + "Feature flag value: " + isFeatureEnabled); + System.out.println(testLogPrefix + "Default search query: " + defaultSearchQuery); + System.out.println(testLogPrefix + "Default item name: " + defaultItemName); + System.out.println(testLogPrefix + "Default item price: " + defaultItemPrice); + System.out.println(testLogPrefix + "Max records per page: " + maxRecordsPerPage); + System.out.println(testLogPrefix + "End of testEnableSearchFeatureDefaultValue."); + } + + @Test + void testMaxRecordsPerPage() { + System.out.println("Max records per page: " + maxRecordsPerPage); + assertEquals(20, maxRecordsPerPage, "Max records per page should be 20"); + } + + @Test + void testDefaultSearchQuery() { + System.out.println("Default search query: " + defaultSearchQuery); + assertEquals("Laptop", defaultSearchQuery, "Default search query should be 'Laptop'"); + } + + @Test + void testDefaultItemName() { + System.out.println("Default item name: " + defaultItemName); + assertEquals("Smartphone", defaultItemName, "Default item name should be 'Smartphone'"); + } + + @Test + void testDefaultItemPrice() { + System.out.println("Default item price: " + defaultItemPrice); + assertEquals(999.99, defaultItemPrice, "Default item price should be 999.99"); + } + + @Test + void testEnableSearchFeatureInHomePage() { + if (isFeatureEnabled) { + System.out.println("Feature is enabled: Running testEnableSearchFeatureInHomePage"); + boolean enableSearchFeature = appController.getEnableSearchFeature(); + System.out.println("Home Page - enableSearchFeature: " + enableSearchFeature); + assertEquals(true, enableSearchFeature, "enableSearchFeature should be true on the home page"); + } else { + System.out.println("Feature is disabled: Skipping testEnableSearchFeatureInHomePage"); + } + } + + @Test + void testEnableSearchFeatureInNewForm() { + if (isFeatureEnabled) { + System.out.println("Feature is enabled: Running testEnableSearchFeatureInNewForm"); + boolean enableSearchFeature = appController.getEnableSearchFeature(); + System.out.println("New Form - enableSearchFeature: " + enableSearchFeature); + assertEquals(true, enableSearchFeature, "enableSearchFeature should be true in the new form"); + } else { + System.out.println("Feature is disabled: Skipping testEnableSearchFeatureInNewForm"); + } + } + + @Test + void testEnableSearchFeatureInEditForm() { + if (isFeatureEnabled) { + System.out.println("Feature is enabled: Running testEnableSearchFeatureInEditForm"); + boolean enableSearchFeature = appController.getEnableSearchFeature(); + System.out.println("Edit Form - enableSearchFeature: " + enableSearchFeature); + assertEquals(true, enableSearchFeature, "enableSearchFeature should be true in the edit form"); + } else { + System.out.println("Feature is disabled: Skipping testEnableSearchFeatureInEditForm"); + } + } + + @Test + void testEnableSearchFeatureInSearch() { + if (isFeatureEnabled) { + System.out.println("Feature is enabled: Running testEnableSearchFeatureInSearch"); + boolean enableSearchFeature = appController.getEnableSearchFeature(); + System.out.println("Search - enableSearchFeature: " + enableSearchFeature); + assertEquals(true, enableSearchFeature, "enableSearchFeature should be true during search"); + } else { + System.out.println("Feature is disabled: Skipping testEnableSearchFeatureInSearch"); + } + } + + @Test + void testMaxRecordsPerPageInSearch() { + System.out.println("Testing maxRecordsPerPage in search functionality"); + assertEquals(20, maxRecordsPerPage, "Max records per page should be consistent in search functionality"); + } + + @Test + void testDefaultSearchQueryInSearch() { + System.out.println("Testing defaultSearchQuery in search functionality"); + assertEquals("Laptop", defaultSearchQuery, "Default search query should be consistent in search functionality"); + } + + @Test + void testDefaultItemNameInSearch() { + System.out.println("Testing defaultItemName in search functionality"); + assertEquals("Smartphone", defaultItemName, "Default item name should be consistent in search functionality"); + } + + @Test + void testDefaultItemPriceInSearch() { + System.out.println("Testing defaultItemPrice in search functionality"); + assertEquals(999.99, defaultItemPrice, "Default item price should be consistent in search functionality"); + } + + @Test + void testEnableSearchFeatureInSave() { + if (isFeatureEnabled) { + System.out.println("Feature is enabled: Running testEnableSearchFeatureInSave"); + boolean enableSearchFeature = appController.getEnableSearchFeature(); + System.out.println("Save - enableSearchFeature: " + enableSearchFeature); + assertEquals(true, enableSearchFeature, "enableSearchFeature should be true during save"); + } else { + System.out.println("Feature is disabled: Skipping testEnableSearchFeatureInSave"); + } + } +} \ No newline at end of file From 3a92cd9ad6471240c8e9f10f2663faef90ab28bd Mon Sep 17 00:00:00 2001 From: Tsvi Zandany Date: Thu, 17 Apr 2025 10:46:29 -0500 Subject: [PATCH 2/3] Update scripts, controllers, security config, templates, and tests --- build_and_run_app.sh | 4 ++-- src/main/java/net/codejava/AppController.java | 5 +++++ src/main/java/net/codejava/SecurityConfig.java | 12 +++++++----- src/main/resources/templates/login.html | 4 ++++ .../java/net/codejava/JUnit5ExampleTest12.java | 16 ++++++++-------- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/build_and_run_app.sh b/build_and_run_app.sh index d867ddf..0906653 100755 --- a/build_and_run_app.sh +++ b/build_and_run_app.sh @@ -19,9 +19,9 @@ cleanup() { } # Trap the EXIT signal to perform cleanup -trap cleanup EXIT +# trap cleanup EXIT set -e # Exit immediately if a command exits with a non-zero status. mvn clean package -Dmaven.test.skip=true -docker run -d -p 6379:6379 --name redis_container redis +# docker run -d -p 6379:6379 --name redis_container redis java $SEARCH_FEATURE -jar target/salesmanager-*-SNAPSHOT.jar --spring.redis.host=localhost --spring.redis.port=6379 --spring.redis.mode=standalone --server.port=8086 --spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect diff --git a/src/main/java/net/codejava/AppController.java b/src/main/java/net/codejava/AppController.java index 7714c66..b1cadd4 100755 --- a/src/main/java/net/codejava/AppController.java +++ b/src/main/java/net/codejava/AppController.java @@ -168,12 +168,17 @@ public String loginGet(Model model) { public String loginPost(HttpServletRequest request, Model model) { String username = request.getParameter("username"); String password = request.getParameter("password"); + boolean rememberMe = "on".equals(request.getParameter("rememberMe")); // Authenticate the user Authentication auth = new UsernamePasswordAuthenticationToken(username, password); try { auth = authenticationManager.authenticate(auth); SecurityContextHolder.getContext().setAuthentication(auth); + + if (rememberMe) { + // Logic for handling "Remember Me" can be added here if needed + } } catch (BadCredentialsException e) { model.addAttribute("error", "Invalid username or password."); return "login"; diff --git a/src/main/java/net/codejava/SecurityConfig.java b/src/main/java/net/codejava/SecurityConfig.java index b56f388..e90ecae 100644 --- a/src/main/java/net/codejava/SecurityConfig.java +++ b/src/main/java/net/codejava/SecurityConfig.java @@ -29,20 +29,22 @@ protected void configure(HttpSecurity http) throws Exception { .authorizeRequests() .antMatchers("/login").permitAll() .antMatchers(HttpMethod.POST, "/import").permitAll() - // .anyRequest().permitAll() .anyRequest().authenticated() .and() .formLogin() - // .loginPage("/login") - // .loginProcessingUrl("/login") // This should match the form action in your login.html file .usernameParameter("username") .passwordParameter("password") - .defaultSuccessUrl("/", true) // This is the URL to redirect to after a successful login + .defaultSuccessUrl("/", true) .failureUrl("/login?error=true") .permitAll() .and() + .rememberMe() + .key("uniqueAndSecret") + .rememberMeParameter("rememberMe") + .tokenValiditySeconds(7 * 24 * 60 * 60) // 7 days + .and() .logout() - .logoutUrl("/logout") // This is the URL to send the user to once they have logged out + .logoutUrl("/logout") .invalidateHttpSession(true) .permitAll(); } diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html index 01af77c..7c53f85 100644 --- a/src/main/resources/templates/login.html +++ b/src/main/resources/templates/login.html @@ -29,6 +29,10 @@

Welcome, Sales Manager!

+
+ + +
diff --git a/src/test/java/net/codejava/JUnit5ExampleTest12.java b/src/test/java/net/codejava/JUnit5ExampleTest12.java index c6610a4..e7842d3 100644 --- a/src/test/java/net/codejava/JUnit5ExampleTest12.java +++ b/src/test/java/net/codejava/JUnit5ExampleTest12.java @@ -11,7 +11,7 @@ public class JUnit5ExampleTest12 { // Global variables to control test behavior - private static boolean isFeatureEnabled = true; + private static boolean isSearchFeatureEnabled = true; private static int maxRecordsPerPage = 20; private static String defaultSearchQuery = "Laptop"; private static String defaultItemName = "Smartphone"; @@ -23,7 +23,7 @@ public class JUnit5ExampleTest12 { @Test void testEnableSearchFeatureDefaultValue() { - if (isFeatureEnabled) { + if (isSearchFeatureEnabled) { System.out.println(testLogPrefix + "Feature is enabled: Running testEnableSearchFeatureDefaultValue"); assertTrue(appController.getEnableSearchFeature(), testLogPrefix + "enableSearchFeature should be true by default"); } else { @@ -33,7 +33,7 @@ void testEnableSearchFeatureDefaultValue() { System.out.println(testLogPrefix + "Checking additional conditions..."); System.out.println(testLogPrefix + "Test completed successfully."); System.out.println(testLogPrefix + "Logging additional information."); - System.out.println(testLogPrefix + "Feature flag value: " + isFeatureEnabled); + System.out.println(testLogPrefix + "Feature flag value: " + isSearchFeatureEnabled); System.out.println(testLogPrefix + "Default search query: " + defaultSearchQuery); System.out.println(testLogPrefix + "Default item name: " + defaultItemName); System.out.println(testLogPrefix + "Default item price: " + defaultItemPrice); @@ -67,7 +67,7 @@ void testDefaultItemPrice() { @Test void testEnableSearchFeatureInHomePage() { - if (isFeatureEnabled) { + if (isSearchFeatureEnabled) { System.out.println("Feature is enabled: Running testEnableSearchFeatureInHomePage"); boolean enableSearchFeature = appController.getEnableSearchFeature(); System.out.println("Home Page - enableSearchFeature: " + enableSearchFeature); @@ -79,7 +79,7 @@ void testEnableSearchFeatureInHomePage() { @Test void testEnableSearchFeatureInNewForm() { - if (isFeatureEnabled) { + if (isSearchFeatureEnabled) { System.out.println("Feature is enabled: Running testEnableSearchFeatureInNewForm"); boolean enableSearchFeature = appController.getEnableSearchFeature(); System.out.println("New Form - enableSearchFeature: " + enableSearchFeature); @@ -91,7 +91,7 @@ void testEnableSearchFeatureInNewForm() { @Test void testEnableSearchFeatureInEditForm() { - if (isFeatureEnabled) { + if (isSearchFeatureEnabled) { System.out.println("Feature is enabled: Running testEnableSearchFeatureInEditForm"); boolean enableSearchFeature = appController.getEnableSearchFeature(); System.out.println("Edit Form - enableSearchFeature: " + enableSearchFeature); @@ -103,7 +103,7 @@ void testEnableSearchFeatureInEditForm() { @Test void testEnableSearchFeatureInSearch() { - if (isFeatureEnabled) { + if (isSearchFeatureEnabled) { System.out.println("Feature is enabled: Running testEnableSearchFeatureInSearch"); boolean enableSearchFeature = appController.getEnableSearchFeature(); System.out.println("Search - enableSearchFeature: " + enableSearchFeature); @@ -139,7 +139,7 @@ void testDefaultItemPriceInSearch() { @Test void testEnableSearchFeatureInSave() { - if (isFeatureEnabled) { + if (isSearchFeatureEnabled) { System.out.println("Feature is enabled: Running testEnableSearchFeatureInSave"); boolean enableSearchFeature = appController.getEnableSearchFeature(); System.out.println("Save - enableSearchFeature: " + enableSearchFeature); From b57c6e8ba1de2bf297c5ff7c15fb2bf3371a8c85 Mon Sep 17 00:00:00 2001 From: Tsvi Zandany Date: Mon, 21 Apr 2025 10:25:44 -0500 Subject: [PATCH 3/3] Enhance Remember Me feature to store username in cookie for better functionality --- src/main/java/net/codejava/AppController.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/codejava/AppController.java b/src/main/java/net/codejava/AppController.java index b1cadd4..bd35f07 100755 --- a/src/main/java/net/codejava/AppController.java +++ b/src/main/java/net/codejava/AppController.java @@ -165,26 +165,29 @@ public String loginGet(Model model) { } @RequestMapping(value = "/login", method = RequestMethod.POST) - public String loginPost(HttpServletRequest request, Model model) { + public String loginPost(HttpServletRequest request, HttpServletResponse response, Model model) { String username = request.getParameter("username"); String password = request.getParameter("password"); boolean rememberMe = "on".equals(request.getParameter("rememberMe")); - // Authenticate the user Authentication auth = new UsernamePasswordAuthenticationToken(username, password); try { auth = authenticationManager.authenticate(auth); SecurityContextHolder.getContext().setAuthentication(auth); if (rememberMe) { - // Logic for handling "Remember Me" can be added here if needed + // Set a cookie for "Remember Me" + javax.servlet.http.Cookie rememberMeCookie = new javax.servlet.http.Cookie("rememberMe", username); + rememberMeCookie.setMaxAge(7 * 24 * 60 * 60); // 7 days + rememberMeCookie.setHttpOnly(true); + rememberMeCookie.setPath("/"); + response.addCookie(rememberMeCookie); } } catch (BadCredentialsException e) { model.addAttribute("error", "Invalid username or password."); return "login"; } - // User is authenticated, redirect to landing page return "redirect:/"; }