Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/release-2024-fall' into bugfix/F…
Browse files Browse the repository at this point in the history
…OUR-19638-fall
  • Loading branch information
pmPaulis committed Oct 21, 2024
2 parents ce9c655 + 6ed946d commit 4d51989
Show file tree
Hide file tree
Showing 36 changed files with 3,291 additions and 2,487 deletions.
10 changes: 8 additions & 2 deletions ProcessMaker/Http/Controllers/Api/DevLinkController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Validation\Rule;
use ProcessMaker\Http\Controllers\Controller;
use ProcessMaker\Http\Resources\ApiCollection;
use ProcessMaker\Jobs\DevLinkInstall;
use ProcessMaker\Models\Bundle;
use ProcessMaker\Models\DevLink;
use ProcessMaker\Models\Setting;
Expand Down Expand Up @@ -153,9 +154,14 @@ public function deleteBundle(Bundle $bundle)
$bundle->delete();
}

public function installRemoteBundle(DevLink $devLink, $remoteBundleId)
public function installRemoteBundle(Request $request, DevLink $devLink, $remoteBundleId)
{
return $devLink->installRemoteBundle($remoteBundleId);
DevLinkInstall::dispatch(
$request->user()->id,
$devLink->id,
$remoteBundleId,
'update'
);
}

