Skip to content

Commit 9b8f017

Browse files
authored
Merge pull request #8199 from ProcessMaker/bugfix/FOUR-23865
FOUR-23865: Fix loading tasks in saved search with process with html entities
2 parents ef1bd41 + cf8c4da commit 9b8f017

File tree

3 files changed

+198
-1
lines changed

3 files changed

+198
-1
lines changed

ProcessMaker/Http/Controllers/Api/ProcessController.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,11 @@ public function store(Request $request)
385385
$processCreated = ProcessCreated::BPMN_CREATION;
386386
}
387387

388+
// Replace html entities with the correct characters
389+
if (isset($data['bpmn'])) {
390+
$data['bpmn'] = BpmnDocument::replaceHtmlEntities($data['bpmn']);
391+
}
392+
388393
if ($schemaErrors = $this->validateBpmn($request)) {
389394
return response(
390395
['message' => __('The bpm definition is not valid'),
@@ -482,6 +487,11 @@ public function update(Request $request, Process $process)
482487
$request->validate($rules);
483488
$original = $process->getOriginal();
484489

490+
// Replace html entities with the correct characters
491+
if ($request->has('bpmn')) {
492+
$request->merge(['bpmn' => BpmnDocument::replaceHtmlEntities($request->input('bpmn'))]);
493+
}
494+
485495
// bpmn validation
486496
if ($schemaErrors = $this->validateBpmn($request)) {
487497
$warnings = [];
@@ -599,7 +609,8 @@ public function updateBpmn(Request $request, Process $process)
599609
$process->alternative = $request->input('alternative');
600610
}
601611

602-
$process->bpmn = $request->input('bpmn');
612+
$bpmn = BpmnDocument::replaceHtmlEntities($request->input('bpmn'));
613+
$process->bpmn = $bpmn;
603614
$process->name = $request->input('name');
604615
$process->description = $request->input('description');
605616
$process->saveOrFail();

tests/Feature/ProcessHtmlTest.php

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
namespace Tests\Feature;
4+
5+
use ProcessMaker\Models\Process;
6+
use ProcessMaker\Models\User;
7+
use ProcessMaker\Nayra\Storage\BpmnDocument;
8+
use Tests\Feature\Shared\RequestHelper;
9+
use Tests\TestCase;
10+
11+
class ProcessHtmlTest extends TestCase
12+
{
13+
use RequestHelper;
14+
15+
protected static $DO_NOT_SEND = 'DO_NOT_SEND';
16+
17+
/**
18+
* A process with html entities in the documentation field should be able to be loaded.
19+
* By default, the bpmn processes are loaded with the html entities support.
20+
*/
21+
public function test_process_with_html_can_be_loaded()
22+
{
23+
$this->user = User::factory()->create([
24+
'is_administrator' => false,
25+
]);
26+
$process = $this->createProcessFromBPMN('tests/Fixtures/process_with_html.bpmn');
27+
28+
$definitions = $process->getDefinitions(true);
29+
30+
$this->assertNotEmpty($definitions, 'The process could not be loaded correctly');
31+
}
32+
33+
/**
34+
* A process with html entities in the documentation field should be able to be stored.
35+
*/
36+
public function test_store_process_with_html_entities()
37+
{
38+
$route = route('api.processes.store');
39+
$base = Process::factory()->make([
40+
'user_id' => static::$DO_NOT_SEND,
41+
'process_category_id' => static::$DO_NOT_SEND,
42+
]);
43+
$array = array_diff($base->toArray(), [static::$DO_NOT_SEND]);
44+
// Add a bpmn content
45+
$bpmn = file_get_contents(base_path('tests/Fixtures/process_with_html.bpmn'));
46+
$array['bpmn'] = $bpmn;
47+
$response = $this->apiCall('POST', $route, $array);
48+
$response->assertStatus(201);
49+
$data = $response->json();
50+
$process = Process::where('id', $data['id'])->first();
51+
52+
// Fix bpmn content to remove the html entities
53+
$fixedBpmn = BpmnDocument::replaceHtmlEntities($process->bpmn);
54+
$this->assertEquals($fixedBpmn, $process->bpmn);
55+
}
56+
57+
/**
58+
* A process with html entities in the documentation field should be able to be updated.
59+
*/
60+
public function test_update_process_with_html_entities()
61+
{
62+
// First create a process
63+
$route = route('api.processes.store');
64+
$base = Process::factory()->make([
65+
'user_id' => static::$DO_NOT_SEND,
66+
'process_category_id' => static::$DO_NOT_SEND,
67+
]);
68+
$array = array_diff($base->toArray(), [static::$DO_NOT_SEND]);
69+
$response = $this->apiCall('POST', $route, $array);
70+
$response->assertStatus(201);
71+
$data = $response->json();
72+
$process = Process::where('id', $data['id'])->first();
73+
74+
// Now update the process
75+
$bpmn = file_get_contents(base_path('tests/Fixtures/process_with_html.bpmn'));
76+
$updateRoute = route('api.processes.update', ['process' => $process->id]);
77+
$updateData = [
78+
'name' => $process->name . ' Updated',
79+
'description' => $process->description . ' Updated',
80+
'bpmn' => $bpmn,
81+
];
82+
$updateResponse = $this->apiCall('PUT', $updateRoute, $updateData);
83+
$updateResponse->assertStatus(200);
84+
85+
// Reload the process from database
86+
$updatedProcess = Process::where('id', $process->id)->first();
87+
88+
// Check if the process was updated correctly
89+
$this->assertEquals($process->name . ' Updated', $updatedProcess->name);
90+
91+
// Fix bpmn content to remove the html entities
92+
$fixedBpmn = BpmnDocument::replaceHtmlEntities($updatedProcess->bpmn);
93+
$this->assertEquals($fixedBpmn, $updatedProcess->bpmn);
94+
}
95+
96+
/**
97+
* Test updating BPMN content directly via the updateBpmn endpoint.
98+
* This endpoint allows updating only the BPMN content, not the other process attributes.
99+
*/
100+
public function test_update_bpmn_endpoint_with_html_entities()
101+
{
102+
// First create a process
103+
$route = route('api.processes.store');
104+
$base = Process::factory()->make([
105+
'user_id' => static::$DO_NOT_SEND,
106+
'process_category_id' => static::$DO_NOT_SEND,
107+
]);
108+
$array = array_diff($base->toArray(), [static::$DO_NOT_SEND]);
109+
$response = $this->apiCall('POST', $route, $array);
110+
$response->assertStatus(201);
111+
$data = $response->json();
112+
$process = Process::where('id', $data['id'])->first();
113+
114+
// Now update the process
115+
$bpmn = file_get_contents(base_path('tests/Fixtures/process_with_html.bpmn'));
116+
$updateRoute = route('api.processes.update_bpmn', ['process' => $process->id]);
117+
$updateData = [
118+
'name' => $process->name . ' Updated',
119+
'description' => $process->description . ' Updated',
120+
'bpmn' => $bpmn,
121+
];
122+
$updateResponse = $this->apiCall('PUT', $updateRoute, $updateData);
123+
$updateResponse->assertStatus(200);
124+
125+
// Reload the process from database
126+
$updatedProcess = Process::where('id', $process->id)->first();
127+
128+
// Check if the process was updated correctly
129+
$this->assertEquals($process->name . ' Updated', $updatedProcess->name);
130+
131+
// Fix bpmn content to remove the html entities
132+
$fixedBpmn = BpmnDocument::replaceHtmlEntities($updatedProcess->bpmn);
133+
$this->assertEquals($fixedBpmn, $updatedProcess->bpmn);
134+
}
135+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:pm="http://processmaker.com/BPMN/2.0/Schema.xsd" xmlns:tns="http://sourceforge.net/bpmn/definitions/_1530553328908" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://bpmn.io/schema/bpmn" exporter="ProcessMaker Modeler" exporterVersion="1.0" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://bpmn.sourceforge.net/schemas/BPMN20.xsd">
3+
<bpmn:process id="ProcessId" name="ProcessName" isExecutable="true">
4+
<bpmn:startEvent id="node_1" name="Start Event" pm:allowInterstitial="true" pm:interstitialScreenRef="1" pm:config="{&#34;web_entry&#34;:null}">
5+
<bpmn:outgoing>node_23</bpmn:outgoing>
6+
</bpmn:startEvent>
7+
<bpmn:task id="node_2" name="Form Task" pm:screenRef="110" pm:allowInterstitial="false" pm:assignment="requester" pm:assignmentLock="false" pm:allowReassignment="false" pm:config="{&#34;web_entry&#34;:null,&#34;email_notifications&#34;:{&#34;notifications&#34;:[]}}" pm:elementDestination="{&#34;type&#34;:&#34;taskSource&#34;,&#34;value&#34;:null}">
8+
<bpmn:incoming>node_23</bpmn:incoming>
9+
<bpmn:outgoing>node_32</bpmn:outgoing>
10+
</bpmn:task>
11+
<bpmn:task id="node_12" name="Form Task" pm:screenRef="439" pm:allowInterstitial="false" pm:isDueInVariable="false" pm:assignment="process_manager" pm:assignedUsers="" pm:assignedGroups="" pm:assignmentLock="false" pm:allowReassignment="false" pm:config="{&#34;web_entry&#34;:null,&#34;email_notifications&#34;:{&#34;notifications&#34;:[]},&#34;selfService&#34;:false,&#34;assigneeManagerEscalation&#34;:true}" pm:elementDestination="{&#34;type&#34;:&#34;taskSource&#34;,&#34;value&#34;:null}">
12+
<bpmn:documentation>&lt;p&gt;dfgdf g gdf gdf. rt fdg dfg f gs gdfh j ghj. ghk gh j75u y u57 uyh jikuilopiuo ityu rt yertqwerq aasd x czx. bdfhg ty gfh nvb nhjtyu uyijknmb. jkluop tyuyu etgfgcvbsrf werrt gb dr ger t dfgdf g gdf gdf. rt fdg dfg f gs gdfh j ghj. ghk gh j75u y u57 uyh jikuilopiuo ityu rt yertqwerq aasd x czx. bdfhg ty gfh nvb nhjtyu uyijknmb. jkluop tyuyu etgfgcvbsrf werrt gb dr ger t dfgdf g gdf gdf. rt fdg dfg f gs gdfh j ghj. ghk gh j75u y u57 uyh jikuilopiuo ityu rt yertqwerq aasd x czx. bdfhg ty gfh nvb nhjtyu uyijknmb. jkluop tyuyu etgfgcvbsrf werrt gb dr ger t dfgdf g gdf gdf. rt fdg dfg f gs gdfh j ghj. ghk gh j75u y u57 uyh jikuilopiuo ityu rt yertqwerq aasd x czx. bdfhg ty gfh nvb nhjtyu uyijknmb. jkluop tyuyu etgfgcvbsrf werrt gb dr ger t dfgdf g gdf gdf. rt fdg dfg f gs gdfh j ghj. ghk gh j75u y u57 uyh jikuilopiuo ityu rt yertqwerq aasd x czx. bdfhg ty gfh nvb nhjtyu uyijknmb. jkluop tyuyu etgfgcvbsrf werrt gb dr ger t&nbsp;&lt;/p&gt;</bpmn:documentation>
13+
<bpmn:incoming>node_32</bpmn:incoming>
14+
<bpmn:outgoing>node_36</bpmn:outgoing>
15+
</bpmn:task>
16+
<bpmn:endEvent id="node_22" name="End Event" pm:elementDestination="{&#34;type&#34;:&#34;summaryScreen&#34;,&#34;value&#34;:null}">
17+
<bpmn:incoming>node_36</bpmn:incoming>
18+
</bpmn:endEvent>
19+
<bpmn:sequenceFlow id="node_23" name="" sourceRef="node_1" targetRef="node_2" />
20+
<bpmn:sequenceFlow id="node_32" name="" sourceRef="node_2" targetRef="node_12" />
21+
<bpmn:sequenceFlow id="node_36" name="" sourceRef="node_12" targetRef="node_22" />
22+
</bpmn:process>
23+
<bpmndi:BPMNDiagram id="BPMNDiagramId">
24+
<bpmndi:BPMNPlane id="BPMNPlaneId" bpmnElement="ProcessId">
25+
<bpmndi:BPMNShape id="node_1_di" bpmnElement="node_1">
26+
<dc:Bounds x="200" y="110" width="36" height="36" />
27+
</bpmndi:BPMNShape>
28+
<bpmndi:BPMNShape id="node_2_di" bpmnElement="node_2">
29+
<dc:Bounds x="280" y="150" width="116" height="76" />
30+
</bpmndi:BPMNShape>
31+
<bpmndi:BPMNShape id="node_12_di" bpmnElement="node_12">
32+
<dc:Bounds x="460" y="160" width="116" height="76" />
33+
</bpmndi:BPMNShape>
34+
<bpmndi:BPMNShape id="node_22_di" bpmnElement="node_22">
35+
<dc:Bounds x="660" y="190" width="36" height="36" />
36+
</bpmndi:BPMNShape>
37+
<bpmndi:BPMNEdge id="node_23_di" bpmnElement="node_23">
38+
<di:waypoint x="218" y="128" />
39+
<di:waypoint x="338" y="188" />
40+
</bpmndi:BPMNEdge>
41+
<bpmndi:BPMNEdge id="node_32_di" bpmnElement="node_32">
42+
<di:waypoint x="338" y="188" />
43+
<di:waypoint x="518" y="198" />
44+
</bpmndi:BPMNEdge>
45+
<bpmndi:BPMNEdge id="node_36_di" bpmnElement="node_36">
46+
<di:waypoint x="518" y="198" />
47+
<di:waypoint x="678" y="208" />
48+
</bpmndi:BPMNEdge>
49+
</bpmndi:BPMNPlane>
50+
</bpmndi:BPMNDiagram>
51+
</bpmn:definitions>

0 commit comments

Comments
 (0)