Skip to content

Commit 30d8705

Browse files
authored
Merge pull request #8633 from ProcessMaker/FOUR-28214
FOUR-28214 Fix Form data is being parsed into URL when trying to reassign task
2 parents 77303cc + 7ffc98d commit 30d8705

File tree

4 files changed

+135
-7
lines changed

4 files changed

+135
-7
lines changed

ProcessMaker/Http/Controllers/Api/UserController.php

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,55 @@ public function index(Request $request)
183183
* ),
184184
* ),
185185
* )
186+
*
187+
* @OA\Post(
188+
* path="/users_task_count",
189+
* summary="Returns all users and their total tasks (POST version for large form_data)",
190+
* operationId="postUsersTaskCount",
191+
* tags={"Users"},
192+
* @OA\RequestBody(
193+
* description="Request body for filtering users",
194+
* @OA\JsonContent(
195+
* @OA\Property(
196+
* property="filter",
197+
* type="string",
198+
* description="Filter results by string. Searches First Name, Last Name, Email, or Username."
199+
* ),
200+
* @OA\Property(
201+
* property="include_ids",
202+
* type="string",
203+
* description="Comma separated list of user IDs to include in the response. Eg. 1,2,3"
204+
* ),
205+
* @OA\Property(
206+
* property="assignable_for_task_id",
207+
* type="integer",
208+
* description="Task ID to get assignable users for"
209+
* ),
210+
* @OA\Property(
211+
* property="form_data",
212+
* type="object",
213+
* description="Form data used to evaluate rule expressions for task assignment"
214+
* ),
215+
* ),
216+
* ),
217+
* @OA\Response(
218+
* response=200,
219+
* description="List of users with task counts",
220+
* @OA\JsonContent(
221+
* type="object",
222+
* @OA\Property(
223+
* property="data",
224+
* type="array",
225+
* @OA\Items(ref="#/components/schemas/users"),
226+
* ),
227+
* @OA\Property(
228+
* property="meta",
229+
* type="object",
230+
* ref="#/components/schemas/metadata",
231+
* ),
232+
* ),
233+
* ),
234+
* )
186235
*/
187236
public function getUsersTaskCount(Request $request)
188237
{
@@ -223,7 +272,8 @@ public function getUsersTaskCount(Request $request)
223272
->withCount('activeTasks')
224273
->orderBy(
225274
$request->input('order_by', 'username'),
226-
$request->input('order_direction', 'ASC'))
275+
$request->input('order_direction', 'ASC')
276+
)
227277
->paginate(50);
228278

229279
return new ApiCollection($response);
@@ -359,8 +409,8 @@ public function getPinnnedControls(User $user)
359409
$meta = $user->meta ? (array) $user->meta : [];
360410

361411
return array_key_exists('pinnedControls', $meta)
362-
? $meta['pinnedControls']
363-
: [];
412+
? $meta['pinnedControls']
413+
: [];
364414
}
365415

