Skip to content

Commit 3102803

Browse files
committed
solving conflict
2 parents 53ffc3b + a847eae commit 3102803

24 files changed

Lines changed: 1254 additions & 589 deletions

ProcessMaker/Http/Controllers/Api/ProcessLaunchpadController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ public function getProcessesMenu(Request $request)
202202
$userId = $user->id;
203203

204204
$processes = Process::select('processes.*')
205+
->notArchived()
205206
->distinct()
206207
->whereHas('requests', function ($query) use ($userId) {
207208
$query->where('user_id', $userId)

ProcessMaker/Http/Controllers/Api/ScreenController.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,14 @@ public function duplicate(Screen $screen, Request $request)
482482
*/
483483
public function destroy(Screen $screen)
484484
{
485+
// Check if the screen is a default screen
486+
if ($screen->is_default == 1) {
487+
return response([
488+
'message' => 'Cannot delete a default screen',
489+
'errors' => ['is_default' => 'Default screens cannot be deleted'],
490+
], 422);
491+
}
492+
485493
$screen->delete();
486494
// Call new event to store changes in LOG
487495
ScreenDeleted::dispatch($screen);

ProcessMaker/Http/Controllers/Process/ModelerController.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use ProcessMaker\Models\ProcessCategory;
1313
use ProcessMaker\Models\ProcessLaunchpad;
1414
use ProcessMaker\Models\ProcessRequest;
15+
use ProcessMaker\Models\Screen;
1516
use ProcessMaker\Models\ScreenCategory;
1617
use ProcessMaker\Models\ScreenType;
1718
use ProcessMaker\Models\ScriptCategory;
@@ -125,6 +126,8 @@ public function prepareModelerData(
125126
$process->load('alternativeInfo');
126127
}
127128

129+
$defaultEmailNotification = $this->getDefaultEmailNotification();
130+
128131
return [
129132
'process' => $process,
130133
'manager' => $manager,
@@ -147,6 +150,34 @@ public function prepareModelerData(
147150
'alternative' => $alternative,
148151
'abPublish' => PackageHelper::isPackageInstalled('ProcessMaker\Package\PackageABTesting\PackageServiceProvider'),
149152
'launchpad' => ProcessLaunchpad::getLaunchpad(true, $process->id),
153+
'defaultEmailNotification' => $defaultEmailNotification,
154+
];
155+
}
156+
157+
/**
158+
* Get the default email notification configuration for tasks
159+
*
160+
* Returns an array containing the default email notification settings including:
161+
* - subject: The default email subject template
162+
* - type: The notification type (screen)
163+
* - screenRef: The ID of the default email notification screen
164+
* - toRecipients: Array of default recipients (assigned user)
165+
* @return array{screenRef: mixed, subject: string, toRecipients: array, type: string}
166+
*/
167+
private function getDefaultEmailNotification(): array
168+
{
169+
$screen = Screen::getScreenByKey('default-email-task-notification');
170+
171+
return [
172+
'subject' => 'RE: {{_user.firstname}} assigned you in "{{_task_name}}"',
173+
'type' => 'screen',
174+
'screenRef' => $screen->id,
175+
'toRecipients' => [
176+
[
177+
'type' => 'assignedUser',
178+
'value' => null,
179+
],
180+
],
150181
];
151182
}
152183

ProcessMaker/Listeners/HandleEndEventRedirect.php

Lines changed: 105 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,124 @@
33
namespace ProcessMaker\Listeners;
44

55
use Illuminate\Support\Facades\Auth;
6+
use Illuminate\Support\Facades\Log;
67
use ProcessMaker\Events\ProcessCompleted;
8+
use ProcessMaker\Models\ProcessRequest;
79

810
class HandleEndEventRedirect extends HandleRedirectListener
911
{
12+
/**
13+
* Handle the process completed event.
14+
*
15+
* This method processes the event by:
16+
* 1. Validating the event is not null
17+
* 2. Getting and validating the process request
18+
* 3. Checking if it's a subprocess (skips if true)
19+
* 4. Handling the main process redirect
20+
*
21+
* @param ProcessCompleted|null $event The process completed event
22+
* @return void
23+
*/
24+
public function handle(?ProcessCompleted $event): void
25+
{
26+
if (!$event) {
27+
Log::error('Null event passed to HandleEndEventRedirect');
28+
29+
return;
30+
}
31+
32+
try {
33+
$request = $this->validateAndGetRequest($event);
34+
if (!$request) {
35+
return;
36+
}
37+
38+
if ($this->isSubprocess($request)) {
39+
Log::debug('Skipping subprocess redirect');
40+
41+
return;
42+
}
43+
44+
$this->handleMainProcessRedirect($request, $event);
45+
} catch (\Throwable $e) {
46+
$this->logError($e);
47+
}
48+
}
1049

1150
/**
12-
* Handle the event.
51+
* Validates and returns the process request from the event
1352
*/
14-
public function handle(ProcessCompleted $event): void
53+
private function validateAndGetRequest(ProcessCompleted $event): ?ProcessRequest
1554
{
1655
$request = $event->getProcessRequest();
17-
if (empty($request)) {
18-
return;
56+
57+
if (!$request instanceof ProcessRequest) {
58+
Log::info('Invalid or empty request in HandleEndEventRedirect');
59+
60+
return null;
1961
}
20-
// Do not redirect to child request summary if there is a previous redirect
21-
if ($request->parent_request_id && self::$redirectionMethod !== '') {
22-
return;
62+
63+
if (!$request->id) {
64+
Log::warning('Request has no ID in HandleEndEventRedirect');
65+
66+
return null;
67+
}
68+
69+
return $request;
70+
}
71+
72+
/**
73+
* Logs error details
74+
*/
75+
private function logError(\Throwable $e): void
76+
{
77+
Log::error('Error in HandleEndEventRedirect: ' . $e->getMessage(), [
78+
'exception' => get_class($e),
79+
'file' => $e->getFile(),
80+
'line' => $e->getLine(),
81+
]);
82+
}
83+
84+
/**
85+
* Check if the request is a subprocess
86+
*
87+
* @param ProcessRequest|null $request
88+
* @return bool
89+
*/
90+
private function isSubprocess(?ProcessRequest $request): bool
91+
{
92+
if (!$request) {
93+
Log::warning('Null request passed to isSubprocess check');
94+
95+
return false;
2396
}
2497

98+
return !empty($request->parent_request_id);
99+
}
100+
101+
/**
102+
* Handle the redirection for the main process
103+
*
104+
* @param ProcessRequest $request
105+
* @param ProcessCompleted $event
106+
* @return void
107+
*/
108+
private function handleMainProcessRedirect(ProcessRequest $request, ProcessCompleted $event): void
109+
{
110+
// Type hints ensure $request and $event are valid, no need for null check
25111
$userId = Auth::id();
26112
$requestId = $request->id;
27-
$this->setRedirectTo($request, 'processCompletedRedirect', $event, $userId, $requestId);
113+
114+
if ($userId) {
115+
try {
116+
$this->setRedirectTo($request, 'processCompletedRedirect', $event, $userId, $requestId);
117+
} catch (\Throwable $e) {
118+
$this->logError($e);
119+
}
120+
} else {
121+
Log::warning('No authenticated user found when handling end event redirect', [
122+
'request_id' => $requestId,
123+
]);
124+
}
28125
}
29126
}

ProcessMaker/Models/Screen.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,17 @@ public static function getScreenByKey(string $key) : ?self
305305
return $screen;
306306
}
307307

308-
private static function createScreenByKey(string $key, bool $isSystem = true, string $path = null): self
308+
public static function getScreenByKeyPerDefault(string $key) : ?self
309+
{
310+
$screen = self::firstWhere('key', $key);
311+
if (!$screen) {
312+
$screen = self::createScreenByKey($key, false, null, 1);
313+
}
314+
315+
return $screen;
316+
}
317+
318+
private static function createScreenByKey(string $key, bool $isSystem = true, string $path = null, $isDefault = 0): self
309319
{
310320
// If no path is provided, use the default path
311321
if (!$path) {
@@ -339,6 +349,7 @@ private static function createScreenByKey(string $key, bool $isSystem = true, st
339349
// Create new screen
340350
unset($screen['categories']);
341351
$screen['screen_category_id'] = null;
352+
$screen['is_default'] = $isDefault;
342353

343354
if ($newScreen) {
344355
$newScreen->fill($screen);

ProcessMaker/Models/TaskDraft.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,14 @@ private static function filesToDelete($task, $mediaItem)
8181
foreach ($task->processRequest->getMedia() as $existingMediaItem) {
8282
$existingMediaDataName = $existingMediaItem->getCustomProperty('data_name');
8383
$mediaItemDataName = $mediaItem->getCustomProperty('data_name');
84+
/**
85+
* This is different when the process depends on a subprocess.
86+
*/
87+
$subProcessParallel = $mediaItem->getCustomProperty('parent_process_request_id') === $task->processRequest->id;
8488
if (
8589
$existingMediaDataName === $mediaItemDataName &&
86-
!$mediaItem->getCustomProperty('is_multiple')
90+
!$mediaItem->getCustomProperty('is_multiple') &&
91+
$subProcessParallel
8792
) {
8893
$delete[] = $existingMediaItem;
8994
}

ProcessMaker/Repositories/TokenRepository.php

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,6 @@ public function persistActivityActivated(ActivityInterface $activity, TokenInter
179179
if (!is_null($user)) {
180180
// Review if the task has enable the action by email
181181
$this->validateAndSendActionByEmail($activity, $token, $user->email);
182-
// Review if the user has enable the email notification
183-
$isEmailTaskValid = $this->validateEmailUserNotification($token, $user);
184-
// Define the flag if the email needs to sent
185-
$token->is_emailsent = $isEmailTaskValid ? 1 : 0;
186182
}
187183
$this->instanceRepository->persistInstanceUpdated($token->getInstance());
188184
}
@@ -234,75 +230,6 @@ private function validateAndSendActionByEmail(ActivityInterface $activity, Token
234230
}
235231
}
236232

237-
/**
238-
* Validates the user's email notification settings and sends an email if enabled.
239-
*
240-
* @param TokenInterface $token The token containing task information.
241-
* @param User $user The user to whom the email notification will be sent.
242-
* @return mixed|null Returns the result of the email sending operation or null if not sent.
243-
*/
244-
private function validateEmailUserNotification(TokenInterface $token, User $user)
245-
{
246-
try {
247-
Log::Info('User isEmailTaskEnable: ' . $user->email_task_notification);
248-
// Return if email task notification is not enabled or email is empty
249-
if ($user->email_task_notification === 0 || empty($user->email)) {
250-
return null;
251-
}
252-
// Check if the required class exists
253-
if (!class_exists('ProcessMaker\Packages\Connectors\ActionsByEmail\EmailProvider')) {
254-
return null;
255-
}
256-
// Prepare data for the email
257-
$data = $this->prepareEmailData($token, $user);
258-
259-
// Send Email
260-
return (new TaskActionByEmail())->sendAbeEmail($data['configEmail'], $user->email, $data['emailData']);
261-
} catch (\Exception $e) {
262-
// Catch and log the error
263-
Log::error('Failed to validate and send email task notification', [
264-
'error' => $e->getMessage(),
265-
]);
266-
}
267-
}
268-
269-
/**
270-
* Prepares the email data and configuration for sending an email notification.
271-
*
272-
* @param TokenInterface $token The token containing task information.
273-
* @param User $user The user for whom the email data is being prepared.
274-
* @return array An associative array containing 'emailData' and 'configEmail'.
275-
*/
276-
private function prepareEmailData(TokenInterface $token, User $user)
277-
{
278-
// Get the case
279-
$caseTitle = ProcessRequest::where('id', $token->process_request_id)->value('case_title');
280-
// Prepare the email data
281-
$taskName = $token->element_name ?? '';
282-
$emailData = [
283-
'firstname' => $user->firstname ?? '',
284-
'assigned_by' => Auth::user()->fullname ?? __('System'),
285-
'element_name' => $taskName,
286-
'case_title' => $caseTitle, // Populate this if needed
287-
'due_date' => $token->due_at ?? '',
288-
'link_review_task' => config('app.url') . '/' . 'tasks/' . $token->id . '/edit',
289-
'imgHeader' => config('app.url') . '/img/processmaker_login.png',
290-
];
291-
// Get the screen by key
292-
$screen = Screen::getScreenByKey('default-email-task-notification');
293-
// Prepare the email configuration
294-
$configEmail = [
295-
'emailServer' => 0, // Use the default email server
296-
'subject' => "{$user->firstname} assigned you in '{$taskName}'",
297-
'screenEmailRef' => $screen->id ?? 0, // Define here the screen to use
298-
];
299-
300-
return [
301-
'emailData' => $emailData,
302-
'configEmail' => $configEmail,
303-
];
304-
}
305-
306233
/**
307234
* Get due Variable
308235
*

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "processmaker/processmaker",
3-
"version": "4.15.5-RC2",
3+
"version": "4.15.5",
44
"description": "BPM PHP Software",
55
"keywords": [
66
"php bpm processmaker"
@@ -106,7 +106,7 @@
106106
"Gmail"
107107
],
108108
"processmaker": {
109-
"build": "d5da695a",
109+
"build": "215b5b87",
110110
"cicd-enabled": true,
111111
"custom": {
112112
"package-ellucian-ethos": "1.19.5",

composer.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration {
8+
/**
9+
* Run the migrations.
10+
*/
11+
public function up(): void
12+
{
13+
Schema::table('screens', function (Blueprint $table) {
14+
$table->boolean('is_default')->default(false);
15+
});
16+
Schema::table('screen_versions', function (Blueprint $table) {
17+
$table->boolean('is_default')->default(false);
18+
});
19+
}
20+
21+
/**
22+
* Reverse the migrations.
23+
*/
24+
public function down(): void
25+
{
26+
Schema::table('screens', function (Blueprint $table) {
27+
$table->dropColumn('is_default');
28+
});
29+
Schema::table('screen_versions', function (Blueprint $table) {
30+
$table->dropColumn('is_default');
31+
});
32+
}
33+
};

0 commit comments

Comments
 (0)