Skip to content

Commit 7f765a6

Browse files
committed
Correctly handle files in drafts
1 parent be46b92 commit 7f765a6

9 files changed

Lines changed: 194 additions & 33 deletions

File tree

‎ProcessMaker/Http/Controllers/Api/FileController.php‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use ProcessMaker\Http\Resources\ApiCollection;
1111
use ProcessMaker\Http\Resources\ApiResource;
1212
use ProcessMaker\Models\Media;
13+
use ProcessMaker\Models\ProcessRequest;
14+
use ProcessMaker\Models\TaskDraft;
1315
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
1416

1517
class FileController extends Controller
@@ -86,7 +88,7 @@ public function index(Request $request)
8688
/**
8789
* Store a newly created resource in storage.
8890
*
89-
* @param \Illuminate\Http\Request $request
91+
* @param Request $request
9092
* @return \Illuminate\Http\Response
9193
*
9294
* @OA\Post(
@@ -292,7 +294,7 @@ public function download(Media $file)
292294
/**
293295
* Update the specified resource in storage.
294296
*
295-
* @param \Illuminate\Http\Request $request
297+
* @param Request $request
296298
* @param Media $file
297299
*
298300
* @return \Illuminate\Http\Response
@@ -342,6 +344,22 @@ public function destroy(Media $file)
342344
$modelId = $file->model_id;
343345
$model = $modelType::find($modelId);
344346

347+
$taskId = (int) request()->input('task_id', 0);
348+
if ($taskId && $modelType === ProcessRequest::class) {
349+
// We are deleting a file from the request, however, we
350+
// need need to preserve it because this is a draft.
351+
$draft = TaskDraft::firstOrCreate(['task_id' => $taskId], ['data' => []]);
352+
$data = $draft->data;
353+
if (!isset($data['__deleted_files'])) {
354+
$data['__deleted_files'] = [];
355+
}
356+
$data['__deleted_files'][] = $file->id;
357+
$draft->data = $data;
358+
$draft->saveOrFail();
359+
360+
return response([], 204);
361+
}
362+
345363
$model->deleteMedia($file->id);
346364

347365
// Register the Event

‎ProcessMaker/Http/Controllers/Api/ProcessRequestFileController.php‎

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use ProcessMaker\Http\Resources\ApiResource;
2424
use ProcessMaker\Models\Media;
2525
use ProcessMaker\Models\ProcessRequest;
26+
use ProcessMaker\Models\TaskDraft;
2627

2728
class ProcessRequestFileController extends Controller
2829
{
@@ -85,18 +86,25 @@ class ProcessRequestFileController extends Controller
8586
*/
8687
public function index(Request $laravel_request, ProcessRequest $request)
8788
{
88-
$media = \ProcessMaker\Models\Media::getFilesRequest($request);
89-
9089
//Retrieve input filter variables
9190
$name = $laravel_request->get('name');
9291
$id = $laravel_request->get('id');
9392
$filter = $name ? $name : $id;
9493

94+
$media = Media::getFilesRequest($request, $id);
95+
9596
// Register the Event
9697
if (!empty($filter)) {
9798
FilesAccessed::dispatch($filter, $request);
9899
}
99100

101+
if ($id && $media) {
102+
// We retrieved a single item by ID, so no need to filter.
103+
// Just return a collection with one item.
104+
$media = [$media];
105+
$filter = false;
106+
}
107+
100108
// If no filter, return entire collection; otherwise, filter collection
101109
if (!$filter) {
102110
return new ResourceCollection($media);
@@ -123,7 +131,7 @@ public function index(Request $laravel_request, ProcessRequest $request)
123131
* Display the specified resource.
124132
*
125133
* @param Media $file
126-
* @return \Illuminate\Http\Response
134+
* @return Response
127135
*
128136
* @OA\Get(
129137
* path="/requests/{request_id}/files/{file_id}",
@@ -208,8 +216,8 @@ protected function chunk(FileReceiver $receiver, ProcessRequest $request, Reques
208216
/**
209217
* Store a newly created resource in storage.
210218
*
211-
* @param \Illuminate\Http\Request $request
212-
* @return \Illuminate\Http\Response
219+
* @param Request $request
220+
* @return Response
213221
*
214222
* @OA\Post(
215223
* path="/requests/{request_id}/files",
@@ -294,8 +302,15 @@ private function saveUploadedFile(UploadedFile $file, ProcessRequest $processReq
294302
$rowId = $laravelRequest->input('row_id', null);
295303
$parent = (int) $laravelRequest->input('parent', null);
296304
$multiple = $laravelRequest->input('multiple', null);
305+
$taskId = (int) $laravelRequest->input('task_id', 0);
297306

298-
foreach ($parentRequest->getMedia() as $mediaItem) {
307+
$model = $parentRequest;
308+
if ($taskId) {
309+
// The draft may not exist yet. Create it now if it doesn't exist.
310+
$model = TaskDraft::firstOrCreate(['task_id' => $taskId], ['data' => []]);
311+
}
312+
313+
foreach ($model->getMedia() as $mediaItem) {
299314
if (
300315
$mediaItem->getCustomProperty('data_name') == $data_name &&
301316
$mediaItem->getCustomProperty('parent') == $parent &&
@@ -309,7 +324,7 @@ private function saveUploadedFile(UploadedFile $file, ProcessRequest $processReq
309324
}
310325

311326
// save the file and return any response you need
312-
$media = $parentRequest
327+
$media = $model
313328
->addMedia($file)
314329
->withCustomProperties([
315330
'data_name' => $data_name,
@@ -319,6 +334,21 @@ private function saveUploadedFile(UploadedFile $file, ProcessRequest $processReq
319334
])
320335
->toMediaCollection();
321336

337+
if ($taskId) {
338+
// Model is a TaskDraft. Save the new file ID in the draft's data.
339+
$data = $model->data;
340+
$data[$data_name] = $media->id;
341+
$model->data = $data;
342+
$model->saveOrFail();
343+
344+
// Set the process request the file should belong to after saving.
345+
// Note that this is the $parentRequest and may be different than
346+
// the task->processRequest.
347+
$media->setCustomProperty('parent_process_request_id', $parentRequest->id);
348+
$media->setCustomProperty('is_multiple', (bool) $multiple);
349+
$media->saveOrFail();
350+
}
351+
322352
// Register the Event
323353
FilesCreated::dispatch($media->id, $processRequest);
324354

@@ -329,7 +359,7 @@ private function saveUploadedFile(UploadedFile $file, ProcessRequest $processReq
329359
* Remove the specified resource from storage.
330360
*
331361
* @param Media $file
332-
* @return \Illuminate\Http\Response
362+
* @return Response
333363
*
334364
* @internal param int $id
335365
*
@@ -365,7 +395,7 @@ private function saveUploadedFile(UploadedFile $file, ProcessRequest $processReq
365395
*/
366396
public function destroy(Request $laravel_request, ProcessRequest $request, $fileId)
367397
{
368-
$file = \ProcessMaker\Models\Media::getFilesRequest($request)->find($fileId);
398+
$file = Media::getFilesRequest($request, $fileId);
369399

370400
if (!$file) {
371401
return abort(response(__('File ID does not exist'), 404));

‎ProcessMaker/Http/Controllers/Api/TaskController.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ public function update(Request $request, ProcessRequestToken $task)
246246
//Call the manager to trigger the start event
247247
$process = $task->process;
248248
$instance = $task->processRequest;
249+
TaskDraft::moveDraftFiles($task);
249250
WorkflowManager::completeTask($process, $instance, $task, $data);
250251

251252
return new Resource($task->refresh());

‎ProcessMaker/Http/Controllers/Api/TaskDraftController.php‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,36 @@
33
namespace ProcessMaker\Http\Controllers\Api;
44

55
use Illuminate\Http\Request;
6+
use Illuminate\Support\Arr;
67
use ProcessMaker\Http\Controllers\Controller;
78
use ProcessMaker\Http\Resources\ApiCollection;
89
use ProcessMaker\Http\Resources\ApiResource;
9-
use ProcessMaker\Models\TaskDraft;
1010
use ProcessMaker\Models\ProcessRequestToken;
11-
use Illuminate\Support\Arr;
11+
use ProcessMaker\Models\TaskDraft;
1212

1313
class TaskDraftController extends Controller
1414
{
1515
public function update(Request $request, ProcessRequestToken $task)
1616
{
1717
$search = ['task_id' => $task->id];
18-
$draft = TaskDraft::updateOrCreate($search,['data' => $request->all()]);
18+
$draft = TaskDraft::firstOrNew($search, ['data' => []]);
19+
// Do not overwrite __deleted_files
20+
$deletedFiles = Arr::get($draft->data, '__deleted_files');
21+
$data = $request->all();
22+
if ($deletedFiles) {
23+
$data['__deleted_files'] = $deletedFiles;
24+
}
25+
$draft->data = $data;
26+
$draft->saveOrFail();
1927

2028
return new ApiResource($draft);
2129
}
30+
2231
public function delete(ProcessRequestToken $task)
2332
{
24-
TaskDraft::where('task_id', $task->id)->delete();
33+
// Use get()->each to fire the delete event for each draft
34+
TaskDraft::where('task_id', $task->id)->get()->each->delete();
35+
2536
return response([], 204);
2637
}
2738
}

‎ProcessMaker/Models/Media.php‎

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace ProcessMaker\Models;
44

55
use Illuminate\Database\Eloquent\Factories\HasFactory;
6+
use Illuminate\Support\Collection;
67
use Illuminate\Validation\ValidationException;
78
use ProcessMaker\Models\Process;
89
use ProcessMaker\Models\ProcessRequest;
@@ -202,18 +203,49 @@ public function saveProcessMedia(Process $process, $properties, $key = 'uuid')
202203
* getFilesRequest
203204
*
204205
* @param ProcessRequest $request
205-
* @return Media files
206+
* @return Collection | Media
206207
*/
207-
public static function getFilesRequest(ProcessRequest $request)
208+
public static function getFilesRequest(ProcessRequest $request, $id = null)
208209
{
209210
$requestTokenIds = [$request->id];
210211
if ($request->collaboration && $request->collaboration->requests()) {
211212
// Get all processes and subprocesses request token id's ..
212213
$requestTokenIds = $request->collaboration->requests->pluck('id');
213214
}
214215

216+
// Return a single file when $id is set
217+
if ($id) {
218+
$mediaById = self::findOrFail($id);
219+
220+
if (!in_array($mediaById->process_request_id, $requestTokenIds)) {
221+
abort(404, __('File is not part of this request'));
222+
}
223+
224+
return $mediaById;
225+
}
226+
215227
// Get all files for process and all subprocesses ..
216-
return self::whereIn('model_id', $requestTokenIds)->get();
228+
return self::where('model_type', ProcessRequest::class)
229+
->whereIn('model_id', $requestTokenIds)->get();
230+
}
231+
232+
public function getProcessRequestIdAttribute()
233+
{
234+
if ($this->model_type == TaskDraft::class) {
235+
return $this->model->processRequestToken->processRequest->id;
236+
} elseif ($this->model_type == ProcessRequest::class) {
237+
return $this->model->id;
238+
}
239+
throw new \Exception('No process request id for ' . $this->model_type);
240+
}
241+
242+
public function toArray()
243+
{
244+
$array = parent::toArray();
245+
246+
$array['process_request_id'] = $this->process_request_id;
247+
248+
return $array;
217249
}
218250

219251
/**

‎ProcessMaker/Models/ProcessRequest.php‎

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@
4747
* @property string $status
4848
* @property array $data
4949
* @property string $collaboration_uuid
50-
* @property \Carbon\Carbon $initiated_at
51-
* @property \Carbon\Carbon $completed_at
52-
* @property \Carbon\Carbon $updated_at
53-
* @property \Carbon\Carbon $created_at
50+
* @property Carbon $initiated_at
51+
* @property Carbon $completed_at
52+
* @property Carbon $updated_at
53+
* @property Carbon $created_at
5454
* @property Process $process
5555
* @property ProcessRequestLock[] $locks
5656
* @property ProcessRequestToken $ownerTask
@@ -562,7 +562,7 @@ public function logError(Throwable $exception, FlowElementInterface $element = n
562562
$errors[] = $error;
563563
$this->errors = $errors;
564564
$this->status = 'ERROR';
565-
\Log::error($exception);
565+
Log::error($exception);
566566
if (!$this->isNonPersistent()) {
567567
$this->save();
568568
}
@@ -740,7 +740,7 @@ public function valueAliasParticipantByFullName($value, $expression)
740740
->whereIn('user_id', function ($subquery) use ($value, $expression) {
741741
$subquery->select('id')
742742
->from('users')
743-
->whereRaw("CONCAT(firstname, ' ', lastname) " . $expression->operator . " ?", [$value]);
743+
->whereRaw("CONCAT(firstname, ' ', lastname) " . $expression->operator . ' ?', [$value]);
744744
})
745745
->whereIn('element_type', ['task', 'userTask', 'startEvent']);
746746
});
@@ -914,7 +914,7 @@ public function ownerTask()
914914
*/
915915
public function requestFiles(bool $includeToken = false)
916916
{
917-
$media = \ProcessMaker\Models\Media::getFilesRequest($this);
917+
$media = Media::getFilesRequest($this);
918918

919919
return (object) $media->mapToGroups(function ($file) use ($includeToken) {
920920
$dataName = $file->getCustomProperty('data_name');
@@ -934,11 +934,7 @@ public function requestFiles(bool $includeToken = false)
934934
public function downloadFile($fileId)
935935
{
936936
// Get all files for process and all subprocesses ..
937-
$media = Media::getFilesRequest($this);
938-
939-
$filtered = $media->filter(function ($value) use ($fileId) {
940-
return $value->id == $fileId;
941-
})->first();
937+
$filtered = Media::getFilesRequest($this, $fileId);
942938

943939
if (!$filtered) {
944940
return null;
@@ -951,7 +947,7 @@ public function downloadFile($fileId)
951947

952948
public function getMedia(string $collectionName = 'default', $filters = []): Collection
953949
{
954-
return \ProcessMaker\Models\Media::getFilesRequest($this);
950+
return Media::getFilesRequest($this);
955951
}
956952

957953
public function getErrors()

0 commit comments

Comments
 (0)