-
Notifications
You must be signed in to change notification settings - Fork 6
[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
base: release/7.0.0-rev2
Are you sure you want to change the base?
Changes from all commits
7f9fa9f
1ae3c85
bb4ad49
8c991c7
7893e76
36c5317
6b2e765
e85f26d
b1a5893
9a5ffc3
13f747b
a7d93d7
cf83cf8
487ac13
d4fcced
7d938e0
8c4f3a3
3d90c24
89b014c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
public void execute(final Runnable runnable) { | ||||||||||||||||||||||||||||||
execute(runnable, userService.getLoggedOrSystem().getWorkspaceId()); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
Comment on lines
+24
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
public void execute(final Runnable runnable, String workspaceId) { | ||||||||||||||||||||||||||||||
WorkspaceContextHolder.setWorkspaceId(workspaceId, true); | ||||||||||||||||||||||||||||||
async.execute(runnable); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
Comment on lines
+28
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||
} |
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 | ||
|
@@ -34,6 +33,7 @@ abstract class RoleActionsRunner { | |
log.debug("Action: $action") | ||
def code = getActionCode(action) | ||
try { | ||
WorkspaceContextHolder.setWorkspaceId(roleContext.petriNet.getWorkspaceId(), true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
🤖 Prompt for AI Agents
|
||
code.init(action, roleContext, params) | ||
code() | ||
} catch (Exception e) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -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.") | ||
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add security authorization to the getAllWorkspaces endpoint. The new +@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
|
||
|
||
// todo not used on front, is it needed? | ||
// @Operation(summary = "Get all users with specified roles", security = {@SecurityRequirement(name = "X-Auth-Token")}) | ||
|
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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:
📝 Committable suggestion
🤖 Prompt for AI Agents