Skip to content

Added create, update and delete methods for UserService. I created a …#14

Merged
Martin-E-Karlsson merged 6 commits into
mainfrom
infrastructure/user-service
Apr 9, 2026
Merged

Added create, update and delete methods for UserService. I created a …#14
Martin-E-Karlsson merged 6 commits into
mainfrom
infrastructure/user-service

Conversation

@Martin-E-Karlsson

@Martin-E-Karlsson Martin-E-Karlsson commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Added create, update and delete methods for UserService.
Created a separate updateUserAuthorization which requires the requestId id to be validated as a SysAdmin

Summary by CodeRabbit

  • New Features

    • Search users by email; create, update, and delete user accounts via the admin UI
    • Manage user authorization levels from the admin interface (SYSADMIN-protected)
  • Bug Fixes

    • Reject duplicate emails on create/update to prevent duplicate accounts
    • Enforce elevated admin privileges for sensitive user operations
  • Chores

    • Improved transactional handling for user operations for greater data reliability
    • CI workflow trigger broadened to run on pushes across branches

…separate updateUserAuthorization which requires the requestId id to be validated as a SysAdmin
@coderabbitai

coderabbitai Bot commented Apr 8, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

UserService gains email lookup plus transactional user-management APIs: findByEmail, createUser, updateUser, updateUserAuthorization, and deleteUser. New flows enforce existence checks, map integrity errors to IllegalArgumentException, set authorizations/passwords, and gate sensitive ops with a validateSysAdmin helper. (50 words)

Changes

Cohort / File(s) Summary
User Management Service
src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java
Added findByEmail, createUser, updateUser, updateUserAuthorization, and deleteUser. New transactional logic maps DTO↔entity, explicitly sets passwords/authorizations, throws EntityNotFoundException when missing, converts DataIntegrityViolationException to IllegalArgumentException for duplicate emails, and adds validateSysAdmin helper to enforce SYSADMIN gating.
CI Workflow Trigger
.github/workflows/build-and-test.yml
Broadened push trigger from main to all branches ("**"). The previous pull_request branch filter was removed; workflow now triggers only on pushes across branches. No changes to build/test steps.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant UserService
    participant UserMapper
    participant UserRepository
    participant Database

    Client->>UserService: createUser(CreateUserDTO)
    UserService->>UserMapper: map DTO -> User
    UserService->>UserRepository: save(user)
    UserRepository->>Database: INSERT
    Database-->>UserRepository: success / DataIntegrityViolation
    UserRepository-->>UserService: savedUser / exception
    UserService-->>Client: UserDTO / IllegalArgumentException

    Client->>UserService: updateUser(UpdateUserDTO, currentAuth)
    UserService->>UserRepository: findById(id)
    UserRepository->>Database: SELECT
    Database-->>UserRepository: user / null
    UserRepository-->>UserService: user / not found
    UserService->>UserMapper: updateEntityFromDTO(dto, user)
    UserService->>UserRepository: save(updatedUser)
    UserRepository->>Database: UPDATE
    Database-->>UserRepository: success
    UserRepository-->>UserService: updatedUser
    UserService-->>Client: UserDTO

    Client->>UserService: updateUserAuthorization(userId, newAuth, requesterId)
    UserService->>UserRepository: findById(requesterId) (validateSysAdmin)
    UserRepository-->>UserService: requester
    UserService->>UserRepository: findById(userId)
    UserRepository-->>UserService: targetUser
    UserService->>UserRepository: save(user with newAuth)
    UserRepository->>Database: UPDATE
    Database-->>UserRepository: success
    UserRepository-->>UserService: updatedUser
    UserService-->>Client: UserDTO

    Client->>UserService: deleteUser(userId, requesterId)
    UserService->>UserRepository: findById(requesterId) (validateSysAdmin)
    UserService->>UserRepository: findById(userId)
    UserRepository-->>UserService: targetUser
    UserService->>UserRepository: delete(targetUser)
    UserRepository->>Database: DELETE
    Database-->>UserRepository: success
    UserService-->>Client: void / UnauthorizedException
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hop through code with whiskers bright,
New checks and saves in the moonlit night,
DTOs transform and authorizations set,
A sysadmin watchful — no one forget,
Hooray, the rabbit stamped it right!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes in the PR: adding create, update, and delete methods to UserService.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch infrastructure/user-service

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Martin-E-Karlsson Martin-E-Karlsson linked an issue Apr 8, 2026 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java (2)

70-70: UpdateUserDTO.userAuthorization field is silently ignored.

