Skip to content
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

FOUR-17569: Fix users without super admin privileges can reassign tasks #7566

Open
wants to merge 15 commits into
base: release-2024-summer
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 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
30 changes: 30 additions & 0 deletions ProcessMaker/Http/Controllers/Api/TaskController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use ProcessMaker\Http\Resources\Task as Resource;
use ProcessMaker\Http\Resources\TaskCollection;
use ProcessMaker\Listeners\HandleRedirectListener;
use ProcessMaker\Models\Group;
use ProcessMaker\Models\GroupMember;
use ProcessMaker\Models\Process;
use ProcessMaker\Models\ProcessRequest;
use ProcessMaker\Models\ProcessRequestToken;
Expand Down Expand Up @@ -330,4 +332,32 @@ public function getScreenFields(ProcessRequestToken $task)
return response()->json(['error' => 'Screen not found'], 404);
}
}

/**
* Returns a comma-separated list of user IDs that are members of the groups specified in the "groups" query parameter.
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function getAssignedUsersInGroups(Request $request)
{
$groups = $request->input('groups');
$userIds = GroupMember::whereIn('group_id', $groups)
->where('member_type', User::class)
->pluck('member_id')
->toArray();

$subGroups = GroupMember::whereIn('group_id', $groups)
->where('member_type', Group::class)
->pluck('member_id');

if ($subGroups->count()) {
$userIds = array_merge($userIds, GroupMember::whereIn('group_id', $subGroups)
->where('member_type', User::class)
->pluck('member_id')
->toArray());
}

return response()->json(implode(',', array_unique($userIds)));
}
}
12 changes: 12 additions & 0 deletions ProcessMaker/Http/Controllers/Api/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ class UserController extends Controller
* description="Comma separated list of IDs to exclude from the response",
* @OA\Schema(type="string", default=""),
* ),
* @OA\Parameter(
* name="include_ids",
* in="query",
* description="Comma separated list of IDs to exclude from the response",
* @OA\Schema(type="string", default=""),
* ),
*
* @OA\Response(
* response=200,
Expand Down Expand Up @@ -111,6 +117,12 @@ public function index(Request $request)
$query->whereNotIn('id', $exclude_ids);
}

$include_ids = $request->input('include_ids', '');
if ($include_ids) {
$include_ids = explode(',', $include_ids);
$query->whereIn('id', $include_ids);
}

if ($request->has('status')) {
$query->where('status', $request->input('status'));
}
Expand Down
43 changes: 42 additions & 1 deletion resources/views/tasks/edit.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ class="d-inline-flex pull-left align-items-center"
id='user'
v-model="selectedUser"
placeholder="{{__('Select the user to reassign to the task')}}"
api="users?status=ACTIVE"
:api="reassign()"
:multiple="false"
:show-labels="false"
:searchable="true"
Expand Down Expand Up @@ -443,6 +443,7 @@ class="multiselect__tag-icon"></i>
isPriority: false,
userHasInteracted: false,
caseTitle: "",
assignedUserIds: null
},
watch: {
task: {
Expand Down Expand Up @@ -533,6 +534,46 @@ class="multiselect__tag-icon"></i>
},
},
methods: {
reassign() {
const assignedGroups = this.task.definition.assignedGroups;
const assignedUsers = this.task.definition.assignedUsers;
// The user shouldn’t be able to reassign the task if the current user is the only one in the pool of applicable users.
if (window.ProcessMaker.user.id == assignedUsers && !assignedGroups) {
this.task.definition.allowReassignment = false;
}

// If a group is used, only the users inside the group/groups should be eligible for reassignment.
if (assignedGroups && !this.userIsAdmin) {
this.getUsersInGroups(assignedGroups);
let assignedUserIds = this.assignedUserIds;
if (assignedUsers) {
let currentAssignedUsers = assignedUsers.split(',');
assignedUserIds += ',' + currentAssignedUsers.join(',');
}
return 'users?include_ids=' + assignedUserIds + '&status=ACTIVE';

}

// Reassignment should only be available to users in the set pool of users
if (assignedUsers && !this.userIsAdmin) {
let currentAssignedUsers = this.task.definition.assignedUsers.split(',');
let assignedUsers = currentAssignedUsers.filter(user => user !== window.ProcessMaker.user.id);
return 'users?include_ids=' + assignedUsers + '&status=ACTIVE';
} else {
// If no group or users are used, all users should be eligible for reassignment.
return "users?status=ACTIVE";
}
},
getUsersInGroups(assignedGroups) {
let groups = assignedGroups.split(',');
ProcessMaker.apiClient.get("tasks/getAssignedUsersInGroups", {
params: {
groups: groups
}
}).then(response => {
this.assignedUserIds = response.data;
});
},
createRule() {
window.location.href = '/tasks/rules/new?' +
`task_id=${this.task.id}&` +
Expand Down
1 change: 1 addition & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
Route::post('tasks/{task}/rollback', [TaskController::class, 'rollbackTask'])->name('tasks.rollback_task')->middleware('can:rollback,task');
Route::post('tasks/{task}/setViewed', [TaskController::class, 'setViewed'])->name('tasks.set_viewed')->middleware('can:viewScreen,task,screen');
Route::put('tasks/{task}/setPriority', [TaskController::class, 'setPriority'])->name('tasks.priority');
Route::get('tasks/getAssignedUsersInGroups', [TaskController::class, 'getAssignedUsersInGroups'])->name('tasks.getAssignedUsersInGroups');

// TaskDrafts
Route::put('drafts/{task}', [TaskDraftController::class, 'update'])->name('taskdraft.update');
Expand Down
Loading
Loading