Subject: [PATCH] boot4_4_fix_userCache
---
Index: src/test/java/ru/javaops/bootjava/user/web/ProfileControllerTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/test/java/ru/javaops/bootjava/user/web/ProfileControllerTest.java b/src/test/java/ru/javaops/bootjava/user/web/ProfileControllerTest.java
--- a/src/test/java/ru/javaops/bootjava/user/web/ProfileControllerTest.java	(revision 97c957acb43aba3fea4fa1413ae0cc4b4a0e4395)
+++ b/src/test/java/ru/javaops/bootjava/user/web/ProfileControllerTest.java	(date 1765565342495)
@@ -87,6 +87,25 @@
                 .andExpect(status().isUnprocessableContent());
     }
 
+    @Test
+    void updateEmail() throws Exception {
+        perform(MockMvcRequestBuilders.get(REST_URL)
+                .with(userHttpBasic(user)))
+                .andExpect(status().isOk());
+
+        UserTo updatedTo = new UserTo(null, "newName", NEW_MAIL, "newPassword");
+        perform(MockMvcRequestBuilders.put(REST_URL).contentType(MediaType.APPLICATION_JSON)
+                .with(userHttpBasic(user))
+                .content(JsonUtil.writeValue(updatedTo)))
+                .andDo(print())
+                .andExpect(status().isNoContent());
+        USER_MATCHER.assertMatch(repository.getExisted(USER_ID), UsersUtil.updateFromTo(new User(user), updatedTo));
+
+        perform(MockMvcRequestBuilders.get(REST_URL)
+                .with(userHttpBasic(user)))
+                .andExpect(status().isUnauthorized());
+    }
+
     @Test
     @WithUserDetails(value = USER_MAIL)
     void updateInvalid() throws Exception {
Index: src/test/resources/application-test.yaml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/test/resources/application-test.yaml b/src/test/resources/application-test.yaml
--- a/src/test/resources/application-test.yaml	(revision 97c957acb43aba3fea4fa1413ae0cc4b4a0e4395)
+++ b/src/test/resources/application-test.yaml	(date 1765563122713)
@@ -1,1 +1,1 @@
-spring.cache.type: none
\ No newline at end of file
+#spring.cache.type: none
\ No newline at end of file
Index: src/test/java/ru/javaops/bootjava/AbstractControllerTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/test/java/ru/javaops/bootjava/AbstractControllerTest.java b/src/test/java/ru/javaops/bootjava/AbstractControllerTest.java
--- a/src/test/java/ru/javaops/bootjava/AbstractControllerTest.java	(revision 97c957acb43aba3fea4fa1413ae0cc4b4a0e4395)
+++ b/src/test/java/ru/javaops/bootjava/AbstractControllerTest.java	(date 1765565240110)
@@ -3,12 +3,15 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
+import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
 import org.springframework.test.context.ActiveProfiles;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.ResultActions;
 import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
+import org.springframework.test.web.servlet.request.RequestPostProcessor;
 import org.springframework.transaction.annotation.Transactional;
 import ru.javaops.bootjava.app.config.WebConfig;
+import ru.javaops.bootjava.user.model.User;
 
 //https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-testing-spring-boot-applications
 @SpringBootTest
@@ -25,4 +28,8 @@
         builder.header(WebConfig.VERSION_HEADER, WebConfig.CURRENT_VERSION);
         return mockMvc.perform(builder);
     }
+
+    protected static RequestPostProcessor userHttpBasic(User user) {
+        return SecurityMockMvcRequestPostProcessors.httpBasic(user.getEmail(), user.getPassword());
+    }
 }
Index: src/test/java/ru/javaops/bootjava/user/web/AdminUserControllerTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/test/java/ru/javaops/bootjava/user/web/AdminUserControllerTest.java b/src/test/java/ru/javaops/bootjava/user/web/AdminUserControllerTest.java
--- a/src/test/java/ru/javaops/bootjava/user/web/AdminUserControllerTest.java	(revision 97c957acb43aba3fea4fa1413ae0cc4b4a0e4395)
+++ b/src/test/java/ru/javaops/bootjava/user/web/AdminUserControllerTest.java	(date 1765565383082)
@@ -110,6 +110,27 @@
         USER_MATCHER.assertMatch(repository.getExisted(USER_ID), getUpdated());
     }
 