The UpdateUserDTO includes a userAuthorization field (per context snippet 4), but UserMapper.updateEntityFromDTO only updates fullName and email. This could confuse API consumers who expect authorization changes via this endpoint.

Consider either removing the field from UpdateUserDTO or documenting that authorization changes require updateUserAuthorization().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`
at line 70, UpdateUserDTO.userAuthorization is declared but never applied
because UserMapper.updateEntityFromDTO only copies fullName and email; either
remove userAuthorization from UpdateUserDTO or explicitly handle it: update
UserMapper.updateEntityFromDTO to map dto.getUserAuthorization() onto the User
entity (or call a helper to validate/apply roles), and if authorization changes
must go through a separate flow keep the field removed and document that
updateUserAuthorization() is the supported API; reference
UpdateUserDTO.userAuthorization, UserMapper.updateEntityFromDTO, and
updateUserAuthorization() when making the change.

94-102: Return value is unused; consider returning void.

validateSysAdmin returns User, but the caller at line 77 discards the result. Either change the return type to void or use the returned requester in the calling method.

Also, minor inconsistency: error message has a trailing period ("User not found.") while other EntityNotFoundException messages do not (lines 62, 80, 90).

♻️ Proposed simplification
-    private User validateSysAdmin(Long requesterId) {
-        User requester = userRepository.findById(requesterId)
-                .orElseThrow(() -> new EntityNotFoundException("User not found."));
+    private void validateSysAdmin(Long requesterId) {
+        User requester = userRepository.findById(requesterId)
+                .orElseThrow(() -> new EntityNotFoundException("User not found"));
 
         if (requester.getUserAuthorization() != UserAuthorization.SYSADMIN) {
             throw new UnauthorizedException("User is not authorized to perform this action.");
         }
-        return requester;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`
around lines 94 - 102, The validateSysAdmin method currently returns a User but
callers discard it; change its signature to return void and keep its internal
checks (use userRepository.findById(...).orElseThrow(new
EntityNotFoundException("User not found")) -> remove the trailing period to
match other messages) and throw UnauthorizedException when
requester.getUserAuthorization() != UserAuthorization.SYSADMIN; update any
callers that relied on the returned User to not expect a value or to fetch the
User separately if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`:
- Around line 46-56: The createUser method currently does a check-then-save
(userRepository.findByEmail(...) then userRepository.save(...)) which is
vulnerable to a race causing a DataIntegrityViolationException; modify
createUser to still attempt the save but catch
org.springframework.dao.DataIntegrityViolationException (thrown by save) and
translate it into the same domain IllegalArgumentException("A user with this
email already exists") so concurrent inserts produce a consistent, user-friendly
exception; keep the pre-check if you want fast-fail but ensure the catch around
userRepository.save(...) in createUser handles DB unique-constraint failures and
returns the mapped DTO as before.
- Line 53: The code currently sets the password in UserService via
user.setPassword(dto.password()) which stores plaintext; add a PasswordEncoder
bean (e.g., BCryptPasswordEncoder) to your Spring configuration, inject that
PasswordEncoder into UserService, and replace the direct assignment with
encoding the DTO password before setting (use
passwordEncoder.encode(dto.password()) in the place of
user.setPassword(dto.password())); ensure the bean is named/available for
injection and remove any placeholder plaintext storage comments in the User
entity.
- Around line 87-92: Add an authorization check to deleteUser by adding a
requesterId parameter and calling validateSysAdmin(requesterId) at the start of
the method (same pattern used in updateUserAuthorization). Specifically, modify
the deleteUser(Long id) signature to accept Long requesterId, invoke
validateSysAdmin(requesterId) before loading the User, and then proceed to find
and delete the user via userRepository as before; keep the
EntityNotFoundException behavior unchanged.

---

Nitpick comments:
In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`:
- Line 70: UpdateUserDTO.userAuthorization is declared but never applied because
UserMapper.updateEntityFromDTO only copies fullName and email; either remove
userAuthorization from UpdateUserDTO or explicitly handle it: update
UserMapper.updateEntityFromDTO to map dto.getUserAuthorization() onto the User
entity (or call a helper to validate/apply roles), and if authorization changes
must go through a separate flow keep the field removed and document that
updateUserAuthorization() is the supported API; reference
UpdateUserDTO.userAuthorization, UserMapper.updateEntityFromDTO, and
updateUserAuthorization() when making the change.
- Around line 94-102: The validateSysAdmin method currently returns a User but
callers discard it; change its signature to return void and keep its internal
checks (use userRepository.findById(...).orElseThrow(new
EntityNotFoundException("User not found")) -> remove the trailing period to
match other messages) and throw UnauthorizedException when
requester.getUserAuthorization() != UserAuthorization.SYSADMIN; update any
callers that relied on the returned User to not expect a value or to fetch the
User separately if needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6bfda340-ef40-4fae-bd70-266c0b78197a

