Skip to content

[NAE-2072] Workspaces #309

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: release/7.0.0-rev2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.netgrif.application.engine;

import com.netgrif.application.engine.auth.config.WorkspaceContextHolder;
import com.netgrif.application.engine.auth.service.UserService;
import groovy.lang.Closure;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class AsyncRunnerWrapper {
private final AsyncRunner async;
private final UserService userService;

public void run(Closure closure) {
run(closure, userService.getLoggedOrSystem().getWorkspaceId());
}

public void run(Closure closure, String workspaceId) {
WorkspaceContextHolder.setWorkspaceId(workspaceId, true);
async.run(closure);
}
Comment on lines +19 to +22
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add workspace context cleanup for async operations.

The workspace context is set but never cleared after the async operation completes. This could lead to context leaking between different async operations.

Consider wrapping the closure execution to ensure cleanup:

 public void run(Closure closure, String workspaceId) {
     WorkspaceContextHolder.setWorkspaceId(workspaceId, true);
-    async.run(closure);
+    async.run(() -> {
+        try {
+            closure.call();
+        } finally {
+            WorkspaceContextHolder.clear();
+        }
+    });
 }
📝 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
public void run(Closure closure, String workspaceId) {
WorkspaceContextHolder.setWorkspaceId(workspaceId, true);
async.run(closure);
}
public void run(Closure closure, String workspaceId) {
WorkspaceContextHolder.setWorkspaceId(workspaceId, true);
async.run(() -> {
try {
closure.call();
} finally {
WorkspaceContextHolder.clear();
}
});
}
🤖 Prompt for AI Agents
In
application-engine/src/main/groovy/com/netgrif/application/engine/AsyncRunnerWrapper.java
around lines 19 to 22, the workspace context is set before running the async
closure but not cleared afterward, risking context leakage. To fix this, wrap
the closure execution with a try-finally block or equivalent so that after the
async.run(closure) call completes, WorkspaceContextHolder.clear() or the
appropriate cleanup method is called to remove the workspace context.


public void execute(final Runnable runnable) {
execute(runnable, userService.getLoggedOrSystem().getWorkspaceId());
}
Comment on lines +24 to +26
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add null safety check for workspace ID in execute method.

Similar to the run method, validate the workspace ID is not null.

Apply the same validation pattern:

 public void execute(final Runnable runnable) {
-    execute(runnable, userService.getLoggedOrSystem().getWorkspaceId());
+    String workspaceId = userService.getLoggedOrSystem().getWorkspaceId();
+    if (workspaceId == null) {
+        throw new IllegalStateException("Workspace ID cannot be null for async operations");
+    }
+    execute(runnable, workspaceId);
 }
📝 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
public void execute(final Runnable runnable) {
execute(runnable, userService.getLoggedOrSystem().getWorkspaceId());
}
public void execute(final Runnable runnable) {
String workspaceId = userService.getLoggedOrSystem().getWorkspaceId();
if (workspaceId == null) {
throw new IllegalStateException("Workspace ID cannot be null for async operations");
}
execute(runnable, workspaceId);
}
🤖 Prompt for AI Agents
In
application-engine/src/main/groovy/com/netgrif/application/engine/AsyncRunnerWrapper.java
around lines 24 to 26, the execute method calls another execute method with a
workspace ID without checking if the workspace ID is null. Add a null check for
the workspace ID similar to the run method by retrieving the workspace ID first,
validating it is not null, and then passing it to the execute method. If the
workspace ID is null, handle it appropriately to avoid potential
NullPointerExceptions.


public void execute(final Runnable runnable, String workspaceId) {
WorkspaceContextHolder.setWorkspaceId(workspaceId, true);
async.execute(runnable);
}
Comment on lines +28 to +31
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add workspace context cleanup for async Runnable execution.

Similar to the Closure execution, the Runnable execution should also clean up the workspace context.

Apply this pattern for consistency:

 public void execute(final Runnable runnable, String workspaceId) {
     WorkspaceContextHolder.setWorkspaceId(workspaceId, true);
-    async.execute(runnable);
+    async.execute(() -> {
+        try {
+            runnable.run();
+        } finally {
+            WorkspaceContextHolder.clear();
+        }
+    });
 }
📝 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
public void execute(final Runnable runnable, String workspaceId) {
WorkspaceContextHolder.setWorkspaceId(workspaceId, true);
async.execute(runnable);
}
public void execute(final Runnable runnable, String workspaceId) {
WorkspaceContextHolder.setWorkspaceId(workspaceId, true);
async.execute(() -> {
try {
runnable.run();
} finally {
WorkspaceContextHolder.clear();
}
});
}
🤖 Prompt for AI Agents
In
application-engine/src/main/groovy/com/netgrif/application/engine/AsyncRunnerWrapper.java
around lines 28 to 31, the execute method sets the workspace context but does
not clear it after running the async Runnable. Modify the method to wrap the
async.execute call in a try-finally block, setting the workspace context before
execution and clearing it in the finally block to ensure proper cleanup and
consistency with the Closure execution pattern.

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.netgrif.application.engine

import com.netgrif.application.engine.objects.auth.domain.LoggedUser
import com.netgrif.application.engine.objects.importer.model.Document
import com.netgrif.application.engine.petrinet.domain.repositories.PetriNetRepository
import com.netgrif.application.engine.workflow.domain.repositories.CaseRepository
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Profile
import org.springframework.security.core.Authentication
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
Expand All @@ -33,15 +35,17 @@ class DevConsole {
private PetriNetRepository netRepository

@GetMapping(value = "/dataset/{title}", produces = APPLICATION_JSON_VALUE)
String dataset(@PathVariable String title) {
def useCase = caseRepository.findAll().find { it.title == title }
String dataset(@PathVariable String title, Authentication auth) {
LoggedUser loggedUser = (LoggedUser) auth.getPrincipal();
def useCase = caseRepository.findAllByWorkspaceId(loggedUser.getWorkspaceId()).find { it.title == title }
return "{ ${useCase?.dataSet?.collect { "\"${useCase?.petriNet?.dataSet?.get(it?.key)?.importId}:${useCase?.petriNet?.dataSet?.get(it?.key)?.name?.toString()?.replaceAll("\n[ ]{2}", "")}\":\"${it?.value?.value as String}\"" }?.join(", ")} }"
}