public function exportLocalBundle(Bundle $bundle)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class UserConfigurationController extends Controller
'isMenuCollapse' => true,
],
'cases' => [
'isMenuCollapse' => true,
'isMenuCollapse' => false,
],
'requests' => [
'isMenuCollapse' => true,
Expand Down
6 changes: 4 additions & 2 deletions ProcessMaker/ImportExport/Importer.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public function doImport($existingAssetInDatabase = null, $importingFromTemplate

$count = count(Arr::where($this->manifest->all(), fn ($exporter) => $exporter->mode !== 'discard'));
$this->logger->log("Importing {$count} assets");
foreach ($this->manifest->all() as $exporter) {
foreach ($this->manifest->all() as $uuid => $exporter) {
$this->logger->setStatus('saving', $uuid);
if ($exporter->mode !== 'discard') {
$this->logger->log('Importing ' . get_class($exporter->model));
if ($exporter->disableEventsWhenImporting) {
Expand All @@ -66,7 +67,8 @@ public function doImport($existingAssetInDatabase = null, $importingFromTemplate
Schema::enableForeignKeyConstraints();

// Now, run the import method in each Exporter class
foreach ($this->manifest->all() as $exporter) {
foreach ($this->manifest->all() as $uuid => $exporter) {
$this->logger->setStatus('associating', $uuid);
if ($exporter->mode !== 'discard') {
$this->logger->log('Associating ' . get_class($exporter->model));
$exporter->runImport($existingAssetInDatabase, $importingFromTemplate);
Expand Down
41 changes: 35 additions & 6 deletions ProcessMaker/ImportExport/Logger.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ class Logger

private $warnings = [];

private int $totalSteps = 1;

private int $currentStep = 1;

public function __construct($userId = null)
{
$this->pid = getmypid();
Expand Down Expand Up @@ -51,9 +55,14 @@ public function error($message)
$this->dispatch('error', $message);
}

public function status($message)
{
$this->dispatch('status', $message);
}

public function exception($e)
{
$this->dispatch('error', get_class($e) . ': ' . $e->getMessage());
$this->dispatch('error', get_class($e) . ': ' . $e->getMessage() . ' ' . $e->getTraceAsString());
}

private function dispatch($type, $message, $additionalParams = [])
Expand All @@ -71,11 +80,6 @@ public function addWarning($message)
$this->warnings[] = $message;
}

public function getWarnings()
{
return $this->warnings;
}

private function logToFile($type, $message, $additionalParams = [])
{
$params = '';
Expand All @@ -85,4 +89,29 @@ private function logToFile($type, $message, $additionalParams = [])
$datetime = date('Y-m-d H:i:s');
Storage::append(ImportV2::LOG_PATH, "[$this->pid] [$this->userId] [$datetime] [$type] $message" . $params);
}

public function setSteps($payloads)
{
$this->currentStep = 0;
$this->totalSteps = 0;

foreach ($payloads as $payload) {
// Multiply by 2 since each has a "saving" and an "associating" stage.
$this->totalSteps += count($payload['export']) * 2;
}
}

public function setStatus($type, $item = '')
{
if ($type === 'done') {
$this->dispatch('status', 'done', $this->warnings);

return;
}

$this->status(ucfirst($type) . ' ' . $item);
$this->currentStep++;

$this->dispatch('progress', round(($this->currentStep / $this->totalSteps) * 100));
}
}
62 changes: 62 additions & 0 deletions ProcessMaker/Jobs/DevLinkInstall.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace ProcessMaker\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Cache;
use ProcessMaker\ImportExport\Logger;
use ProcessMaker\Jobs\ImportV2;
use ProcessMaker\Models\DevLink;
use Throwable;

class DevLinkInstall implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

public $tries = 1;

public $maxExceptions = 1;

public $devLink = null;

public function __construct(
public int $userId,
public int $devLinkId,
public int $bundleId,
public string $importMode = 'update',
) {
}

/**
* Execute the job.
*/
public function handle(): void
{
$this->devLink = DevLink::findOrFail($this->devLinkId);
$this->devLink->logger = new Logger($this->userId);

$lock = Cache::lock(ImportV2::CACHE_LOCK_KEY, ImportV2::RELEASE_LOCK_AFTER);

if ($lock->get()) {
$this->devLink->logger->clear();
$this->devLink->installRemoteBundle($this->bundleId);
$lock->release();
} else {
// Don't throw exception because that will unlock the running job
$this->devLink->logger->error('Already running!');
}
}

public function failed(Throwable $exception): void
{
(new Logger($this->userId))->exception($exception);

// Unlock the job
// We can't use $this->lock->release() here because this is run in a new instance
Cache::lock(ImportV2::CACHE_LOCK_KEY)->forceRelease();
}
}
32 changes: 21 additions & 11 deletions ProcessMaker/Managers/PackageManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,29 @@ public function remove($name)
unset($this->packages[$name]);
}

/**
* Get all json translations registered from packages
*
* @return array
*/
public function getJsonTranslationsRegistered() : array
{
return app()->translator->getLoader()->jsonPaths();
}

/**
* Look into current packages and create a language file for each one
*
*
* @param $code The language code to create a language file of
*/
public function createLanguageFile($code)
{
// Get current packages
$packages = app()->translator->getLoader()->jsonPaths();
$packages = $this->getJsonTranslationsRegistered();

foreach ($packages as $package) {
if (!file_exists("{$package}/en.json")) {
return ;
return;
} else {
// If language does not exist, clone en.json without values
if (!file_exists("{$package}/{$code}.json")) {
Expand All @@ -78,8 +88,8 @@ public function createLanguageFile($code)
$value = '';
}

// Get empty file with only keys, empty values
$baseFile = json_encode($data);
// Get empty file with only keys, empty values
$baseFile = json_encode($data, JSON_PRETTY_PRINT);

// Create file in package
file_put_contents("{$package}/{$code}.json", $baseFile);
Expand All @@ -90,20 +100,20 @@ public function createLanguageFile($code)

/**
* Delete a language file form all currently installed packages
*
* @param $code The language code of which to delete the language file
*
* @param $code The language code of which to delete the language file
*/
public function deleteLanguageFile($code)
{
// Get current packages
$packages = app()->translator->getLoader()->jsonPaths();
// Get current packages
$packages = $this->getJsonTranslationsRegistered();

foreach ($packages as $package) {
foreach ($packages as $package) {
// Check if file exists in package
if (File::exists("{$package}/{$code}.json")) {
// Delete file
File::delete("{$package}/{$code}.json");
}
}
}
}
}
21 changes: 11 additions & 10 deletions ProcessMaker/Models/DevLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ public function remoteAssetsListing($request)

public function installRemoteBundle($bundleId)
{
if (!$this->logger) {
$this->logger = new Logger();
}

$this->logger->status(__('Downloading bundle from remote instance'));

$bundleInfo = $this->client()->get(
route('api.devlink.local-bundle', ['bundle' => $bundleId], false)
)->json();
Expand All @@ -118,34 +124,29 @@ public function installRemoteBundle($bundleId)
[
'name' => $bundleInfo['name'],
'published' => $bundleInfo['published'],
'locked' => $bundleInfo['locked'],
'version' => $bundleInfo['version'],
]
);

$this->logger->status('Installing bundle on the this instance');
$this->logger->setSteps($bundleExport['payloads']);

$assets = [];
foreach ($bundleExport['payloads'] as $payload) {
$assets[] = $this->import($payload);
}

$this->logger->status('Syncing bundle assets');
$bundle->syncAssets($assets);

return [
'warnings_devlink' => $this->logger->getWarnings(),
];
$this->logger->setStatus('done');
}

private function import(array $payload)
{
if (!$this->logger) {
$this->logger = new Logger();
}

$importer = new Importer($payload, new Options([]), $this->logger);
$manifest = $importer->doImport();

$manifest[$payload['root']]->model['warnings_devlink'] = $importer->logger->getWarnings();

return $manifest[$payload['root']]->model;
}

Expand Down
1 change: 1 addition & 0 deletions ProcessMaker/Repositories/CaseRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public function update(ExecutionInstanceInterface $instance, TokenInterface $tok
]);

$this->case->case_title = $instance->case_title;
$this->case->case_title_formatted = $instance->case_title_formatted;
$this->case->case_status = $instance->status === CaseStatusConstants::ACTIVE ? CaseStatusConstants::IN_PROGRESS : $instance->status;
$this->case->request_tokens = CaseUtils::storeRequestTokens($this->case->request_tokens, $token->getKey());
$this->case->tasks = CaseUtils::storeTasks($this->case->tasks, $taskData);
Expand Down
7 changes: 6 additions & 1 deletion ProcessMaker/Repositories/CaseUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,12 @@ public static function storeRequestTokens(Collection $requestTokens, ?int $token
*/
public static function storeTasks(Collection $tasks, ?array $taskData = []): Collection
{
if (in_array($taskData['element_type'], self::ALLOWED_ELEMENT_TYPES) && !empty($taskData) && array_key_exists('id', $taskData) && array_key_exists('element_id', $taskData) && array_key_exists('name', $taskData) && array_key_exists('process_id', $taskData)) {
$requiredKeys = ['id', 'element_id', 'name', 'process_id', 'element_type'];

if (
!empty($taskData) && !array_diff($requiredKeys, array_keys($taskData))
&& in_array($taskData['element_type'], self::ALLOWED_ELEMENT_TYPES)
) {
unset($taskData['element_type']);
$tasks->push($taskData);
}
Expand Down
15 changes: 9 additions & 6 deletions resources/js/admin/devlink/components/AssetListing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@ const dateFormatter = (value) => {
const fields = [
{
key: 'id',
label: 'ID'
label: vue.$t('ID'),
},
{
key: typeConfig?.nameField || 'name',
label: 'Name'
label: vue.$t('Name'),
},
{
key: 'created_at',
label: 'Created',
label: vue.$t('Created'),
formatter: dateFormatter,
},
{
key: 'updated_at',
label: 'Last Modified',
label: vue.$t('Last Modified'),
formatter: dateFormatter,
},
{
Expand All @@ -54,7 +54,10 @@ const closeModal = () => {
};
const install = (asset) => {
vue.$bvModal.msgBoxConfirm('Are you sure you want to install this asset onto this instance?').then((confirm) => {
vue.$bvModal.msgBoxConfirm(vue.$t('Are you sure you want to install this asset onto this instance?'), {
okTitle: vue.$t('Ok'),
cancelTitle: vue.$t('Cancel')
}).then((confirm) => {
if (confirm) {
const params = {
class: typeConfig.class,
Expand All @@ -63,7 +66,7 @@ const install = (asset) => {
ProcessMaker.apiClient
.post(`/devlink/${route.params.id}/install-remote-asset`, params)
.then((response) => {
window.ProcessMaker.alert('Asset successfully installed', "success");
window.ProcessMaker.alert(vue.$t('Asset successfully installed'), "success");
warnings.value = response.data.warnings_devlink;
if (warnings.value.length > 0) {
showModal();
Expand Down
4 changes: 2 additions & 2 deletions resources/js/admin/devlink/components/Assets.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ onMounted(() => {
</div>
<!-- Content -->
<div class="content">
<h3>{{ type.name }}</h3>
<h3>{{ $t(type.name) }}</h3>
</div>
<!-- Button -->
<div class="button-container">
<button @click.prevent="navigate(type)" class="view-button">
View
{{ $t('View') }}
</button>
</div>
</div>
Expand Down
Loading

0 comments on commit 4d51989

Please sign in to comment.