📥 Commits

Reviewing files that changed from the base of the PR and between 84e7222 and 834ff51.

📒 Files selected for processing (1)
  • src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`:
- Around line 87-93: The deleteUser method references an undefined requesterId;
update the method signature for deleteUser to accept a Long requesterId
parameter, e.g., change public void deleteUser(Long id) to public void
deleteUser(Long id, Long requesterId), then propagate that parameter to any
callers; ensure the validateSysAdmin(requesterId) call and subsequent logic in
UserService.deleteUser continue to work with the added parameter and update any
unit tests or call sites that invoke deleteUser accordingly.
- Around line 1-16: The code fails to compile because UserService references
DataIntegrityViolationException but does not import it; add the missing import
for org.springframework.dao.DataIntegrityViolationException at the top of the
UserService class so references inside methods like createUser (or wherever
DataIntegrityViolationException is used) resolve correctly and the class
compiles.
- Around line 58-73: The updateUser method has the same TOCTOU race as
createUser: after checking userRepository.findByEmail(...) you must protect the
subsequent userRepository.save(user) against concurrent unique-email violations;
wrap the save call in a try-catch (as done in createUser) catching the
persistence exception (e.g., DataIntegrityViolationException or
ConstraintViolationException) and translate it into the same
IllegalArgumentException (or other handled domain error) stating "A user with
this email already exists"; keep the existing pre-check using
userRepository.findByEmail(...) but ensure the try-catch around
userMapper.updateEntityFromDTO(dto, user) + userRepository.save(user) in
updateUser to handle any race-condition uniqueness constraint failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c4dd1081-6c04-45b7-b311-35c11773ceb9

📥 Commits

Reviewing files that changed from the base of the PR and between 834ff51 and ab8c88c.

📒 Files selected for processing (1)
  • src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java (1)

66-74: ⚠️ Potential issue | 🟠 Major

Still missing the duplicate-email catch around save().

The pre-check at Lines 66-70 can still lose a race to another transaction, and Line 73 will then leak a raw DataIntegrityViolationException instead of the same user-friendly error used in createUser().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`
around lines 66 - 74, The pre-check using userRepository.findByEmail(...) still
has a race; wrap the call to userRepository.save(user) in updateUser (the block
that calls userMapper.updateEntityFromDTO(dto, user) then
userRepository.save(user)) with a try/catch that catches
DataIntegrityViolationException (or the specific persistence exception your
stack throws) and rethrow an IllegalArgumentException with the same friendly
message used in createUser (e.g., "A user with this email already exists") so
duplicate-email races produce a consistent user-facing error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`:
- Around line 61-74: The updateUser flow currently ignores
UpdateUserDTO.userAuthorization(); in UserService.updateUser after loading the
User, validate that dto.userAuthorization() is null/absent and reject requests
that attempt to change authorization (throw e.g. IllegalArgumentException) OR
remove the field from UpdateUserDTO if contract change is acceptable;
alternatively ensure role changes go only through the existing
updateUserAuthorization(...) method by adding an explicit check before calling
userMapper.updateEntityFromDTO(dto, user) that prevents persisting
dto.userAuthorization() (reject or strip it) and document the behavior.
- Around line 49-53: The createUser(CreateUserDTO dto) method currently trusts
dto.userAuthorization() and allows callers to create SYSADMIN accounts; change
it so createUser no longer assigns elevated roles from the DTO: either set a
safe default role (e.g., Role.USER) inside createUser (call
user.setAuthorization(...) instead of using dto.userAuthorization()), or require
an explicit validated admin requester parameter and gate assignment of elevated
roles to that path; keep elevated-role changes restricted to the existing
updateUserAuthorization(...) flow. Ensure the unique symbols to edit are
createUser(CreateUserDTO), CreateUserDTO.userAuthorization(), and
updateUserAuthorization(...) so the role is not accepted directly from the
incoming DTO.

---

Duplicate comments:
In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`:
- Around line 66-74: The pre-check using userRepository.findByEmail(...) still
has a race; wrap the call to userRepository.save(user) in updateUser (the block
that calls userMapper.updateEntityFromDTO(dto, user) then
userRepository.save(user)) with a try/catch that catches
DataIntegrityViolationException (or the specific persistence exception your
stack throws) and rethrow an IllegalArgumentException with the same friendly
message used in createUser (e.g., "A user with this email already exists") so
duplicate-email races produce a consistent user-facing error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8e5febc4-8da2-42e6-a163-b225c5f6c935