@GetMapping(value = "/net/{title}", produces = APPLICATION_XML_VALUE)
String netSnapshot(@PathVariable String title) {
String netSnapshot(@PathVariable String title, Authentication auth) {
try {
def useCase = caseRepository.findAll().find { it.title == title }
LoggedUser loggedUser = (LoggedUser) auth.getPrincipal();
def useCase = caseRepository.findAllByWorkspaceId(loggedUser.getWorkspaceId()).find { it.title == title }
def net = useCase.petriNet
def xml = new File(net.importXmlPath)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class ActionMigration {

void migrateActions(String petriNetPath) {
InputStream netStream = new ClassPathResource(petriNetPath).inputStream
ImportPetriNetEventOutcome newPetriNet = petriNetService.importPetriNet(netStream, VersionType.MAJOR, userService.transformToLoggedUser(userService.getLoggedOrSystem()))
ImportPetriNetEventOutcome newPetriNet = petriNetService.importPetriNet(netStream, VersionType.MAJOR, userService.transformToLoggedUser(userService.getLoggedOrSystem()), userService.getLoggedOrSystem().getWorkspaceId())
List<PetriNet> oldPetriNets

if(newPetriNet.getNet() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.netgrif.application.engine.petrinet.domain.dataset.logic.action


import com.netgrif.application.engine.AsyncRunner
import com.netgrif.application.engine.AsyncRunnerWrapper
import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService
import com.netgrif.application.engine.adapter.spring.workflow.domain.QCase
import com.netgrif.application.engine.adapter.spring.workflow.domain.QTask
Expand Down Expand Up @@ -61,6 +62,7 @@ import com.netgrif.application.engine.workflow.service.TaskService
import com.netgrif.application.engine.workflow.service.interfaces.*
import com.netgrif.application.engine.workflow.web.responsebodies.MessageResource
import com.netgrif.application.engine.workflow.web.responsebodies.TaskReference
import com.querydsl.core.BooleanBuilder
import com.querydsl.core.types.Predicate
import groovy.transform.NamedVariant
import org.bson.types.ObjectId
Expand Down Expand Up @@ -120,7 +122,7 @@ class ActionDelegate {
IPetriNetService petriNetService

@Autowired
AsyncRunner async
AsyncRunnerWrapper async

@Autowired
IPdfGenerator pdfGenerator
Expand Down Expand Up @@ -1983,9 +1985,9 @@ class ActionDelegate {
* @return
*/
def deleteMenuItem(Case item) {
async.run {
async.run({
workflowService.deleteCase(item.stringId)
}
}, item.getWorkspaceId());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.netgrif.application.engine.petrinet.domain.dataset.logic.action

import com.netgrif.application.engine.auth.config.WorkspaceContextHolder
import com.netgrif.application.engine.business.IPostalCodeService
import com.netgrif.application.engine.business.orsr.IOrsrService
import com.netgrif.application.engine.importer.service.FieldFactory
Expand Down Expand Up @@ -43,11 +44,11 @@ abstract class FieldActionsRunner {

private Map<String, Object> actionsCache = new HashMap<>()

List<EventOutcome> run(com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action action, Case useCase, Map<String, String> params, List<Function> functions = []) {
return run(action, useCase, Optional.empty(), params, functions)
List<EventOutcome> run(com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action action, Case useCase, Map<String, String> params, String workspaceId, List<Function> functions = []) {
return run(action, useCase, Optional.empty(), params, workspaceId, functions)
}

List<EventOutcome> run(com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action action, Case useCase, Optional<Task> task, Map<String, String> params, List<Function> functions = []) {
List<EventOutcome> run(com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action action, Case useCase, Optional<Task> task, Map<String, String> params, String workspaceId, List<Function> functions = []) {
if (!actionsCache)
actionsCache = new HashMap<>()

Expand All @@ -56,6 +57,7 @@ abstract class FieldActionsRunner {
final ActionStartEvent actionStart = new ActionStartEvent(action)
try {
publisher.publishEvent(actionStart)
WorkspaceContextHolder.setWorkspaceId(useCase != null ? useCase.getWorkspaceId() : workspaceId, true);
code.init(action, useCase, task, this, params)
code()
publisher.publishEvent(new ActionStopEvent(action, actionStart, true))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.netgrif.application.engine.petrinet.domain.dataset.logic.action.runner

import com.netgrif.application.engine.auth.config.WorkspaceContextHolder
import com.netgrif.application.engine.event.IGroovyShellFactory
import com.netgrif.application.engine.elastic.service.executors.MaxSizeHashMap
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate
Expand Down Expand Up @@ -42,6 +43,7 @@ abstract class CaseFieldsExpressionRunner {
logger().debug("Expression: $expression")
def code = getExpressionCode(expression)
try {
WorkspaceContextHolder.setWorkspaceId(useCase.getWorkspaceId(), true);
initCode(code.delegate, useCase, fields, params)
code()
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package com.netgrif.application.engine.petrinet.domain.dataset.logic.action.runner


import com.netgrif.application.engine.auth.config.WorkspaceContextHolder
import com.netgrif.application.engine.event.IGroovyShellFactory
import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.context.RoleContext
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.delegate.RoleActionDelegate
import org.codehaus.groovy.control.CompilerConfiguration
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
Expand Down Expand Up @@ -34,6 +33,7 @@ abstract class RoleActionsRunner {
log.debug("Action: $action")
def code = getActionCode(action)
try {
WorkspaceContextHolder.setWorkspaceId(roleContext.petriNet.getWorkspaceId(), true);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure workspace context cleanup after action execution.

The workspace context is properly set before action execution, but there's no visible cleanup mechanism. Consider wrapping the action execution in a try-finally block to ensure the workspace context is cleared.

try {
    WorkspaceContextHolder.setWorkspaceId(roleContext.petriNet.getWorkspaceId(), true);
    code.init(action, roleContext, params)
    code()
+} finally {
+    WorkspaceContextHolder.clear()
}

Also verify the true parameter usage - ensure this aligns with the intended workspace context behavior across the application.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
application-engine/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/runner/RoleActionsRunner.groovy
at line 36, the workspace context is set but not cleared after action execution.
Wrap the action execution code in a try-finally block where you set the
workspace context before the try, execute the action inside the try, and clear
the workspace context in the finally block to ensure cleanup. Also, review the
usage of the 'true' parameter in setWorkspaceId to confirm it matches the
intended behavior for workspace context handling in the application.

code.init(action, roleContext, params)
code()
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import com.netgrif.application.engine.petrinet.domain.repositories.PetriNetRepos
import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService
import com.netgrif.application.engine.petrinet.service.interfaces.IUriService
import com.netgrif.application.engine.startup.runner.SuperCreatorRunner
import com.netgrif.application.engine.workflow.domain.repositories.CaseRepository
import com.netgrif.application.engine.workflow.service.interfaces.IDataService
import com.netgrif.application.engine.workflow.service.interfaces.ITaskService
import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService
Expand Down Expand Up @@ -52,15 +51,9 @@ class ImportHelper {

private static final Logger log = LoggerFactory.getLogger(ImportHelper.class.name)

@Autowired
private PetriNetRepository petriNetRepository

@Autowired
private UserService userService

@Autowired
private CaseRepository caseRepository

@Autowired
private AuthorityService authorityService

Expand Down Expand Up @@ -119,7 +112,11 @@ class ImportHelper {

Optional<PetriNet> createNet(String fileName, VersionType release = VersionType.MAJOR, LoggedUser author = userService.transformToLoggedUser(userService.getSystem()), String uriNodeId = uriService.getDefault().stringId) {
InputStream netStream = new ClassPathResource("petriNets/$fileName" as String).inputStream
PetriNet petriNet = petriNetService.importPetriNet(netStream, release, author, uriNodeId).getNet()
return createNet(netStream, release, author, uriNodeId)
}

Optional<PetriNet> createNet(InputStream netStream, VersionType release = VersionType.MAJOR, LoggedUser author = userService.transformToLoggedUser(userService.getSystem()), String uriNodeId = uriService.getDefault().stringId) {
PetriNet petriNet = petriNetService.importPetriNet(netStream, release, author, uriNodeId, author.getWorkspaceId()).getNet()
log.info("Imported '${petriNet?.title?.defaultValue}' ['${petriNet?.identifier}', ${petriNet?.stringId}]")
return Optional.of(petriNet)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import com.netgrif.application.engine.configuration.properties.ServerAuthProperties;
import com.netgrif.application.engine.auth.service.GroupService;
import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
import com.netgrif.application.engine.objects.petrinet.domain.workspace.DefaultWorkspaceService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -45,6 +47,8 @@ public class RegistrationService implements IRegistrationService {
private ServerAuthProperties serverAuthProperties;
@Autowired
private ProcessRoleService processRoleService;
@Autowired
private DefaultWorkspaceService defaultWorkspaceService;

@Override
@Transactional
Expand Down Expand Up @@ -132,7 +136,12 @@ public User createNewUser(NewUserRequest newUser) {
if (newUser.processRoles != null && !newUser.processRoles.isEmpty()) {
user.setProcessRoles(new HashSet<>(processRole.findByIds(newUser.processRoles)));
}
userService.addRole(user, processRoleService.getDefaultRole().getStringId());
Set<ProcessRole> roles = user.getProcessRoles();
defaultWorkspaceService.getAllWorkspaces().forEach(workspace ->
roles.add(processRoleService.defaultRole(workspace.getId()))
);
user.setProcessRoles(roles);

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

if (newUser.groups != null && !newUser.groups.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public UserResource getResource(LoggedUser loggedUser, Locale locale, boolean sm
User result = loggedUser.isImpersonating() ?
getLocalisedUser(user, getImpersonated(loggedUser, small), locale) :
getLocalisedUser(user, locale);
result.setWorkspaceId(loggedUser.getWorkspaceId());
return new UserResource(result, "profile");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@
import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService;
import com.netgrif.application.engine.auth.service.*;
import com.netgrif.application.engine.auth.web.requestbodies.PreferencesRequest;
import com.netgrif.application.engine.auth.web.requestbodies.UpdateUserRequest;
import com.netgrif.application.engine.auth.web.requestbodies.UserCreateRequest;
import com.netgrif.application.engine.auth.web.responsebodies.*;
import com.netgrif.application.engine.configuration.properties.ServerAuthProperties;
import com.netgrif.application.engine.objects.petrinet.domain.workspace.DefaultWorkspaceService;
import com.netgrif.application.engine.objects.petrinet.domain.workspace.Workspace;
import com.netgrif.application.engine.security.service.ISecurityContextService;
import com.netgrif.application.engine.workflow.web.responsebodies.MessageResource;
import com.netgrif.application.engine.workflow.web.responsebodies.ResourceLinkAssembler;
import com.netgrif.application.engine.auth.web.requestbodies.UserSearchRequestBody;
import com.netgrif.application.engine.auth.web.responsebodies.PreferencesResource;
import com.netgrif.application.engine.auth.web.responsebodies.User;
Expand All @@ -25,6 +33,7 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -53,6 +62,9 @@ public class UserController {
private final PreferencesService preferencesService;
private final AuthorityService authorityService;
private final RealmService realmService;
private final DefaultWorkspaceService workspaceService;
private final ServerAuthProperties serverAuthProperties;
private final ISecurityContextService securityContextService;
private final UserFactory userFactory;

@Operation(summary = "Create a new user", description = "Creates a new user in the realm specified by id.")
Expand Down Expand Up @@ -167,37 +179,17 @@ public ResponseEntity<User> getUser(@PathVariable("realmId") String realmId, @Pa
} catch (IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
user.setWorkspaceId(actualUser.getWorkspaceId());
return ResponseEntity.ok(userFactory.getUser(user, locale));
}

// todo step 2, only used in test on frontend
// @Operation(summary = "Update user", security = {@SecurityRequirement(name = "X-Auth-Token")})
// @PostMapping(value = "/update", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
// public ResponseEntity<User> updateUser(@RequestBody UpdateUserRequest updates, Authentication auth, Locale locale) {
@Operation(summary = "Get all workspaces", security = {@SecurityRequirement(name = "BasicAuth")})
@GetMapping(value = "/workspaces", produces = MediaTypes.HAL_JSON_VALUE)
public List<WorkspaceResponse> getAllWorkspaces() {
List<Workspace> workspaces = workspaceService.getAllWorkspaces();

/// / todo should this be kept? not relevant anymore?
// if (!serverAuthProperties.isEnableProfileEdit()) {
// return null;
// }
// LoggedUser loggedUser = (LoggedUser) auth.getPrincipal();
// String userId = updates.getStringId();
// IUser user;
// try {
// user = userService.findById(userId, updatedUser.getRealmId());
// } catch (IllegalArgumentException e) {
// log.error("Could not find user with id [{}]", userId, e);
// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
// }
// user = userService.update(user, updates.getUpdatedUser());
// securityContextService.saveToken(userId);
// if (Objects.equals(loggedUser.getId(), userId)) {
// loggedUser.setFirstName(user.getFirstName());
// loggedUser.setLastName(user.getLastName());
// securityContextService.reloadSecurityContext(loggedUser);
// }
// log.info("Updating user " + user.getEmail() + " with data " + updatedUser);
// return ResponseEntity.ok(User.createUser(user));
// }
return workspaces.stream().map(w -> new WorkspaceResponse(w.getId(), w.isDefaultWorkspace())).collect(Collectors.toList());
}
Comment on lines +186 to +192
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add security authorization to the getAllWorkspaces endpoint.

The new getAllWorkspaces endpoint lacks authorization annotations. Consider whether this endpoint should be restricted to authenticated users or specific roles, especially since it exposes workspace information.

+@PreAuthorize("isAuthenticated()")
@Operation(summary = "Get all workspaces", security = {@SecurityRequirement(name = "BasicAuth")})
@GetMapping(value = "/workspaces", produces = MediaTypes.HAL_JSON_VALUE)
public List<WorkspaceResponse> getAllWorkspaces() {

Or if admin access is required:

+@PreAuthorize("@authorizationService.hasAuthority('ADMIN')")
@Operation(summary = "Get all workspaces", security = {@SecurityRequirement(name = "BasicAuth")})
@GetMapping(value = "/workspaces", produces = MediaTypes.HAL_JSON_VALUE)
public List<WorkspaceResponse> getAllWorkspaces() {
🤖 Prompt for AI Agents
In
application-engine/src/main/java/com/netgrif/application/engine/auth/web/UserController.java
around lines 186 to 192, the getAllWorkspaces endpoint lacks security
authorization annotations. Add appropriate security annotations such as
@PreAuthorize or @RolesAllowed to restrict access to authenticated users or
specific roles like admin. This will ensure that only authorized users can
access workspace information.


// todo not used on front, is it needed?
// @Operation(summary = "Get all users with specified roles", security = {@SecurityRequirement(name = "X-Auth-Token")})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class UpdateUserRequest implements IUser, Serializable {

public String surname;

public String workspaceId;

public UpdateUserRequest() {
}

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Loading
Loading