Skip to content

Commit

Permalink
Merge branch 'release-2024-fall' into feature/FOUR-18098
Browse files Browse the repository at this point in the history
  • Loading branch information
nolanpro committed Oct 8, 2024
2 parents b8a2d81 + a4f3b67 commit e84bc26
Show file tree
Hide file tree
Showing 67 changed files with 2,216 additions and 988 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy-pm4.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ env:
GITHUB_TOKEN: ${{ secrets.GIT_TOKEN }}
BUILD_BASE: ${{ (contains(github.event.pull_request.body, 'ci:build-base') || github.event_name == 'schedule') && '1' || '0' }}
BASE_IMAGE: ${{ secrets.REGISTRY_HOST }}/processmaker/processmaker:base
K8S_BRANCH: ${{ contains(github.event.pull_request.body, 'ci:next') && 'next' || 'develop' }}
K8S_BRANCH: ${{ contains(github.event.pull_request.body, 'ci:next') && 'next' || 'release-2024-fall' }}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
Expand Down
3 changes: 2 additions & 1 deletion ProcessMaker/Console/Migration/ExtendedMigrateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

use Illuminate\Database\Console\Migrations\MigrateCommand as BaseMigrateCommand;
use Illuminate\Support\Facades\Cache;
use ProcessMaker\Helpers\CachedSchema;
use ProcessMaker\Models\ProcessMakerModel;

class ExtendedMigrateCommand extends BaseMigrateCommand
{

public function handle(): void
{
Cache::tags(ProcessMakerModel::MIGRATION_COLUMNS_CACHE_KEY)->flush();
Cache::tags(CachedSchema::CACHE_TAG)->flush();

parent::handle();
}
Expand Down
9 changes: 9 additions & 0 deletions ProcessMaker/Exception/InvalidImportOption.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace ProcessMaker\Exception;

use Exception;

class InvalidImportOption extends Exception
{
}
33 changes: 33 additions & 0 deletions ProcessMaker/Helpers/CachedSchema.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace ProcessMaker\Helpers;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Schema;

class CachedSchema
{
const CACHE_TAG = 'schema';

public function hasTable(string $table) : bool
{
$key = 'hasTable_' . $table;

return Cache::tags(self::CACHE_TAG)->rememberForever(
$key, function () use ($table) {
return Schema::hasTable($table);
}
);
}

public function hasColumn(string $table, string $column) : bool
{
$key = 'hasColumn_' . $table . '_' . $column;

return Cache::tags(self::CACHE_TAG)->rememberForever(
$key, function () use ($table, $column) {
return Schema::hasColumn($table, $column);
}
);
}
}
124 changes: 112 additions & 12 deletions ProcessMaker/Helpers/ScreenTemplateHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,33 @@ public static function removeScreenComponents($config, $components)
return $updatedConfig;
}

/**
* Filters and retrieves screen components from the provided configuration.
*
* This method processes the given screen configuration, iterating through each page
* to filter its items based on the specified components. It can optionally remove
* components from the configuration or keep only the specified components.
* @param array $config The full screen configuration
* @param array $components An array of component names that will be used to filter
* the items in the configuration.
* @param bool $removeComponents (optional) Determines the filtering behavior:
* - If 'true', the components in the `$components` array will be removed from the configuration
* - If 'false', only the components in the `$components` array will be retained
* Defaults to `true`.
*
* @return array The updated configuration after filtering the components.
*/
public static function getScreenComponents($config, $components, $removeComponents = true)
{
foreach ($config as $page) {
$filteredPageItems = self::filterPageItems($page['items'] ?? [], $components, $removeComponents);
$page['items'] = $filteredPageItems;
$updatedConfig[] = $page;
}

return $updatedConfig;
}

