From 6891850e659dd24b91113649d8b7ebfae4d0a4fd Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:53:22 +0200 Subject: [PATCH 1/8] Change password option Changes options for updating users in service, mapper and DTO. Also adds a log event when creating a user using OAUTH and updates the redirect --- .../config/OauthSuccessHandler.java | 20 ++++++++++++++++--- .../user/dto/UpdateUserDTO.java | 2 +- .../user/mapper/UserMapper.java | 3 +-- .../user/service/UserService.java | 2 +- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/example/visacasemanagementsystem/config/OauthSuccessHandler.java b/src/main/java/org/example/visacasemanagementsystem/config/OauthSuccessHandler.java index 0dd0a6d..3968357 100644 --- a/src/main/java/org/example/visacasemanagementsystem/config/OauthSuccessHandler.java +++ b/src/main/java/org/example/visacasemanagementsystem/config/OauthSuccessHandler.java @@ -3,6 +3,8 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.example.visacasemanagementsystem.audit.UserEventType; +import org.example.visacasemanagementsystem.audit.service.UserLogService; import org.example.visacasemanagementsystem.user.UserAuthorization; import org.example.visacasemanagementsystem.user.entity.User; import org.example.visacasemanagementsystem.user.repository.UserRepository; @@ -18,6 +20,8 @@ import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.security.web.context.SecurityContextRepository; +import org.springframework.transaction.annotation.Transactional; + import java.io.IOException; import java.util.Objects; import java.util.UUID; @@ -28,14 +32,17 @@ public class OauthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; private final SecurityContextRepository securityContextRepository; + private final UserLogService userLogService; - public OauthSuccessHandler(UserRepository userRepository, PasswordEncoder passwordEncoder, SecurityContextRepository securityContextRepository) { + public OauthSuccessHandler(UserRepository userRepository, PasswordEncoder passwordEncoder, SecurityContextRepository securityContextRepository, UserLogService userLogService) { this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; this.securityContextRepository = securityContextRepository; + this.userLogService = userLogService; } @Override + @Transactional public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) @@ -57,7 +64,14 @@ public void onAuthenticationSuccess(HttpServletRequest request, newUser.setPassword(passwordEncoder.encode(UUID.randomUUID().toString())); newUser.setUserAuthorization(UserAuthorization.USER); try { - return userRepository.saveAndFlush(newUser); + User savedUser = userRepository.saveAndFlush(newUser); + userLogService.createUserLog( + savedUser.getId(), + savedUser.getId(), + UserEventType.CREATED, + "User account created via OAUTH2." + ); + return savedUser; } catch (DataIntegrityViolationException e) { return userRepository.findByEmail(email).orElseThrow(); } @@ -72,7 +86,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, clearAuthenticationAttributes(request); - String targetUrl = "/dashboard"; + String targetUrl = "/home"; getRedirectStrategy().sendRedirect(request, response, targetUrl); } } diff --git a/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java b/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java index 11cb128..ad1f5ba 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java @@ -6,5 +6,5 @@ public record UpdateUserDTO( @NotNull Long id, @NotBlank(message = "Full name must be specified") String fullName, - @NotBlank(message = "Email must be specified") String email) { + @NotBlank(message = "Password must be set") String password) { } diff --git a/src/main/java/org/example/visacasemanagementsystem/user/mapper/UserMapper.java b/src/main/java/org/example/visacasemanagementsystem/user/mapper/UserMapper.java index 881cd9c..9ec65b6 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/mapper/UserMapper.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/mapper/UserMapper.java @@ -38,7 +38,6 @@ public void updateEntityFromDTO(UpdateUserDTO dto, User user) { if (dto == null || user == null) return; user.setFullName(dto.fullName()); - user.setEmail(dto.email()); - user.setUsername(dto.email()); + user.setPassword(dto.password()); } } diff --git a/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java b/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java index 08f53e8..791278b 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java @@ -104,7 +104,7 @@ public UserDTO updateUser(UpdateUserDTO dto, Long actorUserId) { actorUserId, savedUser.getId(), UserEventType.UPDATED, - "User profile updated (fullName/email)." + "User profile updated (fullName/password)." ); return userMapper.toDTO(savedUser); } From 0cc9a783239a1f689f5c8885ae5fae1c7211665e Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:08:42 +0200 Subject: [PATCH 2/8] Small fixes --- .../visacasemanagementsystem/user/dto/UpdateUserDTO.java | 2 +- .../visacasemanagementsystem/user/mapper/UserMapper.java | 1 - .../visacasemanagementsystem/user/service/UserService.java | 4 ++++ .../user/mapper/UserMapperTest.java | 6 ++---- .../user/service/UserServiceIntegrationTest.java | 6 ++---- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java b/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java index ad1f5ba..b10d439 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java @@ -6,5 +6,5 @@ public record UpdateUserDTO( @NotNull Long id, @NotBlank(message = "Full name must be specified") String fullName, - @NotBlank(message = "Password must be set") String password) { + String password) { } diff --git a/src/main/java/org/example/visacasemanagementsystem/user/mapper/UserMapper.java b/src/main/java/org/example/visacasemanagementsystem/user/mapper/UserMapper.java index 9ec65b6..5d10770 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/mapper/UserMapper.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/mapper/UserMapper.java @@ -38,6 +38,5 @@ public void updateEntityFromDTO(UpdateUserDTO dto, User user) { if (dto == null || user == null) return; user.setFullName(dto.fullName()); - user.setPassword(dto.password()); } } diff --git a/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java b/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java index 791278b..5889369 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java @@ -93,6 +93,10 @@ public UserDTO updateUser(UpdateUserDTO dto, Long actorUserId) { User user = userRepository.findById(dto.id()) .orElseThrow(() -> new EntityNotFoundException(USER_NOT_FOUND)); + if (!dto.password().isBlank()) { + passwordEncoder.encode(dto.password()); + } + User savedUser; try { userMapper.updateEntityFromDTO(dto, user); diff --git a/src/test/java/org/example/visacasemanagementsystem/user/mapper/UserMapperTest.java b/src/test/java/org/example/visacasemanagementsystem/user/mapper/UserMapperTest.java index a7494c6..88d4188 100644 --- a/src/test/java/org/example/visacasemanagementsystem/user/mapper/UserMapperTest.java +++ b/src/test/java/org/example/visacasemanagementsystem/user/mapper/UserMapperTest.java @@ -99,7 +99,7 @@ void shouldReturnNullEntity_WhenCreateUserDTOIsNull() { } @Test - @DisplayName("Checking if updateEntityFromDTO overwrites fullName, email, and username on an existing User entity") + @DisplayName("Checking if updateEntityFromDTO overwrites fullName on an existing User entity") void shouldUpdateExistingUserEntityFromUpdateUserDTO() { // Arrange User user = new User(); @@ -109,15 +109,13 @@ void shouldUpdateExistingUserEntityFromUpdateUserDTO() { user.setPassword("password123"); user.setUserAuthorization(UserAuthorization.USER); - UpdateUserDTO dto = new UpdateUserDTO(1L, "New Name", "new@example.com"); + UpdateUserDTO dto = new UpdateUserDTO(1L, "New Name", ""); // Act userMapper.updateEntityFromDTO(dto, user); // Assert assertThat(user.getFullName()).isEqualTo("New Name"); - assertThat(user.getEmail()).isEqualTo("new@example.com"); - assertThat(user.getUsername()).isEqualTo("new@example.com"); } @Test diff --git a/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceIntegrationTest.java b/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceIntegrationTest.java index acf779b..54ef8e4 100644 --- a/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceIntegrationTest.java +++ b/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceIntegrationTest.java @@ -70,23 +70,21 @@ void createUser_shouldSaveUser_WhenDataIsValid() { } @Test - @DisplayName("Checking if updateUser changes fullName and email in the database") + @DisplayName("Checking if updateUser changes fullName in the database") void updateUser_shouldUpdateUserFields_WhenDataIsValid() { // Arrange User user = createAndSaveValidUser(); authenticateUser(user); - UpdateUserDTO dto = new UpdateUserDTO(user.getId(), "Updated Name", "updated@integration.test"); + UpdateUserDTO dto = new UpdateUserDTO(user.getId(), "Updated Name", ""); // Act — actor is the user themselves editing their own profile UserDTO result = userService.updateUser(dto, user.getId()); // Assert assertThat(result.fullName()).isEqualTo("Updated Name"); - assertThat(result.email()).isEqualTo("updated@integration.test"); User updatedUser = userRepository.findById(user.getId()).orElseThrow(); assertThat(updatedUser.getFullName()).isEqualTo("Updated Name"); - assertThat(updatedUser.getEmail()).isEqualTo("updated@integration.test"); } @Test From d42c9c2d5ea31d0dda788f1651025bb564f345f2 Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:39:20 +0200 Subject: [PATCH 3/8] Bugfixes following CodeRabbit feedback --- .../user/controller/UserViewController.java | 6 +++--- .../visacasemanagementsystem/user/dto/UpdateUserDTO.java | 4 ++++ .../user/service/UserService.java | 2 +- .../user/service/UserServiceIntegrationTest.java | 8 ++++++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/example/visacasemanagementsystem/user/controller/UserViewController.java b/src/main/java/org/example/visacasemanagementsystem/user/controller/UserViewController.java index 8afd999..5acd751 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/controller/UserViewController.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/controller/UserViewController.java @@ -144,12 +144,12 @@ public String showProfileEditForm(@AuthenticationPrincipal UserPrincipal princip public String updateProfile(@AuthenticationPrincipal UserPrincipal principal, @PathVariable Long userId, @RequestParam String fullName, - @RequestParam String email, + @RequestParam String password, Model model) { userService.validateProfileAccess(principal, userId); try { - UpdateUserDTO dto = new UpdateUserDTO(userId, fullName, email); + UpdateUserDTO dto = new UpdateUserDTO(userId, fullName, password); userService.updateUser(dto, principal.getUserId()); return "redirect:/profile/view/" + userId; } catch (IllegalArgumentException e) { @@ -158,7 +158,7 @@ public String updateProfile(@AuthenticationPrincipal UserPrincipal principal, UserDTO existing = userService.findById(userId) .orElseThrow(() -> new EntityNotFoundException("User not found")); model.addAttribute("error", e.getMessage()); - model.addAttribute("user", new UserDTO(userId, fullName, email, existing.userAuthorization())); + model.addAttribute("user", new UserDTO(userId, fullName, password, existing.userAuthorization())); addAuthorizationFormAttributes(model, principal, userId); return "profile/edit"; } diff --git a/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java b/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java index b10d439..0e3ce3f 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java @@ -2,9 +2,13 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; public record UpdateUserDTO( @NotNull Long id, @NotBlank(message = "Full name must be specified") String fullName, + + @NotNull(message = "Password must be provided (use empty string to skip change)") + @Pattern(regexp = "^$|.{8,}", message = "Password must be at least 8 characters") String password) { } diff --git a/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java b/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java index 5889369..228e1d4 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java @@ -94,7 +94,7 @@ public UserDTO updateUser(UpdateUserDTO dto, Long actorUserId) { .orElseThrow(() -> new EntityNotFoundException(USER_NOT_FOUND)); if (!dto.password().isBlank()) { - passwordEncoder.encode(dto.password()); + user.setPassword(passwordEncoder.encode(dto.password())); } User savedUser; diff --git a/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceIntegrationTest.java b/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceIntegrationTest.java index 54ef8e4..0a9354e 100644 --- a/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceIntegrationTest.java +++ b/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceIntegrationTest.java @@ -17,6 +17,7 @@ import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.bean.override.mockito.MockitoBean; @@ -39,6 +40,8 @@ class UserServiceIntegrationTest { @MockitoBean private FileService fileService; + @Autowired + private PasswordEncoder passwordEncoder; @AfterEach void tearDown() { @@ -70,12 +73,12 @@ void createUser_shouldSaveUser_WhenDataIsValid() { } @Test - @DisplayName("Checking if updateUser changes fullName in the database") + @DisplayName("Checking if updateUser changes fullName and password in the database") void updateUser_shouldUpdateUserFields_WhenDataIsValid() { // Arrange User user = createAndSaveValidUser(); authenticateUser(user); - UpdateUserDTO dto = new UpdateUserDTO(user.getId(), "Updated Name", ""); + UpdateUserDTO dto = new UpdateUserDTO(user.getId(), "Updated Name", "newPassword"); // Act — actor is the user themselves editing their own profile UserDTO result = userService.updateUser(dto, user.getId()); @@ -85,6 +88,7 @@ void updateUser_shouldUpdateUserFields_WhenDataIsValid() { User updatedUser = userRepository.findById(user.getId()).orElseThrow(); assertThat(updatedUser.getFullName()).isEqualTo("Updated Name"); + assertThat(passwordEncoder.matches("newPassword", updatedUser.getPassword())).isTrue(); } @Test From 8e5312feb4bb70c231f6b307c913ba42b58072e9 Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Mon, 27 Apr 2026 16:05:32 +0200 Subject: [PATCH 4/8] Bugfixes following CodeRabbit feedback --- .../user/service/UserService.java | 6 ++++ .../controller/UserViewControllerTest.java | 8 ++--- .../user/service/UserServiceTest.java | 31 ++++++++++++++++++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java b/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java index 228e1d4..e75f712 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java @@ -15,6 +15,7 @@ import org.example.visacasemanagementsystem.user.security.UserPrincipal; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -89,6 +90,7 @@ public UserDTO createUser(@Valid CreateUserDTO dto) { @Transactional public UserDTO updateUser(UpdateUserDTO dto, Long actorUserId) { + validateProfileAccess(getUserPrincipal(), dto.id()); // Check if user and email exists User user = userRepository.findById(dto.id()) .orElseThrow(() -> new EntityNotFoundException(USER_NOT_FOUND)); @@ -158,4 +160,8 @@ public void validateProfileAccess(UserPrincipal principal, Long userId) { throw new UnauthorizedException("You do not have permission to edit this profile."); } } + + private static UserPrincipal getUserPrincipal() { + return (UserPrincipal) Objects.requireNonNull(Objects.requireNonNull(SecurityContextHolder.getContext().getAuthentication()).getPrincipal()); + } } diff --git a/src/test/java/org/example/visacasemanagementsystem/user/controller/UserViewControllerTest.java b/src/test/java/org/example/visacasemanagementsystem/user/controller/UserViewControllerTest.java index 0b86301..3d9f514 100644 --- a/src/test/java/org/example/visacasemanagementsystem/user/controller/UserViewControllerTest.java +++ b/src/test/java/org/example/visacasemanagementsystem/user/controller/UserViewControllerTest.java @@ -259,7 +259,7 @@ void updateProfile_WithValidData_ShouldRedirectToProfileView() throws Exception // Act & Assert mockMvc.perform(post("/profile/edit/" + userId) .param("fullName", "Updated Name") - .param("email", "updated@test.com") + .param("password", "newPassword") .with(authentication(authFor(userId, "Test User", "user@test.com", UserAuthorization.USER))) .with(csrf())) .andExpect(status().is3xxRedirection()) @@ -281,7 +281,7 @@ void updateProfile_WithDuplicateEmail_ShouldReturnEditViewWithError() throws Exc // Act & Assert mockMvc.perform(post("/profile/edit/" + userId) .param("fullName", "Test User") - .param("email", "taken@test.com") + .param("password", "newPassword") .with(authentication(authFor(userId, "Test User", "user@test.com", UserAuthorization.USER))) .with(csrf())) .andExpect(status().isOk()) @@ -302,7 +302,7 @@ void updateProfile_WhenUserConcurrentlyDeleted_ShouldReturnNotFound() throws Exc // Act & Assert — handled by GlobalExceptionHandler → 404 mockMvc.perform(post("/profile/edit/" + userId) .param("fullName", "Test User") - .param("email", "taken@test.com") + .param("password", "newPassword") .with(authentication(authFor(userId, "Test User", "user@test.com", UserAuthorization.USER))) .with(csrf())) .andExpect(status().isNotFound()); @@ -320,7 +320,7 @@ void updateProfile_AsUnauthorizedUser_ShouldReturnForbidden() throws Exception { // Act & Assert mockMvc.perform(post("/profile/edit/" + targetUserId) .param("fullName", "Hacked") - .param("email", "hacked@test.com") + .param("password", "newPassword") .with(authentication(authFor(1L, "Test User", "user@test.com", UserAuthorization.USER))) .with(csrf())) .andExpect(status().isForbidden()); diff --git a/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceTest.java b/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceTest.java index 1dc35e8..005dc07 100644 --- a/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceTest.java +++ b/src/test/java/org/example/visacasemanagementsystem/user/service/UserServiceTest.java @@ -19,6 +19,9 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; import java.util.Optional; @@ -121,6 +124,10 @@ void createUser_shouldSaveAndReturnUserDTO_WhenDataIsValid() { @DisplayName("Checking if updateUser throws EntityNotFoundException when user ID does not exist") void updateUser_shouldThrowEntityNotFoundException_WhenUserDoesNotExist() { // Arrange + User sysadmin = createAndSaveUser("sysadmin", UserAuthorization.SYSADMIN); + sysadmin.setId(1L); + authenticateUser(sysadmin); + UpdateUserDTO dto = new UpdateUserDTO(999L, "Name", "email@test.com"); when(userRepository.findById(999L)).thenReturn(Optional.empty()); @@ -157,8 +164,9 @@ void updateUser_shouldUpdateAndReturnUser_WhenDataIsValid() { Long userId = 1L; UpdateUserDTO dto = new UpdateUserDTO(userId, "Updated Name", "updated@test.com"); - User existingUser = new User(); + User existingUser = createAndSaveUser("user", UserAuthorization.USER); existingUser.setId(userId); + authenticateUser(existingUser); UserDTO expectedDTO = new UserDTO(userId, "Updated Name", "updated@test.com", UserAuthorization.USER); when(userRepository.findById(userId)).thenReturn(Optional.of(existingUser)); @@ -309,5 +317,26 @@ void findByEmail_shouldReturnEmpty_WhenEmailDoesNotExist() { // Act & Assert assertThat(userService.findByEmail("nobody@test.com")).isEmpty(); } + + // ── Helper methods ──────────────────────────────────────────────────────── + + private User createAndSaveUser(String name, UserAuthorization auth) { + User user = new User(); + String uniqueEmail = java.util.UUID.randomUUID() + "@test.com"; + user.setFullName(name); + user.setEmail(uniqueEmail); + user.setUsername(uniqueEmail); + user.setPassword("password123"); + user.setUserAuthorization(auth); + userRepository.save(user); + return user; + } + + private UserPrincipal authenticateUser(User user) { + UserPrincipal principal = new UserPrincipal(user); + Authentication authentication = new TestingAuthenticationToken(principal, "password123", principal.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authentication); + return principal; + } } \ No newline at end of file From 90babe3c963fd1de1abb7b84fd7330f6405a7e3f Mon Sep 17 00:00:00 2001 From: Edvin Sandgren <229709012+EdvinSandgren@users.noreply.github.com> Date: Mon, 27 Apr 2026 16:10:04 +0200 Subject: [PATCH 5/8] Spotless fix --- .../visacasemanagementsystem/user/dto/UpdateUserDTO.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java b/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java index 0e3ce3f..390fbc5 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/dto/UpdateUserDTO.java @@ -7,8 +7,6 @@ public record UpdateUserDTO( @NotNull Long id, @NotBlank(message = "Full name must be specified") String fullName, - @NotNull(message = "Password must be provided (use empty string to skip change)") - @Pattern(regexp = "^$|.{8,}", message = "Password must be at least 8 characters") - String password) { + @Pattern(regexp = "^$|.{8,}", message = "Password must be at least 8 characters") String password) { } From 58bec87fe4f210e22a811785defd08f1f24e0ae0 Mon Sep 17 00:00:00 2001 From: Martin Karlsson Date: Mon, 27 Apr 2026 21:00:21 +0200 Subject: [PATCH 6/8] Feature: - Added password changing logic to UserViewController - Added password duplication requirement to profile/edit and user/signup --- .../user/controller/UserViewController.java | 10 ++++++- .../resources/templates/profile/edit.html | 27 +++++++++++++++---- src/main/resources/templates/user/signup.html | 26 ++++++++++++++++-- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/example/visacasemanagementsystem/user/controller/UserViewController.java b/src/main/java/org/example/visacasemanagementsystem/user/controller/UserViewController.java index 5acd751..3a71cee 100644 --- a/src/main/java/org/example/visacasemanagementsystem/user/controller/UserViewController.java +++ b/src/main/java/org/example/visacasemanagementsystem/user/controller/UserViewController.java @@ -59,8 +59,12 @@ public String userSignupForm(@AuthenticationPrincipal UserPrincipal principal, M public String createUser(@RequestParam String fullName, @RequestParam String email, @RequestParam String password, + @RequestParam String confirmPassword, Model model) { try { + if (!password.equals(confirmPassword)) { + throw new IllegalArgumentException("Passwords do not match"); + } CreateUserDTO dto = new CreateUserDTO(fullName, email, password, UserAuthorization.USER); userService.createUser(dto); return "redirect:/user/login"; @@ -145,10 +149,14 @@ public String updateProfile(@AuthenticationPrincipal UserPrincipal principal, @PathVariable Long userId, @RequestParam String fullName, @RequestParam String password, + @RequestParam String confirmPassword, Model model) { userService.validateProfileAccess(principal, userId); try { + if (!password.equals(confirmPassword)) { + throw new IllegalArgumentException("Passwords do not match"); + } UpdateUserDTO dto = new UpdateUserDTO(userId, fullName, password); userService.updateUser(dto, principal.getUserId()); return "redirect:/profile/view/" + userId; @@ -158,7 +166,7 @@ public String updateProfile(@AuthenticationPrincipal UserPrincipal principal, UserDTO existing = userService.findById(userId) .orElseThrow(() -> new EntityNotFoundException("User not found")); model.addAttribute("error", e.getMessage()); - model.addAttribute("user", new UserDTO(userId, fullName, password, existing.userAuthorization())); + model.addAttribute("user", new UserDTO(userId, fullName, existing.email(), existing.userAuthorization())); addAuthorizationFormAttributes(model, principal, userId); return "profile/edit"; } diff --git a/src/main/resources/templates/profile/edit.html b/src/main/resources/templates/profile/edit.html index b41393d..ce9334e 100644 --- a/src/main/resources/templates/profile/edit.html +++ b/src/main/resources/templates/profile/edit.html @@ -47,11 +47,15 @@

Edit Profile

required>
- - + + +
+
+ +