366416
/**
@@ -774,10 +824,12 @@ private function uploadAvatar(User $user, Request $request)
774824
// Validate image content
775825
if ($type === 'svg') {
776826
// For SVG files, validate against XSS
777-
if (preg_match('/<script/i', $data) ||
827+
if (
828+
preg_match('/<script/i', $data) ||
778829
preg_match('/on\w+\s*=/i', $data) ||
779830
preg_match('/javascript:/i', $data) ||
780-
preg_match('/data:/i', $data)) {
831+
preg_match('/data:/i', $data)
832+
) {
781833
throw new \Exception('SVG contains potentially malicious content');
782834
}
783835
} else {
@@ -853,7 +905,7 @@ public function restore(Request $request)
853905
// Otherwise, search trashed users
854906
// for the user to restore
855907
$user = User::onlyTrashed()->where($input, $request->input($input))
856-
->first();
908+
->first();
857909
}
858910

859911
if ($user instanceof User) {

resources/js/common/reassignMixin.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export default {
3737
}
3838
}
3939

40-
ProcessMaker.apiClient.get('users_task_count', { params }).then(response => {
40+
ProcessMaker.apiClient.post('users_task_count', { params }).then(response => {
4141
this.reassignUsers = [];
4242
response.data.data.forEach((user) => {
4343
this.reassignUsers.push({

routes/api.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@
6262
Route::put('users/update_language', [UserController::class, 'updateLanguage'])->name('users.updateLanguage');
6363
Route::get('users_task_count', [UserController::class, 'getUsersTaskCount'])->name('users.users_task_count')
6464
->middleware('can:view-users');
65+
Route::post('users_task_count', [UserController::class, 'getUsersTaskCount'])->name('users.users_task_count_post')
66+
->middleware('can:view-users');
6567

6668
// User Groups
6769
Route::put('users/{user}/groups', [UserController::class, 'updateGroups'])->name('users.groups.update')->middleware('can:edit-users');

tests/Feature/Api/UsersTest.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,80 @@ public function testGetUsersTaskCount()
933933
$this->assertContains($admin->id, collect($users)->pluck('id')->toArray());
934934
}
935935

936+
public function testPostUsersTaskCount()
937+
{
938+
$admin = $this->user;
939+
$user = User::factory()->create();
940+
$groupUser = User::factory()->create();
941+
$group = Group::factory()->create();
942+
GroupMember::factory()->create([
943+
'group_id' => $group->id,
944+
'member_id' => $groupUser->id,
945+
'member_type' => User::class,
946+
]);
947+
948+
$process = Process::factory()->create([
949+
'user_id' => $admin->id,
950+
'manager_id' => $admin->id,
951+
]);
952+
953+
$bpmn = file_get_contents(__DIR__ . '/../../Fixtures/task_with_user_group_assignment.bpmn');
954+
$bpmn = str_replace([
955+
'[assigned-users]',
956+
'[assigned-groups]',
957+
], [
958+
$user->id,
959+
$group->id,
960+
], $bpmn);
961+
962+
$process->bpmn = $bpmn;
963+
$process->save();
964+
965+
$request = ProcessRequest::factory()->create([
966+
'process_id' => $process->id,
967+
'user_id' => $admin->id,
968+
]);
969+
970+
$tasks = ProcessRequestToken::factory(3)->create([
971+
'process_id' => $process->id,
972+
'process_request_id' => $request->id,
973+
'element_id' => 'node_2',
974+
'user_id' => $user->id,
975+
'status' => 'ACTIVE',
976+
]);
977+
978+
// Test POST endpoint with form_data in request body
979+
$result = $this->apiCall('POST', route('api.users.users_task_count_post'), [
980+
'assignable_for_task_id' => $tasks[0]->id,
981+
'form_data' => [
982+
'some_field' => 'some_value',
983+
],
984+
]);
985+
986+
$users = $result->json()['data'];
987+
988+
// Assert only the $user and $groupUser are in the list
989+
$this->assertContains($user->id, array_column($users, 'id'));
990+
$this->assertContains($groupUser->id, array_column($users, 'id'));
991+
992+
// Assert the $user has 3 active tasks
993+
$tokenCount = collect($users)->first(fn ($r) => $r['id'] === $user->id)['active_tasks_count'];
994+
$this->assertEquals(3, $tokenCount);
995+
996+
// Test POST endpoint without assignable_for_task_id
997+
$result = $this->apiCall('POST', route('api.users.users_task_count_post'));
998+
$users = $result->json()['data'];
999+
1000+
// Assert the list of users now contains the admin user
1001+
$this->assertContains($admin->id, collect($users)->pluck('id')->toArray());
1002+
1003+
// Test POST endpoint with filter in request body
1004+
$result = $this->apiCall('POST', route('api.users.users_task_count_post'), [
1005+
'filter' => $user->firstname,
1006+
]);
1007+
$result->assertStatus(200);
1008+
}
1009+
9361010
/**
9371011
* Test save and get filters per user saved in cache
9381012
*/

0 commit comments

Comments
 (0)