+    @Test
+    void updateEmail() throws Exception {
+        perform(MockMvcRequestBuilders.get(ProfileController.REST_URL)
+                .with(userHttpBasic(user)))
+                .andExpect(status().isOk());
+
+        User updated = getUpdated();
+        updated.setEmail(NEW_MAIL);
+        perform(MockMvcRequestBuilders.put(REST_URL_SLASH + USER_ID)
+                .with(userHttpBasic(admin))
+                .contentType(MediaType.APPLICATION_JSON)
+                .content(jsonWithPassword(updated, "newPass")))
+                .andDo(print())
+                .andExpect(status().isNoContent());
+        USER_MATCHER.assertMatch(repository.getExisted(USER_ID), updated);
+
+        perform(MockMvcRequestBuilders.get(ProfileController.REST_URL)
+                .with(userHttpBasic(user)))
+                .andExpect(status().isUnauthorized());
+    }
+
     @Test
     @WithUserDetails(value = ADMIN_MAIL)
     void createWithLocation() throws Exception {
Index: src/test/java/ru/javaops/bootjava/user/UserTestData.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/test/java/ru/javaops/bootjava/user/UserTestData.java b/src/test/java/ru/javaops/bootjava/user/UserTestData.java
--- a/src/test/java/ru/javaops/bootjava/user/UserTestData.java	(revision 97c957acb43aba3fea4fa1413ae0cc4b4a0e4395)
+++ b/src/test/java/ru/javaops/bootjava/user/UserTestData.java	(date 1765550513700)
@@ -19,6 +19,7 @@
     public static final String USER_MAIL = "user@yandex.ru";
     public static final String ADMIN_MAIL = "admin@gmail.com";
     public static final String GUEST_MAIL = "guest@gmail.com";
+    public static final String NEW_MAIL = "new@gmail.com";
 
     public static final User user = new User(USER_ID, "User", USER_MAIL, "password", Role.USER);
     public static final User admin = new User(ADMIN_ID, "Admin", ADMIN_MAIL, "admin", Role.ADMIN, Role.USER);
Index: src/main/java/ru/javaops/bootjava/user/web/AdminUserController.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/ru/javaops/bootjava/user/web/AdminUserController.java b/src/main/java/ru/javaops/bootjava/user/web/AdminUserController.java
--- a/src/main/java/ru/javaops/bootjava/user/web/AdminUserController.java	(revision 97c957acb43aba3fea4fa1413ae0cc4b4a0e4395)
+++ b/src/main/java/ru/javaops/bootjava/user/web/AdminUserController.java	(date 1765564226899)
@@ -29,13 +29,11 @@
         return super.get(id);
     }
 
-    @Override
     @DeleteMapping("/{id}")
     @ResponseStatus(HttpStatus.NO_CONTENT)
     public void delete(@PathVariable int id) {
         User user = repository.getExisted(id);
-        super.delete(id);
-        userCache.removeUserFromCache(user.getEmail());
+        super.delete(id, user.getEmail());
     }
 
     @GetMapping
@@ -60,8 +58,8 @@
     public void update(@Valid @RequestBody User user, @PathVariable int id) {
         log.info("update {} with id={}", user, id);
         assureIdConsistent(user, id);
-        repository.prepareAndSave(user);
-        userCache.removeUserFromCache(user.getEmail());
+        User dbUser = repository.getExisted(id);
+        super.update(user, dbUser.getEmail());
     }
 
     @GetMapping("/by-email")
Index: src/main/java/ru/javaops/bootjava/user/web/AbstractUserController.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/ru/javaops/bootjava/user/web/AbstractUserController.java b/src/main/java/ru/javaops/bootjava/user/web/AbstractUserController.java
--- a/src/main/java/ru/javaops/bootjava/user/web/AbstractUserController.java	(revision 97c957acb43aba3fea4fa1413ae0cc4b4a0e4395)
+++ b/src/main/java/ru/javaops/bootjava/user/web/AbstractUserController.java	(date 1765563996194)
@@ -32,8 +32,14 @@
         return repository.getExisted(id);
     }
 
-    public void delete(int id) {
+    public void delete(int id, String invalidateEmail) {
         log.info("delete {}", id);
         repository.deleteExisted(id);
+        userCache.removeUserFromCache(invalidateEmail);
+    }
+
+    public void update(User user, String invalidateEmail) {
+        repository.prepareAndSave(user);
+        userCache.removeUserFromCache(invalidateEmail);
     }
 }
\ No newline at end of file
Index: src/main/java/ru/javaops/bootjava/user/web/ProfileController.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/ru/javaops/bootjava/user/web/ProfileController.java b/src/main/java/ru/javaops/bootjava/user/web/ProfileController.java
--- a/src/main/java/ru/javaops/bootjava/user/web/ProfileController.java	(revision 97c957acb43aba3fea4fa1413ae0cc4b4a0e4395)
+++ b/src/main/java/ru/javaops/bootjava/user/web/ProfileController.java	(date 1765563996179)
@@ -35,8 +35,7 @@
     @DeleteMapping
     @ResponseStatus(HttpStatus.NO_CONTENT)
     public void delete(@AuthenticationPrincipal AuthUser authUser) {
-        super.delete(authUser.id());
-        userCache.removeUserFromCache(authUser.getUsername());
+        super.delete(authUser.id(), authUser.getUsername());
     }
 
     @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
@@ -57,7 +56,6 @@
         log.info("update {} with id={}", userTo, authUser.id());
         assureIdConsistent(userTo, authUser.id());
         User user = authUser.getUser();
-        repository.prepareAndSave(UsersUtil.updateFromTo(user, userTo));
-        userCache.removeUserFromCache(authUser.getUsername());
+        super.update(UsersUtil.updateFromTo(user, userTo), authUser.getUsername());
     }
 }
\ No newline at end of file