/**
* Filter items of a page based on the provided components.
*
Expand All @@ -36,14 +63,15 @@ public static function removeScreenComponents($config, $components)
*
* @param array $items The items of a page to filter.
* @param array $components The components to filter the items against.
* @param bool $removeComponents Whether to remove.
* @return array The filtered items of the page.
*/
private static function filterPageItems($items, $components)
private static function filterPageItems($items, $components, $removeComponents = true)
{
$filteredItems = [];

foreach ($items as $item) {
$filteredItem = self::filterItemByComponent($item, $components);
$filteredItem = self::filterItemByComponent($item, $components, $removeComponents);
if ($filteredItem !== null) {
if (is_array($filteredItem) && !isset($filteredItem['component'])) {
$filteredItems = array_merge($filteredItems, self::flattenNestedItems($filteredItem));
Expand All @@ -67,15 +95,16 @@ private static function filterPageItems($items, $components)
*
* @param array $item The item to filter.
* @param array $components The components to filter against.
* @param bool $removeComponents Whether to remove.
* @return array|null The filtered item or null if it should be removed.
*/
private static function filterItemByComponent($item, $components)
private static function filterItemByComponent($item, $components, $removeComponents = true)
{
if ($item['component'] === 'FormMultiColumn') {
return self::filterFormMultiColumn($item, $components);
return self::filterFormMultiColumn($item, $components, $removeComponents);
}

return !self::removeNestedComponents($item, $components) ? $item : null;
return !self::removeNestedComponents($item, $components, $removeComponents) ? $item : null;
}

/**
Expand All @@ -88,15 +117,16 @@ private static function filterItemByComponent($item, $components)
*
* @param array $item The 'FormMultiColumn' item to filter.
* @param array $components The components to filter against.
* @param bool $removeComponents Whether to remove.
* @return array The filtered 'FormMultiColumn' item.
*/
private static function filterFormMultiColumn($item, $components)
private static function filterFormMultiColumn($item, $components, $removeComponents = true)
{
$removeMultiColumn = self::removeNestedComponents($item, $components);
$removeMultiColumn = self::removeNestedComponents($item, $components, $removeComponents);
$filteredMultiColumnItems = $removeMultiColumn ? [] : $item;

foreach ($item['items'] as $index => $column) {
$filteredColumnItems = self::filterColumnItems($column, $components, $removeMultiColumn);
$filteredColumnItems = self::filterColumnItems($column, $components, $removeMultiColumn, $removeComponents);

if (isset($filteredMultiColumnItems['items'])) {
$filteredMultiColumnItems['items'][$index] = $filteredColumnItems;
Expand All @@ -117,9 +147,10 @@ private static function filterFormMultiColumn($item, $components)
*
* @param array $item The item to check for removal.
* @param array $components The screen components to filter against.
* @param bool $removeComponents Whether to remove.
* @return bool Whether the item should be removed.
*/
private static function removeNestedComponents($item, $components)
private static function removeNestedComponents($item, $components, $removeComponents = true)
{
$componentList = ['BFormComponent', 'BWrapperComponent'];
if (in_array($item['component'], $componentList)) {
Expand All @@ -128,7 +159,8 @@ private static function removeNestedComponents($item, $components)
return in_array($bootstrapComponent, $components[$item['component']]['bootstrapComponent']);
}
} else {
return in_array($item['component'], $components);
return in_array($item['component'], $components) && $removeComponents ||
!$removeComponents && !in_array($item['component'], $components);
}

return false;
Expand All @@ -145,18 +177,19 @@ private static function removeNestedComponents($item, $components)
*
* @param array $column The column items to filter.
* @param array $components The components to filter against.
* @param bool $removeComponents Whether to remove.
* @param bool $removeMultiColumn Whether the entire 'FormMultiColumn' should be removed.
* @return array The filtered column items.
*/
private static function filterColumnItems($column, $components, $removeMultiColumn)
private static function filterColumnItems($column, $components, $removeMultiColumn, $removeComponents = true)
{
$filteredColumnItems = [];

foreach ($column as $colItem) {
if (isset($colItem['component']) && $colItem['component'] === 'FormMultiColumn') {
self::filterNestedMultiColumns($colItem, $components, $removeMultiColumn);
$filteredColumnItems[] = $colItem;
} elseif (!self::removeNestedComponents($colItem, $components)) {
} elseif (!self::removeNestedComponents($colItem, $components, $removeComponents)) {
$filteredColumnItems[] = $colItem;
}
}
Expand Down Expand Up @@ -250,4 +283,71 @@ private static function flattenNestedItems($items)

return $flattenedItems;
}

// Parse the CSS string into an associative array
public static function parseCss($cssString)
{
$rules = [];
// Regex to match complex CSS selectors, allowing for any selector pattern
preg_match_all('/(?:\/\*.*?\*\*\/|([^{}]+))\s*\{(?:\/\*.*?\*\*\/|([^}]*))\}/', $cssString, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
$fullSelector = trim($match[1]); // Full CSS selector
$propertiesString = trim($match[2]); // Properties between the brackets

// Split properties into key-value pairs
$propertiesArray = explode(';', $propertiesString);
$properties = [];

foreach ($propertiesArray as $property) {
$propertyParts = explode(':', $property);
if (count($propertyParts) == 2) {
$key = trim($propertyParts[0]);
$value = trim($propertyParts[1]);
if (!empty($key) && !empty($value)) {
$properties[$key] = $value;
}
}
}

// Add rule for the selector
$rules[$fullSelector] = $properties;
}

return $rules;
}

// Merge the two CSS arrays
public static function mergeCss($currentCss, $templateCss)
{
foreach ($templateCss as $selector => $properties) {
if (isset($currentCss[$selector])) {
// Merge properties from Template CSS into the Current Screen CSS for the same selector
$currentCss[$selector] = array_merge($currentCss[$selector], $properties);
} else {
// Add new selector and properties from Template CSS
$currentCss[$selector] = $properties;
}
}

return $currentCss;
}

public static function generateCss($cssArray)
{
// Convert the CSS array back into a string and output the final CSS
$cssString = '';

foreach ($cssArray as $selector => $properties) {
$cssString .= "$selector {\n";

foreach ($properties as $key => $value) {
$cssString .= " $key: $value;\n";
}

$cssString .= "}\n\n";
}

return $cssString;
}
}
25 changes: 23 additions & 2 deletions ProcessMaker/Http/Controllers/Api/ProcessRequestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@ public function getDefaultChart(Request $request, $process)
'label' => __('Default chart'),
'data' => [$countCompleted, $countInProgress],
'backgroundColor' => [
'CLOSED' => '#62B2FD', // Color for 'Completed'
'ACTIVE' => '#9BDFC4', // Color for 'In Progress'
'CLOSED' => '#F9A8D4', // Color for 'Completed'
'ACTIVE' => '#4F46E5', // Color for 'In Progress'
],
],
],
Expand Down Expand Up @@ -818,4 +818,25 @@ public function enableIsActionbyemail($id)

return $affectedRows > 0;
}

/**
* This endpoint returns the destination of the last end event of a process request
*
* @param ProcessRequest $request
*/
public function endEventDestination(ProcessRequest $request)
{
$lastEndEvent = $request->tokens()
->where('element_type', 'end_event')
->orderBy('id', 'desc')
->first();
if (!$lastEndEvent) {
return response()->json(['message' => __('No end event found'), 'data' => null]);
}
$data = [
'endEventDestination' => $lastEndEvent->element_destination,
];

return response()->json(['message' => __('End event found'), 'data' => $data]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ private function validatePDFFile(UploadedFile $file, &$errors)
{
$text = $file->get();

$jsKeywords = ['/JavaScript', '/JS', '<< /S /JavaScript'];
$jsKeywords = ['/JavaScript', '<< /S /JavaScript'];

foreach ($jsKeywords as $keyword) {
if (strpos($text, $keyword) !== false) {
Expand Down
1 change: 0 additions & 1 deletion ProcessMaker/Http/Controllers/Api/TaskController.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ public function update(Request $request, ProcessRequestToken $task)
$instance = $task->processRequest;
TaskDraft::moveDraftFiles($task);
WorkflowManager::completeTask($process, $instance, $task, $data);
HandleRedirectListener::sendRedirectToEvent();

return new Resource($task->refresh());
} elseif (!empty($request->input('user_id'))) {
Expand Down
9 changes: 7 additions & 2 deletions ProcessMaker/Http/Controllers/Api/TemplateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@ public function deleteMediaImages(string $type, Request $request)
return $this->template->deleteMediaImages($type, $request);
}

public function applyTemplate(string $type, Request $request)
{
return $this->template->applyTemplate($type, $request);
}

private function validateImportedFile($content, $request, $type)
{
$decoded = null;
Expand Down Expand Up @@ -283,9 +288,9 @@ private function checkIfAssetsExist($request)
continue;
}

if (!$asset['model']::where('uuid', $key)->exists()
|| $payload['root'] === $asset['attributes']['uuid']
if ($payload['root'] === $asset['attributes']['uuid']
|| Str::contains($asset['type'], 'Category')
|| !$asset['model']::where('uuid', $key)->exists()
) {
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion ProcessMaker/Http/Controllers/TaskController.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public function edit(ProcessRequestToken $task, string $preview = '')
$task->allow_interstitial = $interstitial['allow_interstitial'];
$task->definition = $task->getDefinition();
$task->requestor = $task->processRequest->user;
$task->draft = $task->draft();
$task->draft = $task->draft;
$element = $task->getDefinition(true);
$screenFields = $screenVersion ? $screenVersion->screenFilteredFields() : [];
$taskDraftsEnabled = TaskDraft::draftsEnabled();
Expand Down
Loading

0 comments on commit e84bc26

Please sign in to comment.