Skip to content

Conversation

@SamuelPalaj
Copy link
Contributor

@SamuelPalaj SamuelPalaj commented Sep 19, 2025

Description

  • added UserType enum
  • added type parameter to AbstractUser
  • added list of domains to Realm
  • UserService type refactor, now works with User instead of AbstractUser
  • slight refactor related to above mentioned change
  • added UpdateUserRequest to nae-user-common
  • added anonymous user type enum value to UserType

Implements NAE-2169

How Has Been This Tested?

manualy

Test Configuration

Name Tested on
OS windows 10
Runtime java 21
Dependency Manager Maven 3.9.9
Framework version Spring Boot 3.4.4
Run parameters
Other configuration

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes have been checked, personally or remotely, with @...
  • I have commented my code, particularly in hard-to-understand areas
  • I have resolved all conflicts with the target branch of the PR
  • I have updated and synced my code with the target branch
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes:
    • Lint test
    • Unit tests
    • Integration tests
  • I have checked my contribution with code analysis tools:
  • I have made corresponding changes to the documentation:
    • Developer documentation
    • User Guides
    • Migration Guides

Summary by CodeRabbit

  • New Features

    • User responses now include a “user type” (Internal, External, System, Anonymous).
    • Realms support configurable domain lists.
    • Added partial user update support via an update request payload.
    • Impersonation user listing returns enhanced paged resources with links.
  • Bug Fixes

    • More robust password reset/recovery with clearer handling of inactive or non-existent users.
  • Refactor

    • Unified user handling across services and controllers for greater consistency and reliability.

- added UserType enum
- added type parameter to AbstractUser
- added list of domains to Realm
- UserService type refactor, now works with User instead of AbstractUser
- slight refactor related to above mentioned change
- added UpdateUserRequest to nae-user-common
- added anonymous user type enum value to UserType
# Conflicts:
#	application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java
#	nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java
- removed duplicate class UpdateUserRequest.java
- moved user type resolution from createUser method to saveUser method in UserServiceImpl.java
@coderabbitai
Copy link

coderabbitai bot commented Sep 19, 2025

Walkthrough

Migrates public APIs and internal usages from AbstractUser to concrete User across services, controllers, and adapters. Introduces UserType enum and propagates it through domain, logged user, DTOs, and constructors. Adds UpdateUserRequest-based update methods, realm domains handling, and adjusts related authorization/impersonation and role/group services accordingly.

Changes

Cohort / File(s) Summary
Domain model: user/actor/realm
nae-object-library/.../AbstractUser.java, .../AbstractActor.java, .../LoggedUser.java, .../Realm.java, .../enums/UserType.java
Added UserType enum and field on AbstractUser and response DTOs; constructors updated (now protected) to include UserType; LoggedUser constructors updated (protected) to include type and set sessionTimeout; Realm gains domains list and constructor visibility reduced.
User service API and implementation
nae-user-common/.../auth/service/UserService.java, nae-user-ce/.../auth/service/UserServiceImpl.java
Replaced AbstractUser with User across method signatures and paging; added UpdateUserRequest-based update overloads and helper; injected RealmService; refined system user/type handling; numerous related private helpers updated to User.
Group services
nae-user-common/.../auth/service/GroupService.java, nae-user-ce/.../auth/service/GroupServiceImpl.java
Switched parameters from AbstractUser to User across create/get/add/remove methods; internal pages and lookups updated accordingly.
Registration service
application-engine/.../auth/service/interfaces/IRegistrationService.java, .../auth/service/RegistrationService.java
Public methods now accept/return User instead of AbstractUser (password ops, creation, registration, recovery); casts removed; token and persistence paths updated.
Controllers and assemblers
application-engine/.../auth/web/AuthenticationController.java, .../auth/web/PublicUserController.java, .../auth/web/UserController.java, .../auth/web/responsebodies/UserResourceAssembler.java, application-engine/.../impersonation/web/ImpersonationController.java
Controller internals and paging types changed to User; assembler generic type changed to User; impersonation endpoint now assembles Page and adds resource links.
Impersonation services
application-engine/.../impersonation/service/interfaces/IImpersonationAuthorizationService.java, .../service/ImpersonationAuthorizationService.java, .../service/interfaces/IImpersonationService.java, .../service/ImpersonationService.java
Public APIs and internals switched from AbstractUser to User for impersonated subjects; return types and parameters updated; imports adjusted.
Process role services
application-engine/.../petrinet/service/ProcessRoleService.java, nae-spring-core-adapter/.../petrinet/service/ProcessRoleService.java
assignRolesToUser overloads and internal helpers now use User; delete/search flows updated to Page; imports consolidated.
Web DTOs
nae-user-common/.../auth/web/requestbodies/UpdateUserRequest.java, nae-user-common/.../auth/web/responsebodies/User.java
UpdateUserRequest gains UserType field; User response adds UserType, populated from domain User.
Startup and utilities
application-engine/.../startup/runner/SuperCreatorRunner.java, application-engine/.../workflow/service/MongoSearchService.java, nae-spring-core-adapter/.../auth/domain/AnonymousUser.java, application-engine/src/test/java/.../MockService.java
Super user field/type changed to User; author resolution uses User; AnonymousUser sets type to ANONYMOUS; test LoggedUserImpl constructor updated to include UserType.
Realm service updates
nae-user-ce/.../auth/service/RealmServiceImpl.java, nae-user-common/.../auth/service/RealmService.java
Propagates domains on create/update; removed unused import in interface.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant API as UserController/API
  participant USvc as UserService
  participant Repo as UserRepository
  participant Realm as RealmService

  Client->>API: PATCH /users/{id} (UpdateUserRequest)
  API->>USvc: update(userId, realmId, UpdateUserRequest)
  USvc->>Repo: findById(userId, realmId)
  Repo-->>USvc: User
  USvc->>USvc: resolveUserUpdateValue(...) per field
  USvc->>Realm: resolve realm (if needed)
  Realm-->>USvc: Realm
  USvc->>Repo: save(User with updated fields/type)
  Repo-->>USvc: User
  USvc-->>API: User
  API-->>Client: 200 OK (User DTO with type)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Possibly related PRs

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 includes the ticket reference and clearly summarizes the primary change—adding a user flag to distinguish internal and external users—making it concise and specific to the pull request’s main objective.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e22f3fe and ba3cf1e.