📥 Commits

Reviewing files that changed from the base of the PR and between ab8c88c and 77f4592.

📒 Files selected for processing (1)
  • src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java

Comment thread src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java Outdated
@ithsjava25 ithsjava25 deleted a comment from coderabbitai Bot Apr 9, 2026
@ithsjava25 ithsjava25 deleted a comment from coderabbitai Bot Apr 9, 2026
@eeebbaandersson eeebbaandersson linked an issue Apr 9, 2026 that may be closed by this pull request
…out old email check logic in createUser. The current userAuthorization is now a parameter in updateUser.

Fix: Changed CI pipeline so pushes in all branches run tests.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java (1)

49-55: ⚠️ Potential issue | 🔴 Critical

Set the default role before save(...).

Line 54 is too late. With User.id using GenerationType.IDENTITY, the insert can happen at Line 53 to fetch the generated key, so the first write still uses whatever userMapper.toEntity(dto) put in userAuthorization — or null, which violates the entity's @NotNull. Default USER on the transient entity before persisting it.

Proposed fix
 `@Transactional`
 public UserDTO createUser(CreateUserDTO dto) {
     User user = userMapper.toEntity(dto);
     user.setPassword(dto.password()); // mapper doesn't set this currently
+    user.setUserAuthorization(UserAuthorization.USER);
     try {
         User savedUser = userRepository.save(user);
-        savedUser.setUserAuthorization(UserAuthorization.USER);
         return userMapper.toDTO(savedUser);
     } catch (DataIntegrityViolationException e) {
         throw new IllegalArgumentException("A user with this email already exists", e);
     }
 }
In Spring Data JPA / Hibernate, when an entity uses `@GeneratedValue(strategy = GenerationType.IDENTITY)`, can `save()` / `persist()` execute the INSERT before transaction commit to obtain the generated id, so field changes made after `save()` happen after the initial INSERT?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`
around lines 49 - 55, The user default role is being set after persisting,
risking a null or wrong userAuthorization in the INSERT; in createUser
(UserService.createUser) set the default role on the transient User object
returned by userMapper.toEntity(dto) before calling userRepository.save(user) —
e.g., call user.setUserAuthorization(UserAuthorization.USER) immediately after
userMapper.toEntity(dto) and before save so the persisted row always has the
USER role and avoids `@NotNull` violations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`:
- Around line 62-77: The updateUser method currently overwrites the persisted
role using the caller-provided currentAuth
(savedUser.setUserAuthorization(currentAuth)), which allows callers to escalate
roles; instead, keep the existing role from the loaded User entity (the user
returned by userRepository.findById) when saving (do not use currentAuth or
accept role changes in updateUser), so remove or replace the
savedUser.setUserAuthorization(currentAuth) call to preserve
user.getUserAuthorization(); reserve all role changes for
updateUserAuthorization(...) which enforces validateSysAdmin(...).
- Around line 73-79: The try/catch around userMapper.updateEntityFromDTO(dto,
user) and userRepository.save(user) may miss unique-email violations because JPA
defers SQL until flush/commit; replace the call to userRepository.save(user)
with userRepository.saveAndFlush(user) (or explicitly call flush on the
EntityManager) inside the try so the DataIntegrityViolationException is raised
there and can be caught and rethrown as the IllegalArgumentException; keep the
same catch for DataIntegrityViolationException and wrapping behavior.

---

Duplicate comments:
In
`@src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java`:
- Around line 49-55: The user default role is being set after persisting,
risking a null or wrong userAuthorization in the INSERT; in createUser
(UserService.createUser) set the default role on the transient User object
returned by userMapper.toEntity(dto) before calling userRepository.save(user) —
e.g., call user.setUserAuthorization(UserAuthorization.USER) immediately after
userMapper.toEntity(dto) and before save so the persisted row always has the
USER role and avoids `@NotNull` violations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fb7d8f6f-797f-49d4-8672-eb84694ecb26

📥 Commits

Reviewing files that changed from the base of the PR and between 77f4592 and e1100bf.

📒 Files selected for processing (2)
  • .github/workflows/build-and-test.yml
  • src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java
✅ Files skipped from review due to trivial changes (1)
  • .github/workflows/build-and-test.yml

Comment thread src/main/java/org/example/visacasemanagementsystem/user/service/UserService.java Outdated
… by updateUserAuthorization method only. Implemented CodeRabbit about duplicate email interception.
@Martin-E-Karlsson
Martin-E-Karlsson merged commit 6104784 into main Apr 9, 2026
2 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update CI-pipeline to trigger on all branch pushes Implement create and update user methods

1 participant