From 605c04600e25f27964d1a952ea612bcdd21346d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 8 Sep 2026 19:12:21 +0000 Subject: [PATCH 1/2] Initial plan From 067d0ab5a5a3406acd6712ffc7d0aa1c78acf349 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 8 Sep 2026 19:19:09 +0000 Subject: [PATCH 2/2] Restore audit logs for user profile and password updates Co-authored-by: jamilhelal37 <239214190+jamilhelal37@users.noreply.github.com> --- .../account/service/PasswordResetService.java | 14 +++++++++++ .../UserProfileTransactionService.java | 24 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/main/java/com/jamil/ahadith/features/account/service/PasswordResetService.java b/src/main/java/com/jamil/ahadith/features/account/service/PasswordResetService.java index db943ef..5669c72 100644 --- a/src/main/java/com/jamil/ahadith/features/account/service/PasswordResetService.java +++ b/src/main/java/com/jamil/ahadith/features/account/service/PasswordResetService.java @@ -7,6 +7,8 @@ import com.jamil.ahadith.core.security.RefreshTokenRevoker; import com.jamil.ahadith.core.validation.EmailNormalizer; import com.jamil.ahadith.core.web.dto.MessageResponseDto; +import com.jamil.ahadith.features.audit.service.AuditData; +import com.jamil.ahadith.features.audit.service.AuditEventPublisher; import com.jamil.ahadith.features.account.dto.request.ResetPasswordRequestDto; import com.jamil.ahadith.features.account.entity.PasswordResetToken; import com.jamil.ahadith.features.account.event.AccountEmailEvent; @@ -31,6 +33,7 @@ public class PasswordResetService { private static final String INVALID_PASSWORD_RESET_TOKEN_MESSAGE = "Invalid or expired password reset token"; private static final String FORGOT_PASSWORD_MESSAGE = "If the email is registered, password reset instructions have been sent"; + private static final String USERS_TABLE_NAME = "users"; private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; @@ -43,6 +46,7 @@ public class PasswordResetService { private final RateLimitKeyResolver rateLimitKeyResolver; private final OneTimeTokenValidator oneTimeTokenValidator; private final ApplicationEventPublisher eventPublisher; + private final AuditEventPublisher auditEventPublisher; @Transactional public MessageResponseDto forgotPassword(String email) { @@ -86,6 +90,7 @@ public MessageResponseDto resetPassword(ResetPasswordRequestDto request) { User user = resetToken.getUser(); requireActive(user); + var oldData = AuditData.snapshot(user); String encodedPassword = passwordEncoder.encode(request.getNewPassword()); @@ -99,6 +104,15 @@ public MessageResponseDto resetPassword(ResetPasswordRequestDto request) { passwordResetTokenRepository.consumeActiveForUser(user, now); + auditEventPublisher.publishUpdateAs( + user, + USERS_TABLE_NAME, + user.getId(), + oldData, + AuditData.snapshot(user), + "password reset" + ); + return new MessageResponseDto( "Password has been reset" ); diff --git a/src/main/java/com/jamil/ahadith/features/user/service/UserProfileTransactionService.java b/src/main/java/com/jamil/ahadith/features/user/service/UserProfileTransactionService.java index 1336fb1..7b4bfc7 100644 --- a/src/main/java/com/jamil/ahadith/features/user/service/UserProfileTransactionService.java +++ b/src/main/java/com/jamil/ahadith/features/user/service/UserProfileTransactionService.java @@ -4,6 +4,8 @@ import com.jamil.ahadith.core.security.RefreshTokenRevoker; import com.jamil.ahadith.core.storage.dto.ProfileImageResponse; import com.jamil.ahadith.core.web.dto.MessageResponseDto; +import com.jamil.ahadith.features.audit.service.AuditData; +import com.jamil.ahadith.features.audit.service.AuditEventPublisher; import com.jamil.ahadith.features.account.service.PasswordPolicyService; import com.jamil.ahadith.features.auth.dto.response.AuthUserDto; import com.jamil.ahadith.features.auth.mapper.AuthUserMapper; @@ -24,6 +26,7 @@ @Service @RequiredArgsConstructor public class UserProfileTransactionService { + private static final String USERS_TABLE_NAME = "users"; private final UserRepository userRepository; private final ApplicationEventPublisher eventPublisher; @@ -31,6 +34,7 @@ public class UserProfileTransactionService { private final PasswordEncoder passwordEncoder; private final PasswordPolicyService passwordPolicyService; private final RefreshTokenRevoker refreshTokenRevoker; + private final AuditEventPublisher auditEventPublisher; @Transactional public void replaceProfileImage( @@ -86,11 +90,21 @@ public AuthUserDto updateProfile( User user = userRepository .findByIdForUpdate(userId) .orElseThrow(UserNotFoundException::new); + var oldData = AuditData.snapshot(user); user.setName(request.getName().trim()); user.setGender(request.getGender()); user.setBirthDate(request.getBirthDate()); + auditEventPublisher.publishUpdateAs( + user, + USERS_TABLE_NAME, + user.getId(), + oldData, + AuditData.snapshot(user), + "profile updated" + ); + return authUserMapper.toDto(user); } @@ -106,6 +120,7 @@ public MessageResponseDto changePassword( User user = userRepository .findByIdForUpdate(userId) .orElseThrow(UserNotFoundException::new); + var oldData = AuditData.snapshot(user); if (user.getPassword() == null || !passwordEncoder.matches( @@ -140,6 +155,15 @@ public MessageResponseDto changePassword( refreshTokenRevoker.revokeAllForUser(user); + auditEventPublisher.publishUpdateAs( + user, + USERS_TABLE_NAME, + user.getId(), + oldData, + AuditData.snapshot(user), + "password changed" + ); + return new MessageResponseDto( "Password changed successfully" );