📒 Files selected for processing (4)
  • application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.java (9 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationService.java (5 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java (1 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java (7 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-04T11:09:31.264Z
Learnt from: renczesstefan
PR: netgrif/application-engine#350
File: application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java:56-63
Timestamp: 2025-09-04T11:09:31.264Z
Learning: In the SuperCreatorRunner.java file, setPassword() sets the same credential as setCredential("password", passwordCredential), so there's no need to call both methods when creating the super user.

Applied to files:

  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java
📚 Learning: 2025-09-04T11:09:31.264Z
Learnt from: renczesstefan
PR: netgrif/application-engine#350
File: application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java:56-63
Timestamp: 2025-09-04T11:09:31.264Z
Learning: In SuperCreatorRunner.java, when creating a user with PasswordCredential via setCredential("password", passwordCredential), there's no need to also call setPassword() as it would be redundant - the PasswordCredential already contains the password information needed by UserServiceImpl.createUser(), and both setPassword() and setCredential() ultimately reference the same credential system.

Applied to files:

  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java
📚 Learning: 2025-09-04T11:09:31.264Z
Learnt from: renczesstefan
PR: netgrif/application-engine#350
File: application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java:56-63
Timestamp: 2025-09-04T11:09:31.264Z
Learning: In SuperCreatorRunner.java, when creating a user with PasswordCredential via setCredential("password", passwordCredential), there's no need to also call setPassword() as it would be redundant - the PasswordCredential already contains the password information needed by UserServiceImpl.createUser().

Applied to files:

  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java
🧬 Code graph analysis (1)
application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java (1)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/constants/UserConstants.java (1)
  • UserConstants (3-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (3)
application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java (1)

49-75: Type alignment looks good

Returning User here keeps the method, field, and getter consistent with the updated service API. Nice cleanup.

nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java (1)

37-196: Alignment with concrete User type

The interface consistently switching to the domain User keeps the contract in lockstep with the rest of the migration—looks good to me.

application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationService.java (1)

155-158: Appreciate the switch to isAdmin()
This removes the invalid Boolean cast we flagged earlier and keeps the admin shortcut straightforward.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

@coderabbitai coderabbitai bot added improvement A change that improves on an existing feature new feature A change that introduces new functionality labels Sep 19, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 22

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (34)
application-engine/src/main/java/com/netgrif/application/engine/startup/ApplicationRunnerExecutor.java (1)

53-56: Avoid resolving class twice; hoist runnerClass.

Minor cleanup to compute once and reuse in catch.

-    protected void callRunner(T runner, ApplicationRunnerOrderResolver.SortedRunners<T> runners, ApplicationArguments args) throws Exception {
-        try {
-            Class<?> runnerClass = resolveClass(runner);
+    protected void callRunner(T runner, ApplicationRunnerOrderResolver.SortedRunners<T> runners, ApplicationArguments args) throws Exception {
+        Class<?> runnerClass = resolveClass(runner);
+        try {
             if (runners.getReplaced().containsKey(runnerClass)) {
                 log.warn("Runner {} is starting that replaced runner {}", runnerClass.getSimpleName(), runners.getReplaced().get(runnerClass).getSimpleName());
             } else {
                 log.info("Runner {} is starting", runnerClass.getSimpleName());
             }
             executeRunner(runner, args);
             log.info("Runner {} has ended", runnerClass.getSimpleName());
         } catch (Exception e) {
-            Class<?> runnerClass = resolveClass(runner);
             if (runnerClass.isAnnotationPresent(OptionalRunner.class)) {
                 log.error("Runner {} has failed. Runner is flagged as optional, execution will continue", runnerClass.getSimpleName(), e);
             } else {
                 log.error("Runner {} has failed", runnerClass.getSimpleName(), e);
                 throw new RuntimeException(e);
             }
         }
     }

Also applies to: 63-66

application-engine/src/main/java/com/netgrif/application/engine/auth/web/AuthenticationController.java (1)

196-216: Missing subject check allows cross-account password change

Any authenticated user can change another user’s password if they know the current password. Enforce “self or admin” and guard null auth.

Apply:

-            Optional<User> user = userService.findUserByUsername(request.login, null);
+            Optional<User> user = userService.findUserByUsername(request.login, null);
             if (user.isEmpty() || request.password == null || request.newPassword == null) {
                 return MessageResource.errorMessage("Incorrect login!");
             }
 
+            if (auth == null || !(auth.getPrincipal() instanceof LoggedUser principal)) {
+                return MessageResource.errorMessage("Not authenticated!");
+            }
+
             String newPassword = new String(Base64.getDecoder().decode(request.newPassword));
             if (!registrationService.isPasswordSufficient(newPassword)) {
                 return MessageResource.errorMessage("Insufficient password!");
             }
 
             String password = new String(Base64.getDecoder().decode(request.password));
-            if (registrationService.stringMatchesUserPassword(user.get(), password)) {
-                registrationService.changePassword((user.get()), newPassword);
-                securityContextService.saveToken(((LoggedUser) auth.getPrincipal()).getStringId());
-                securityContextService.reloadSecurityContext((LoggedUser) auth.getPrincipal());
+            User target = user.get();
+            if (!principal.isAdmin() && !principal.getStringId().equals(target.getStringId())) {
+                return MessageResource.errorMessage("Forbidden!");
+            }
+            if (registrationService.stringMatchesUserPassword(target, password)) {
+                registrationService.changePassword(target, newPassword);
+                if (principal.getStringId().equals(target.getStringId())) {
+                    securityContextService.saveToken(principal.getStringId());
+                    securityContextService.reloadSecurityContext(principal);
+                }
             } else {
                 return MessageResource.errorMessage("Incorrect password!");
             }
application-engine/src/main/java/com/netgrif/application/engine/menu/services/MenuItemService.java (3)

630-642: Fix immutable List mutation: List.of(...) causes runtime UnsupportedOperationException

Both appendChildCaseIdInDataSet and appendChildCaseIdInMemory create immutable lists via List.of(...) and later mutate them. This will blow up on the next append.

Apply this diff:

@@
-    protected void appendChildCaseIdInDataSet(Case folderCase, String childItemCaseId, Map<String, Map<String, Object>> dataSet) {
-        List<String> childIds = MenuItemUtils.getCaseIdsFromCaseRef(folderCase, MenuItemConstants.FIELD_CHILD_ITEM_IDS);
-        if (childIds == null || childIds.isEmpty()) {
-            childIds = List.of(childItemCaseId);
-        } else {
-            childIds.add(childItemCaseId);
-        }
+    protected void appendChildCaseIdInDataSet(Case folderCase, String childItemCaseId, Map<String, Map<String, Object>> dataSet) {
+        List<String> existing = MenuItemUtils.getCaseIdsFromCaseRef(folderCase, MenuItemConstants.FIELD_CHILD_ITEM_IDS);
+        List<String> childIds = new ArrayList<>(existing == null ? Collections.emptyList() : existing);
+        childIds.add(childItemCaseId);
@@
-    protected void appendChildCaseIdInMemory(Case folderCase, String childItemCaseId) {
-        List<String> childIds = MenuItemUtils.getCaseIdsFromCaseRef(folderCase, MenuItemConstants.FIELD_CHILD_ITEM_IDS);
-        if (childIds == null || childIds.isEmpty()) {
-            folderCase.getDataField(MenuItemConstants.FIELD_CHILD_ITEM_IDS).setValue(List.of(childItemCaseId));
-        } else {
-            childIds.add(childItemCaseId);
-            folderCase.getDataField(MenuItemConstants.FIELD_CHILD_ITEM_IDS).setValue(childIds);
-        }
+    protected void appendChildCaseIdInMemory(Case folderCase, String childItemCaseId) {
+        List<String> existing = MenuItemUtils.getCaseIdsFromCaseRef(folderCase, MenuItemConstants.FIELD_CHILD_ITEM_IDS);
+        List<String> childIds = new ArrayList<>(existing == null ? Collections.emptyList() : existing);
+        childIds.add(childItemCaseId);
+        folderCase.getDataField(MenuItemConstants.FIELD_CHILD_ITEM_IDS).setValue(childIds);
         folderCase.getDataField(MenuItemConstants.FIELD_HAS_CHILDREN).setValue(MenuItemUtils.hasFolderChildren(folderCase));
     }

Also applies to: 645-653


239-244: Use the constant for process identifier; remove leftover TODO

Hardcoding "menu_item" is brittle and inconsistent with the rest of the class.

     @Override
     public boolean existsMenuItem(String identifier) {
-        //TODO mongo
-        Case menuItem = this.workflowService.searchOne(QCase.case$.processIdentifier.eq("menu_item")
+        Case menuItem = this.workflowService.searchOne(QCase.case$.processIdentifier
+                .eq(MenuProcessRunner.MENU_NET_IDENTIFIER)
                 .and(QCase.case$.dataSet.get(MenuItemConstants.FIELD_IDENTIFIER).value.eq(identifier)));
         return menuItem != null;

693-701: nameFromPath returns a leading slash for nested paths

For "/a/b" it returns "/b". Likely the intent is "b".

-    protected String nameFromPath(String path) {
+    protected String nameFromPath(String path) {
         if (path == null || path.equals(MenuItemConstants.PATH_SEPARATOR) || path.isEmpty()) {
             return "";
         }
-        if (path.lastIndexOf(MenuItemConstants.PATH_SEPARATOR) == 0) {
-            return path.replace(MenuItemConstants.PATH_SEPARATOR, "");
-        }
-        return path.substring(path.lastIndexOf(MenuItemConstants.PATH_SEPARATOR));
+        int idx = path.lastIndexOf(MenuItemConstants.PATH_SEPARATOR);
+        if (idx == 0) return path.substring(1);
+        return path.substring(idx + 1);
     }
application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResourceAssembler.java (1)

32-39: Exception message and unused small flag

  • Message still says “toResource”; this class exposes toModel.
  • The initialized ‘small’ flag is never used.
-            throw new IllegalStateException("You must initialize the UserResourceAssembler before calling the toResource method! To initialize the assembler call the initialize method.");
+            throw new IllegalStateException("You must initialize the UserResourceAssembler before calling the toModel method! Call initialize(locale, small, selfRel) first.");

If small should affect projection, consider threading it into userFactory.getUser(...) or the UserResource constructor.

application-engine/src/main/java/com/netgrif/application/engine/auth/web/PublicUserController.java (1)

56-71: Align getLoggedUser to domain User

Stay consistent with the migration away from AbstractUser.

-        AbstractUser user;
+        com.netgrif.application.engine.objects.auth.domain.User user;
         try {
             user = userService.findById(loggedUser.getStringId(), loggedUser.getRealmId());

Update imports accordingly.

application-engine/src/main/java/com/netgrif/application/engine/impersonation/web/ImpersonationController.java (1)

69-77: Use User.class in ResourceLinkAssembler.addLinks

Links are being added under AbstractUser.class while the page now holds User. This can break link assembly or produce inconsistent rels.

-        ResourceLinkAssembler.addLinks(resources, AbstractUser.class, selfLink.getRel().toString());
+        ResourceLinkAssembler.addLinks(resources, User.class, selfLink.getRel().toString());
nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/domain/LoggedUserImpl.java (1)

24-25: Remove Lombok @AllArgsConstructor to avoid generating an invalid no‑arg ctor

This class declares no fields; @AllArgsConstructor will generate a no‑arg constructor calling super(), which may not exist on LoggedUser and can break compilation or allow unintended construction paths. Rely on the explicit ctors only.

Apply:

-import lombok.AllArgsConstructor;
@@
-@AllArgsConstructor
 public class LoggedUserImpl extends LoggedUser implements UserDetails {
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractUser.java (1)

19-21: Remove Lombok @AllArgsConstructor to prevent an incomplete ctor without id/realmId

@AllArgsConstructor here generates a constructor for this class’s fields only (not id/realmId in the superclass), competing with explicit ctors and enabling partially‑initialized instances in subclasses.

Apply:

-import lombok.AllArgsConstructor;
@@
-@AllArgsConstructor
 @EqualsAndHashCode(callSuper = true)
 public abstract class AbstractUser extends AbstractActor {
application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserController.java (3)

219-230: Missing authorization guard on role assignment endpoint

Endpoint allows assigning roles without @PreAuthorize; spec says ADMIN required. Add explicit guard.

Apply:

-    public ResponseEntity<ResponseMessage> assignRolesToUser(@PathVariable("realmId") String realmId, @PathVariable("id") String userId, @RequestBody Set<String> roleIds, Authentication auth) {
+    @PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
+    public ResponseEntity<ResponseMessage> assignRolesToUser(@PathVariable("realmId") String realmId, @PathVariable("id") String userId, @RequestBody Set<String> roleIds, Authentication auth) {

278-287: Success/error messages are swapped

On failure you return a “success” message; on success you return an “error” message. Swap factories.

Apply:

-        } catch (IllegalArgumentException e) {
-            log.error("Assigning authority to user [{}] has failed!", userId, e);
-            return ResponseEntity.badRequest().body(ResponseMessage.createSuccessMessage("Assigning authority to user " + userId + " has failed!"));
-        }
-        return ResponseEntity.ok(ResponseMessage.createErrorMessage("Authority was assigned to user successfully"));
+        } catch (IllegalArgumentException e) {
+            log.error("Assigning authority to user [{}] has failed!", userId, e);
+            return ResponseEntity.badRequest().body(ResponseMessage.createErrorMessage("Assigning authority to user " + userId + " has failed!"));
+        }
+        return ResponseEntity.ok(ResponseMessage.createSuccessMessage("Authority was assigned to user successfully"));

161-164: Use 403 Forbidden instead of 401 Unauthorized for authorization failures

The caller is authenticated but not allowed to access another user; 403 is the correct status.

Apply:

-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+            return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java (2)

314-319: Bug: persisting with null realm.

Calling saveUser(user, null) will overwrite user.realmId with null in UserServiceImpl, risking collection routing issues.

Apply:

-        userService.saveUser(user, null);
+        userService.saveUser(user);

210-241: Remove unused private helpers in ProcessRoleService

updateRequestedRoles(...) and getPetriNetIdRoleBelongsTo/getPetriNetIdFromFirstRole are unused — ripgrep shows only their definitions in application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java (lines 210–241). Delete them to remove dead/duplicated code.

nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java (4)

190-206: Lookup loop works; consider direct query.

Current paging + filter is O(n). If feasible, add repository method findByOwnerIdAndIdentifier(ownerId, username) to avoid scanning.


247-253: Mirror the realm guard for removal; consider atomicity.

-    public Group removeUser(User user, Group group) {
+    // @Transactional
+    public Group removeUser(User user, Group group) {
+        if (!Objects.equals(user.getRealmId(), group.getRealmId())) {
+            throw new IllegalArgumentException(
+                "User [%s] and Group [%s] belong to different realms".formatted(user.getStringId(), group.getStringId()));
+        }
         log.info("Removing user [{}] from group [{}]", user.getStringId(), group.getStringId());
         user.removeGroupId(group.getStringId());
         group.removeMemberId(user.getStringId());
         userService.saveUser(user, user.getRealmId());
         return save(group);
     }

385-392: Use exact match for realmId to avoid slow/incorrect matches.

realmId is an identifier; regex "i" is unnecessary and can mis-match.

-        if (searchDto.getRealmId() != null && !searchDto.getRealmId().isBlank()) {
-            filters.add(Criteria.where("realmId").regex(searchDto.getRealmId(), "i"));
-        }
+        if (searchDto.getRealmId() != null && !searchDto.getRealmId().isBlank()) {
+            filters.add(Criteria.where("realmId").is(searchDto.getRealmId()));
+        }

232-238: Enforce same‑realm and make addUser atomic

  • Add a realm check at the start of addUser(User, Group) and make the user+group saves atomic. Location: nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java — addUser(User, Group).
  • Repo scan: @transactional is used elsewhere but no MongoTransactionManager or explicit Mongo transaction bean was found — verify Mongo multi‑document transactions (MongoTransactionManager + replica set) before relying on @transactional; if not available, use MongoTemplate.executeInTransaction/TransactionTemplate or a compensating update.

Suggested change (small diff):

-    public Group addUser(User user, Group group) {
+    // Optionally annotate if Mongo transactions are enabled
+    // @Transactional
+    public Group addUser(User user, Group group) {
+        if (!Objects.equals(user.getRealmId(), group.getRealmId())) {
+            throw new IllegalArgumentException(
+                "User [%s] and Group [%s] belong to different realms".formatted(user.getStringId(), group.getStringId()));
+        }
         log.info("Adding user [{}] to group [{}]", user.getStringId(), group.getStringId());
         user.addGroupId(group.getStringId());
         group.addMemberId(user.getStringId());
         userService.saveUser(user, user.getRealmId());
         return save(group);
     }

If using @transactional, also add: import org.springframework.transaction.annotation.Transactional;

application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationAuthorizationService.java (1)

53-66: Pagination total is wrong — totalElements must count unique impersonated users, not cases

You dedupe user IDs from cases.getContent() but still pass cases.getTotalElements() (total cases) to PageImpl; that makes paging/total incorrect. Compute the total number of DISTINCT impersonated user IDs for the same filters and use that as the PageImpl total (e.g., DB DISTINCT/count or an ES cardinality aggregation). Temporary fallback: users.size() will only reflect the current page and is not a correct global total.

File: application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationAuthorizationService.java (lines 53–66)

application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.java (9)

54-59: Use the all-realms removal API; current call likely only affects the default realm

Avoid passing null realmId into a single‑realm method. Use the multi‑realm variant to actually sweep all realms.

Apply this diff:

-    public void removeExpiredUsers() {
+    public void removeExpiredUsers() {
         log.info("Removing expired unactivated invited users");
-        userService.removeAllByStateAndExpirationDateBefore(UserState.INACTIVE, LocalDateTime.now(),null);
+        userService.removeAllByStateAndExpirationDateBeforeForRealms(UserState.INACTIVE, LocalDateTime.now(), null);
     }

89-94: Enforce password policy in changePassword

Validate strength before encoding.

Apply:

     public void changePassword(User user, String newPassword) {
-        user.setPassword(newPassword);
+        if (!isPasswordSufficient(newPassword)) {
+            throw new IllegalArgumentException("Password does not meet minimal requirements");
+        }
+        user.setPassword(newPassword);
         encodeUserPassword(user);
         userService.saveUser(user, null);
         log.info("Changed password for user " + user.getEmail() + ".");
     }

97-106: Don’t log raw tokens; guard against null expiration to avoid NPE

Logging secrets is unsafe. Also, getExpirationDate() can be null.

Apply:

     public boolean verifyToken(String token) {
         try {
-            log.info("Verifying token:" + token);
-            String[] tokenParts = decodeToken(token);
-            User user = userService.findByEmail(tokenParts[0], null);
-            return user != null && Objects.equals(user.getToken(), tokenParts[1]) && user.getExpirationDate().isAfter(LocalDateTime.now());
+            String[] tokenParts = decodeToken(token);
+            log.debug("Verifying token for {}", tokenParts[0]);
+            User user = userService.findByEmail(tokenParts[0], null);
+            return user != null
+                    && Objects.equals(user.getToken(), tokenParts[1])
+                    && user.getExpirationDate() != null
+                    && user.getExpirationDate().isAfter(LocalDateTime.now());
         } catch (InvalidUserTokenException e) {
             log.error(e.getMessage());
             return false;
         }
     }

110-116: Consider enforcing minimal password length here as well

Consistent enforcement protects other call sites.

     public void encodeUserPassword(User user) {
         String pass = user.getPassword();
         if (pass == null) {
             throw new IllegalArgumentException("User has no password");
         }
+        if (!isPasswordSufficient(pass)) {
+            throw new IllegalArgumentException("Password does not meet minimal requirements");
+        }
         user.setPassword(passwordEncoder.encode(pass));
     }

144-149: Avoid redundant cast and premature save inside addRole path

  • (User) cast on saveUser return is redundant.
  • Calling addRole before the first save forces a save with realmId == null.

Prefer saving first, then assigning default role; or at least drop the cast.

-        userService.addRole(user, processRoleService.getDefaultRole().getStringId());
-        user = (User) userService.saveUser(user, null);
+        user = userService.saveUser(user, null);
+        user = userService.addRole(user, processRoleService.getDefaultRole().getStringId());

If changing the order is risky for this release, at minimum:

-        user = (User) userService.saveUser(user, null);
+        user = userService.saveUser(user, null);

160-177: Critical: registerUser persists raw password

Must hash before saving; also enforce policy.

     public User registerUser(RegistrationRequest registrationRequest) throws InvalidUserTokenException {
         String email = decodeToken(registrationRequest.token)[0];
         log.info("Registering user " + email);
         User user = userService.findByEmail(email, null);
         if (user == null) {
             return null;
         }
 
         user.setFirstName(registrationRequest.name);
         user.setLastName(registrationRequest.surname);
-        user.setPassword(registrationRequest.password);
+        if (!isPasswordSufficient(registrationRequest.password)) {
+            throw new IllegalArgumentException("Password does not meet minimal requirements");
+        }
+        user.setPassword(registrationRequest.password);
+        encodeUserPassword(user);
 
         user.setToken(StringUtils.EMPTY);
         user.setExpirationDate(null);
         user.setState(UserState.ACTIVE);
 
         return userService.saveUser(user, null);
     }

180-194: Reset flow: avoid (User) cast and consider disabling vs nulling password

  • findByEmail already returns User; the cast is unnecessary.
  • Setting password to null can break password matches in unrelated code paths. Consider a sentinel like "N/A" or a dedicated credential flag.
-        User user = (User) userService.findByEmail(email, null);
+        User user = userService.findByEmail(email, null);
@@
-        user.setPassword(null);
+        user.setPassword(null); // consider sentinel or credential flag instead of null

197-210: Recover flow: enforce password policy before encode/save

Same policy as register/change.

     public User recover(String email, String newPassword) {
         log.info("Recovering user " + email);
         User user = userService.findByEmail(email, null);
         if (user == null) {
             return null;
         }
         user.setState(UserState.ACTIVE);
-        user.setPassword(newPassword);
+        if (!isPasswordSufficient(newPassword)) {
+            throw new IllegalArgumentException("Password does not meet minimal requirements");
+        }
+        user.setPassword(newPassword);
         encodeUserPassword(user);
         user.setToken(null);
         user.setExpirationDate(null);
 
         return userService.saveUser(user, null);
     }

229-235: Decode with explicit charset

Be explicit to avoid platform default differences.

-        String decodedString = new String(decodedBytes);
+        String decodedString = new String(decodedBytes, java.nio.charset.StandardCharsets.UTF_8);
nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserService.java (2)

415-418: Typo: singular type, plural name

realmIds is a String here. Rename to realmId.

-    Page<User> findAllByStateAndExpirationDateBefore(UserState state, LocalDateTime expirationDate, String realmIds, Pageable pageable);
+    Page<User> findAllByStateAndExpirationDateBefore(UserState state, LocalDateTime expirationDate, String realmId, Pageable pageable);

24-44: Add an all-realms finder to support scheduled maintenance

RegistrationService.resetExpiredToken() needs a cross‑realm cursor. Propose adding:

+    /**
+     * Finds users across all realms by state and expiration threshold.
+     */
+    Page<User> findAllByStateAndExpirationDateBeforeForAllRealms(UserState state, LocalDateTime expirationDate, Pageable pageable);

And implement in the CE module by iterating collectionNameProvider.getCollectionNamesForAllRealm().

nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java (3)

193-205: Double semicolon and redundant double-save

  • Remove the stray ;;.
  • You save the user twice in createUser(User, String). If the second save is intentional (post group ops), add a brief comment; otherwise drop the first save.
-        user = this.saveUser(user, realmId);;
+        user = this.saveUser(user, realmId);
@@
-        user = this.saveUser(user, realmId);
+        // Re-save only if group operations mutated the user; otherwise this is redundant.
+        user = this.saveUser(user, realmId);

If redundant, remove the first save and move setPassword before the single save as needed.


151-159: Remove redundant Optional.map

No-op .map(user -> user).

-        Optional<User> userOpt = userRepository.findByUsername(username, mongoTemplate, collectionName).map(user -> user);
+        Optional<User> userOpt = userRepository.findByUsername(username, mongoTemplate, collectionName);

631-637: Unnecessary cast and missing null check in updateAdminWithRoles

findByEmail already returns User; also guard for missing admin.

-        User admin = (User) findByEmail(UserConstants.ADMIN_USER_EMAIL, null);
+        User admin = findByEmail(UserConstants.ADMIN_USER_EMAIL, null);
+        if (admin == null) {
+            throw new IllegalStateException("Admin user not found");
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 786a111 and e22f3fe.

📒 Files selected for processing (46)
  • application-engine/pom.xml (2 hunks)
  • application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleServiceInjector.groovy (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.java (9 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IRegistrationService.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/auth/web/AuthenticationController.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/auth/web/PublicUserController.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserController.java (4 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResourceAssembler.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationAuthorizationService.java (5 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationService.java (5 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/interfaces/IImpersonationAuthorizationService.java (3 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/interfaces/IImpersonationService.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/impersonation/web/ImpersonationController.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/menu/services/MenuItemService.java (5 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java (6 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/startup/ApplicationRunnerExecutor.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/startup/ApplicationRunnerOrderResolver.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseEventHandler.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/MongoSearchService.java (2 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java (1 hunks)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java (1 hunks)
  • application-engine/src/test/java/com/netgrif/application/engine/MockService.java (2 hunks)
  • nae-object-library/pom.xml (1 hunks)
  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java (1 hunks)
  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractUser.java (4 hunks)
  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/LoggedUser.java (3 hunks)
  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/Realm.java (1 hunks)
  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/enums/UserType.java (1 hunks)
  • nae-spring-core-adapter/pom.xml (1 hunks)
  • nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/domain/AnonymousUser.java (2 hunks)
  • nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/domain/LoggedUserImpl.java (3 hunks)
  • nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/service/ProcessRoleService.java (2 hunks)
  • nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java (1 hunks)
  • nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/workflow/domain/Case.java (1 hunks)
  • nae-user-ce/pom.xml (1 hunks)
  • nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java (9 hunks)
  • nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/RealmServiceImpl.java (2 hunks)
  • nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java (24 hunks)
  • nae-user-common/pom.xml (1 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java (7 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/RealmService.java (0 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserService.java (27 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/UpdateUserRequest.java (3 hunks)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/User.java (3 hunks)
  • pom.xml (1 hunks)
💤 Files with no reviewable changes (1)
  • nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/RealmService.java
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-07-31T08:05:21.587Z
Learnt from: renczesstefan
PR: netgrif/application-engine#329
File: nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/RealmServiceImpl.java:39-39
Timestamp: 2025-07-31T08:05:21.587Z
Learning: In the Netgrif Application Engine, the domain Realm class (com.netgrif.application.engine.objects.auth.domain.Realm) is abstract and cannot be instantiated. The concrete implementation is in the adapter package (com.netgrif.application.engine.adapter.spring.auth.domain.Realm) which extends the abstract domain class. Services must instantiate the concrete adapter class and cast it when saving to repositories that accept the abstract domain type.

Applied to files:

  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/Realm.java
  • nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/RealmServiceImpl.java
📚 Learning: 2025-09-04T11:09:31.264Z
Learnt from: renczesstefan
PR: netgrif/application-engine#350
File: application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java:56-63
Timestamp: 2025-09-04T11:09:31.264Z
Learning: In the SuperCreatorRunner.java file, setPassword() sets the same credential as setCredential("password", passwordCredential), so there's no need to call both methods when creating the super user.

Applied to files:

  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java
📚 Learning: 2025-09-04T11:09:31.264Z
Learnt from: renczesstefan
PR: netgrif/application-engine#350
File: application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java:56-63
Timestamp: 2025-09-04T11:09:31.264Z
Learning: In SuperCreatorRunner.java, when creating a user with PasswordCredential via setCredential("password", passwordCredential), there's no need to also call setPassword() as it would be redundant - the PasswordCredential already contains the password information needed by UserServiceImpl.createUser(), and both setPassword() and setCredential() ultimately reference the same credential system.

Applied to files:

  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java
📚 Learning: 2025-09-04T11:09:31.264Z
Learnt from: renczesstefan
PR: netgrif/application-engine#350
File: application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java:56-63
Timestamp: 2025-09-04T11:09:31.264Z
Learning: In SuperCreatorRunner.java, when creating a user with PasswordCredential via setCredential("password", passwordCredential), there's no need to also call setPassword() as it would be redundant - the PasswordCredential already contains the password information needed by UserServiceImpl.createUser().

Applied to files:

  • application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java
🧬 Code graph analysis (7)
application-engine/src/main/java/com/netgrif/application/engine/startup/ApplicationRunnerExecutor.java (1)
nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java (1)
  • NaeReflectionUtils (8-57)
application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java (1)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/constants/UserConstants.java (1)
  • UserConstants (3-11)
application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseEventHandler.java (2)
application-engine/src/main/java/com/netgrif/application/engine/importer/service/FieldFactory.java (1)
  • org (31-862)
nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/workflow/domain/Case.java (1)
  • Document (19-109)
application-engine/src/main/java/com/netgrif/application/engine/menu/services/MenuItemService.java (1)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/workflow/domain/menu/MenuItemConstants.java (1)
  • MenuItemConstants (7-39)
application-engine/src/main/java/com/netgrif/application/engine/startup/ApplicationRunnerOrderResolver.java (1)
nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java (1)
  • NaeReflectionUtils (8-57)
nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java (3)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java (1)
  • Getter (21-311)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/Group.java (1)
  • Getter (17-172)
nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java (1)
  • Slf4j (39-719)
nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java (4)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/constants/UserConstants.java (1)
  • UserConstants (3-11)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java (1)
  • Getter (21-311)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/Group.java (1)
  • Getter (17-172)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/Authority.java (1)
  • Getter (17-141)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: task-list-completed
  • GitHub Check: task-list-completed
  • GitHub Check: task-list-completed
  • GitHub Check: task-list-completed
  • GitHub Check: task-list-completed
🔇 Additional comments (53)
pom.xml (1)

9-9: Root version bump acknowledged.
Downstream POMs appear updated; keep jackson.version consistent with module usages (see comments in module POMs).

nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractActor.java (1)

46-54: Constructor visibility tightened — good encapsulation.
Protected ctors prevent external instantiation while keeping subclass access. No concerns.

nae-user-ce/pom.xml (1)

9-9: Parent bump verified — all POMs use 7.0.0-RC7.1
Search output shows a single parent version (7.0.0-RC7.1) across the repo; no action required.

nae-object-library/pom.xml (1)

10-10: Align jackson-datatype-jsr310 to parent-managed ${jackson.version}

Two modules explicitly pin jsr310 to 2.18.2 — switch them to ${jackson.version} for consistency.

Locations: nae-user-common/pom.xml (lines 98–99), nae-object-library/pom.xml (lines 78–79)

Apply:

-        <dependency>
-            <groupId>com.fasterxml.jackson.datatype</groupId>
-            <artifactId>jackson-datatype-jsr310</artifactId>
-            <version>2.18.2</version>
-            <scope>provided</scope>
-        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+            <version>${jackson.version}</version>
+            <scope>provided</scope>
+        </dependency>

Likely an incorrect or invalid review comment.

nae-spring-core-adapter/pom.xml (1)

10-10: Version alignment confirmed for adapter; application-engine not verifiable

nae-spring-core-adapter/pom.xml (parent) contains 7.0.0-RC7.1. No application-engine parent POM was found in the repo to confirm the downstream bump — verify that application-engine picked up 7.0.0-RC7.1.

application-engine/src/main/java/com/netgrif/application/engine/startup/ApplicationRunnerExecutor.java (1)

15-16: Centralizing class resolution via NaeReflectionUtils is good.

Static import of resolveClass aligns with other modules and handles proxies. LGTM.

nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/enums/UserType.java (1)

1-9: Enum introduction looks good.

Clear, minimal enum. Consider documenting semantics (e.g., who can assign SYSTEM) in javadocs elsewhere.

application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java (1)

86-87: setPetriNet added — implemented internally; downstream check needed

IWorkflowService#setPetriNet(Case) declared at application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IWorkflowService.java:86 and implemented in application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java:501; callers at application-engine/src/main/java/com/netgrif/application/engine/workflow/service/CaseEventHandler.java:37 and WorkflowService.java:126,142. No other implementers found in this repo — verify downstream consumers if this is a published API.

nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/domain/AnonymousUser.java (1)

6-6: Correctly setting anonymous user type; verify persistence/migration.

Setting this.type = UserType.ANONYMOUS is appropriate. Please verify that:

  • AbstractUser persists type and serializers/deserializers handle missing/null type (older records) with a safe default.

Also applies to: 45-46

application-engine/src/main/java/com/netgrif/application/engine/workflow/service/MongoSearchService.java (1)

5-6: Method name vs. lookup mismatch; confirm correct identifier and query shape.

resolveAuthorByEmail calls userService.findUserByUsername(email, null). If usernames aren’t emails, this returns wrong users. Also confirm whether downstream expects a quoted string or an {$oid:"..."} fragment.

If emails are the intended identifier, switch to findUserByEmail(...) (or add such method). If username is indeed the email, consider renaming to resolveAuthorByUsername to avoid confusion.

-    protected String resolveAuthorByEmail(String email) {
-        Optional<User> user = userService.findUserByUsername(email, null);
-        return user.map(User::getStringId).orElse(null);
-    }
+    protected String resolveAuthorByEmail(String email) {
+        // Prefer a dedicated email lookup if available
+        Optional<User> user = userService.findUserByEmail(email); // adjust to actual API
+        return user.map(User::getStringId).orElse(null);
+    }

Also applies to: 248-250

application-engine/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java (1)

500-509: Guard against null PetriNetId and document idempotency

  • new ObjectId(useCase.getPetriNetId()) will throw if getPetriNetId() is null — add an explicit null-check and clear exception (include useCase.getStringId()). I could not find the Case class/getPetriNetId implementation in this module to confirm if it can be null; verify and fix accordingly.
  • Decide & document whether setPetriNet should be idempotent (avoid re‑initializing tokens/arcs when a model is already attached) or add a guard.
     @Override
     public void setPetriNet(Case useCase) {
         PetriNet model = useCase.getPetriNet();
-        if (model == null) {
-            model = new com.netgrif.application.engine.adapter.spring.petrinet.domain.PetriNet((com.netgrif.application.engine.adapter.spring.petrinet.domain.PetriNet) petriNetService.get(new ObjectId(useCase.getPetriNetId())));
-            useCase.setPetriNet(model);
-        }
-        model.initializeTokens(useCase.getActivePlaces());
-        model.initializeArcs(useCase.getDataSet());
+        if (model == null) {
+            String netId = useCase.getPetriNetId();
+            if (netId == null) {
+                throw new IllegalStateException("Case " + useCase.getStringId() + " has no PetriNetId");
+            }
+            model = new com.netgrif.application.engine.adapter.spring.petrinet.domain.PetriNet(
+                (com.netgrif.application.engine.adapter.spring.petrinet.domain.PetriNet)
+                    petriNetService.get(new ObjectId(netId)));
+            useCase.setPetriNet(model);
+        }
+        // If re-initialization on existing model is not required, guard with a flag/condition.
+        model.initializeTokens(useCase.getActivePlaces());
+        model.initializeArcs(useCase.getDataSet());
     }
nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/Realm.java (1)

116-116: Constructor visibility tightened — OK

Protected ctor on an abstract class is appropriate and non-breaking for subclasses.

Please confirm the adapter subclass (com.netgrif.application.engine.adapter.spring.auth.domain.Realm) still calls super(name) successfully in all constructors.

nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/User.java (1)

39-39: Expose User.type in responses — OK

Mapping type from domain to response is correct and backwards compatible.

Confirm all clients tolerate the new field (no strict JSON schema enforcement). If needed, document in release notes.

Also applies to: 67-67

application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java (1)

41-41: Switched to domain User — OK

Type aligns with refactor across services.

application-engine/pom.xml (2)

9-9: Parent bump to 7.0.0-RC7.1 — verified

All module POMs reference application-engine-parent version 7.0.0-RC7.1; no mismatches found.


138-142: Approve — nae-spring-core-adapter module present and dependency added
Root pom.xml includes nae-spring-core-adapter and application-engine/pom.xml declares the dependency (lines 138–142); required for NaeReflectionUtils — OK.

application-engine/src/main/java/com/netgrif/application/engine/menu/services/MenuItemService.java (4)

212-216: Predicate refactor LGTM

QueryDSL-based lookup by name and path is clear and type-safe.


227-229: Predicate refactor LGTM

Folder lookup via QCase predicate reads well.


388-390: Good extraction

Centralizing predicate-based lookups through findCase(Predicate) reduces duplication.


158-163: Incorrect — identifiers are sanitized before persistence; no change required.

MenuItemBody.getIdentifier() calls MenuItemUtils.sanitize(...) and toDataSet() writes that sanitized value, and MenuItemService already uses sanitized identifiers for creation/update/lookups (so lookups against FIELD_IDENTIFIER are consistent). See: nae-object-library/.../MenuItemBody.java:90 (getIdentifier) and :163 (putDataSetEntry FIELD_IDENTIFIER); application-engine/.../MenuItemService.java:99-101 (createMenuItem), 155-161 (createOrUpdateMenuItem), 197-201 (findMenuItem query).

Likely an incorrect or invalid review comment.

application-engine/src/main/java/com/netgrif/application/engine/auth/web/responsebodies/UserResourceAssembler.java (1)

11-11: Switch to domain User type: OK

Interface generic updated to User; consistent with the PR-wide migration.

application-engine/src/main/java/com/netgrif/application/engine/auth/web/PublicUserController.java (2)

83-87: Search now returns Page: OK

Type migration looks correct, including roles mapping and principal usage.


130-136: DTO conversion helpers: OK

Signatures align with the domain User type and response DTO mapping.

application-engine/src/main/java/com/netgrif/application/engine/startup/ApplicationRunnerOrderResolver.java (1)

17-19: Static imports of NaeReflectionUtils: OK

Delegating resolve/index helpers to the shared utility reduces duplication. SortedRunners logic remains intact.

nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/LoggedUser.java (1)

70-76: Constructor changes verified — LoggedUserImpl updated

  • nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/auth/domain/LoggedUserImpl.java calls super(..., sessionTimeout, type); no other subclasses extending LoggedUser found.
application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/interfaces/IImpersonationService.java (1)

31-34: Signature migration to User — implemented and resolved.

ImpersonationService implements IImpersonationService and defines reloadImpersonatedUserRoles (application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationService.java:143) and applyRolesAndAuthorities (application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationService.java:155) with User signatures; no other callers found (only a commented reference at application-engine/src/main/java/com/netgrif/application/engine/auth/service/UserResourceHelperService.java:55).

nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/service/ProcessRoleService.java (1)

25-27: API change to User — implementers & call sites updated

New User-based signatures are implemented and in use. Locations: nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/petrinet/service/ProcessRoleService.java (interface); application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java (implementation + internal calls); application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserController.java (controller call site).

nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java (1)

24-28: LGTM: proxy‑aware class resolution

resolveClass correctly unwraps Spring AOP proxies and handles Class inputs.

application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserController.java (1)

103-105: Type migration to domain User: controller layer changes look consistent

FQCN usage for domain User avoids collision with response DTO and the mapping to UI User via userFactory remains intact.

Please ensure Swagger/OpenAPI schemas remain unchanged for responses; run your API docs generation and spot-check /api/users/{realmId}/all and /api/users/search.

Also applies to: 141-146, 328-334

nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractUser.java (1)

75-84: Enforce non‑null UserType and revisit equality semantics

  • Require non-null for type in both constructors:
@@
-        this.type = type;
+        this.type = java.util.Objects.requireNonNull(type, "user type must not be null");
  • If identity should remain based on id/realmId, exclude type from equals/hashCode:
-@EqualsAndHashCode(callSuper = true)
+@EqualsAndHashCode(callSuper = true, exclude = "type")

Confirm intended equality semantics for users across caches/collections. Applies to nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/domain/AbstractUser.java lines 75-84 and 99-108.

application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/interfaces/IImpersonationAuthorizationService.java (1)

5-5: API signature change verified — implementor and callers updated

IImpersonationAuthorizationService now uses User/LoggedUser; the sole implementor (ImpersonationAuthorizationService) and callers (ImpersonationService, ImpersonationController) already use User/LoggedUser — no AbstractUser-based signatures remain for these interface methods.

application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java (3)

140-150: Context reload flow is sound.

Persist-then-reload for current principal is correct.


104-112: Signature migration to User looks consistent — verify no remaining AbstractUser call sites

Overload delegates correctly; automated rg in the sandbox produced no matches, so cannot confirm absence of callers passing AbstractUser. Run locally:
rg -nP --type=java -C2 '\bassignRolesToUser\s*(\s*AbstractUser\b'


410-427: Incorrect — passing realm.getName() is correct. The UserService API is findAllByProcessRoles(..., String realmId, ...); realm.getName() supplies the expected realm identifier.

Likely an incorrect or invalid review comment.

application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationService.java (3)

58-64: User switch is OK.

findById now returning User integrates cleanly here.


73-77: OK: config-based impersonated lookup uses User.


143-152: Return type change to User is consistent.

nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java (4)

56-64: OK: default system group helper now accepts User.


169-179: OK: addUser(User, String) and addUser(User, Group).


187-197: OK: removeUser(User, …) overloads.


38-49: API migration to User — breaking change

Signatures now accept User (breaking). Ensure all implementors/consumers are updated.

  • Implementor found: nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java
  • Interface: nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/GroupService.java
  • Notable references to check/update: nae-user-ce/src/main/java/com/netgrif/application/engine/auth/config/AuthBeansConfiguration.java, application-engine/src/main/java/com/netgrif/application/engine/orgstructure/web/GroupController.java, application-engine/src/main/java/com/netgrif/application/engine/startup/runner/GroupRunner.java, application-engine/src/main/java/com/netgrif/application/engine/startup/runner/SuperCreatorRunner.java, application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java, application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/PetriNetService.java, application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.java, nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java

Action: search for callers passing AbstractUser/LoggedUser to GroupService methods and either update them to pass User, add adapter/overloads, or restore compatibility.

nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/GroupServiceImpl.java (3)

92-102: Member paging switch to Page looks good.


167-175: create(User) change is fine.

Guards duplicate default groups (except for system) and delegates to main creator.


177-187: create(String, String, User) is fine.

Owner/group membership are synchronized.

application-engine/src/main/java/com/netgrif/application/engine/impersonation/service/ImpersonationAuthorizationService.java (3)

76-78: OK: canImpersonateUser now works with User.


92-100: Authority filtering logic is fine.

Only authorities both present on user and allowed by config are kept.


103-114: Roles filtering logic is fine.

Includes default role and intersects config roles with user’s roles.

nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java (4)

288-306: Authority/role defaults look fine

Default authorities/role assignment is correctly guarded and persisted.


621-628: transformToUser overloads LGTM

Both correctly delegate to findById.


667-673: Casting helper assumes content type — safe for now

Given repository returns User, this is fine.


701-719: Confirm whether User extends AbstractUser — if not, update method parameter types.
verifyPasswords(...) and canUpdatePassword(...) accept AbstractUser; this is only correct if your concrete User type extends AbstractUser — otherwise change signatures to the concrete User type or a shared interface.
Location: nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java:701-719

application-engine/src/main/java/com/netgrif/application/engine/auth/service/RegistrationService.java (1)

67-86: resetExpiredToken — verify null‑realm handling; fix counting

  • findAllByStateAndExpirationDateBefore delegates to collectionNameProvider.getCollectionNameForRealm(realmId); passing null is handled by that provider — confirm whether null maps to a single/default realm. If it doesn't iterate all realms, either loop realms here or add a UserService method that does (like the remove variant).
  • Final log prints only the last page size; accumulate a total and remove the unnecessary stream when saving.

Suggested minimal fix:

-        do {
+        int total = 0;
+        do {
             users = userService.findAllByStateAndExpirationDateBefore(UserState.BLOCKED, LocalDateTime.now(), null, pageable);
             if (users == null || users.isEmpty()) {
                 log.info("There are none expired tokens. Everything is awesome.");
                 return;
             }
 
             users.forEach(user -> {
                 user.setToken(null);
                 user.setExpirationDate(null);
             });
-            userService.saveUsers(users.getContent().stream().toList());
+            userService.saveUsers(users.getContent());
+            total += users.getNumberOfElements();
 
             pageable = pageable.next();
         } while (users.hasNext());
 
-        log.info("Reset " + users.getContent().size() + " expired user tokens");
+        log.info("Reset " + total + " expired user tokens");
application-engine/src/main/java/com/netgrif/application/engine/auth/service/interfaces/IRegistrationService.java (1)

16-31: API migration to User looks good

Signatures consistently use domain User. Ensure downstream controllers/services updated accordingly (looks aligned in this PR).

Run to check for lingering AbstractUser references in registration layer:

Comment on lines 80 to 82
Class serviceClass = NaeReflectionUtils.resolveClass(entry.value)
ModuleService[] annotations = serviceClass.getAnnotationsByType(ModuleService.class)
if (annotations.length == 0) throw new IllegalStateException("Module Service bean must have @ModuleService annotations")
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick

Honor meta-annotations and repeatables when resolving @ModuleService

Use Spring’s AnnotatedElementUtils to merge repeatable and composed annotations on proxies.

-            Class serviceClass = NaeReflectionUtils.resolveClass(entry.value)
-            ModuleService[] annotations = serviceClass.getAnnotationsByType(ModuleService.class)
+            Class serviceClass = NaeReflectionUtils.resolveClass(entry.value)
+            def annotations = AnnotatedElementUtils.findMergedRepeatableAnnotations(serviceClass, ModuleService)

Then treat annotations as a collection:

-            if (annotations.length == 0) throw new IllegalStateException("Module Service bean must have @ModuleService annotations")
-            ModuleService annotation = annotations[0]
+            if (annotations.isEmpty()) throw new IllegalStateException("Module Service bean must have @ModuleService annotations")
+            ModuleService annotation = annotations.iterator().next()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Class serviceClass = NaeReflectionUtils.resolveClass(entry.value)
ModuleService[] annotations = serviceClass.getAnnotationsByType(ModuleService.class)
if (annotations.length == 0) throw new IllegalStateException("Module Service bean must have @ModuleService annotations")
Class serviceClass = NaeReflectionUtils.resolveClass(entry.value)
def annotations = AnnotatedElementUtils.findMergedRepeatableAnnotations(serviceClass, ModuleService)
if (annotations.isEmpty()) throw new IllegalStateException("Module Service bean must have @ModuleService annotations")
ModuleService annotation = annotations.iterator().next()
🤖 Prompt for AI Agents
In
application-engine/src/main/groovy/com/netgrif/application/engine/integration/modules/ModuleServiceInjector.groovy
around lines 80 to 82, replace the direct getAnnotationsByType usage with
Spring's AnnotatedElementUtils merged/ repeatable lookup (e.g.
AnnotatedElementUtils.findMergedRepeatableAnnotations or an equivalent
AnnotatedElementUtils call) so meta-annotations and repeatable/composed
@ModuleService annotations on proxies are honored; then treat the result as a
collection (check for empty and iterate over elements) instead of relying on a
raw array length check.

Comment on lines 196 to 201
@Override
public Case findMenuItem(String identifier, boolean retry) {
String query = String.format("processIdentifier:%s AND dataSet.%s.textValue.keyword:\"%s\"",
MenuProcessRunner.MENU_NET_IDENTIFIER, MenuItemConstants.FIELD_IDENTIFIER, identifier);
return findCase(MenuProcessRunner.MENU_NET_IDENTIFIER, query);
return findCase(QCase.case$.processIdentifier
.eq(MenuProcessRunner.MENU_NET_IDENTIFIER)
.and(QCase.case$.dataSet.get(MenuItemConstants.FIELD_IDENTIFIER).value.eq(identifier)));
}
Copy link

@coderabbitai coderabbitai bot Sep 19, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick

Unused retry parameter

The retry flag isn’t used anymore. Either remove the overload or implement a small retry/backoff if eventual consistency is still a concern.

🤖 Prompt for AI Agents
In
application-engine/src/main/java/com/netgrif/application/engine/menu/services/MenuItemService.java
around lines 196 to 201, the method signature includes an unused boolean
parameter `retry`; remove the parameter from the method signature and all
callers (and any interface/override declarations) if retry behavior is no longer
needed, or alternatively implement a simple retry loop with backoff (e.g.,
attempt findCase, catch transient exceptions or check null, sleep with
exponential backoff and retry a few times) and document the behavior; ensure
method overrides and unit tests are updated to match the chosen fix.

Copy link
Member

Choose a reason for hiding this comment

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

Will be removed in other PR.

Copy link

Choose a reason for hiding this comment

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

@renczesstefan Got it! Thanks for confirming that the unused retry parameter will be cleaned up in a future PR. That approach makes sense for keeping this PR focused on the main changes.

Comment on lines +72 to 75
Optional<User> findUserByUsername(String username, String realmName);

Page<AbstractUser> findAllUsersByQuery(Query query, String realmName, Pageable pageable);
Page<User> findAllUsersByQuery(Query query, String realmName, Pageable pageable);

Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick

Parameter naming: use realmId consistently

realmName is used here but most methods use realmId. Align to avoid confusion.

-    Page<User> findAllUsersByQuery(Query query, String realmName, Pageable pageable);
+    Page<User> findAllUsersByQuery(Query query, String realmId, Pageable pageable);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Optional<User> findUserByUsername(String username, String realmName);
Page<AbstractUser> findAllUsersByQuery(Query query, String realmName, Pageable pageable);
Page<User> findAllUsersByQuery(Query query, String realmName, Pageable pageable);
Optional<User> findUserByUsername(String username, String realmName);
Page<User> findAllUsersByQuery(Query query, String realmId, Pageable pageable);
🤖 Prompt for AI Agents
In
nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserService.java
around lines 72 to 75, the method parameters use realmName but the rest of the
codebase expects realmId; rename the parameter from realmName to realmId for
both findUserByUsername and findAllUsersByQuery, update their Javadoc/parameter
references if present, and ensure all implementing classes and callers are
updated to use the new parameter name to keep the API consistent.

Comment on lines +83 to 84
Page<User> findAllUsers(String realmName, Pageable pageable);

Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick

Parameter naming: realmName → realmId for consistency

Same rationale as above.

-    Page<User> findAllUsers(String realmName, Pageable pageable);
+    Page<User> findAllUsers(String realmId, Pageable pageable);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Page<User> findAllUsers(String realmName, Pageable pageable);
Page<User> findAllUsers(String realmId, Pageable pageable);
🤖 Prompt for AI Agents
In
nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserService.java
around lines 83 to 84, the method parameter name realmName should be renamed to
realmId for consistency; update the method signature to Page<User>
findAllUsers(String realmId, Pageable pageable) and then propagate that rename
to all implementing classes, overriding methods, callers, unit tests, and any
Javadoc or comments to use realmId instead of realmName to keep the API
consistent across the codebase.

Comment on lines +35 to 36
", type='" + type + '\'' +
'}';
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick

Avoid logging PII and sensitive changes in toString().

toString() prints email and now type. Prefer redaction or avoid using toString() in logs.

-                ", email='" + email + '\'' +
-                ", type='" + type + '\'' +
+                ", email='***'" +
+                ", type='" + type + '\'' +
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
", type='" + type + '\'' +
'}';
", email='***'" +
", type='" + type + '\'' +
'}';
🤖 Prompt for AI Agents
In
nae-user-common/src/main/java/com/netgrif/application/engine/auth/web/requestbodies/UpdateUserRequest.java
around lines 35-36, the toString() currently includes sensitive fields (email
and type); update it to avoid exposing PII by removing those fields from the
string representation or replacing them with redacted/masked placeholders (e.g.,
"[REDACTED]" or show only hashed/partial values). Ensure toString() returns
non-sensitive context (IDs or non-PII fields) only, and document why sensitive
fields are omitted.

@renczesstefan renczesstefan changed the base branch from release/7.0.0-rev8 to release/7.0.0-rev7 September 23, 2025 13:56
@renczesstefan renczesstefan changed the base branch from release/7.0.0-rev7 to release/7.0.0-rev8 September 23, 2025 13:56
Comment on lines 196 to 201
@Override
public Case findMenuItem(String identifier, boolean retry) {
String query = String.format("processIdentifier:%s AND dataSet.%s.textValue.keyword:\"%s\"",
MenuProcessRunner.MENU_NET_IDENTIFIER, MenuItemConstants.FIELD_IDENTIFIER, identifier);
return findCase(MenuProcessRunner.MENU_NET_IDENTIFIER, query);
return findCase(QCase.case$.processIdentifier
.eq(MenuProcessRunner.MENU_NET_IDENTIFIER)
.and(QCase.case$.dataSet.get(MenuItemConstants.FIELD_IDENTIFIER).value.eq(identifier)));
}
Copy link
Member

Choose a reason for hiding this comment

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

Will be removed in other PR.

renczesstefan
renczesstefan previously approved these changes Sep 30, 2025
@machacjozef machacjozef changed the base branch from release/7.0.0-rev8 to release/7.0.0-rev9 November 9, 2025 11:14
@machacjozef machacjozef dismissed renczesstefan’s stale review November 9, 2025 11:14

The base branch was changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement A change that improves on an existing feature Large new feature A change that introduces new functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants