Merged in release/3.5.0 (pull request #7389)

Release/3.5.0

Approved-by: Julio Cesar Laura Avendaño <contact@julio-laura.com>
This commit is contained in:
Paula Quispe
2020-07-03 18:55:56 +00:00
committed by Julio Cesar Laura Avendaño
46 changed files with 5486 additions and 396 deletions

9
Rakefile Normal file → Executable file
View File

@@ -1,5 +1,6 @@
require 'rubygems'
require 'json'
desc "Default Task - Build Library"
task :default => [:required] do
Rake::Task['build'].execute
@@ -67,6 +68,11 @@ task :build => [:required] do
mafeHash = getHash(Dir.pwd + "/vendor/colosa/MichelangeloFE")
pmdynaformHash = getHash(Dir.pwd + "/vendor/colosa/pmDynaform")
puts "Building file: Task Scheduler".cyan
system "npm run build --prefix #{Dir.pwd}/vendor/colosa/taskscheduler"
system "cp -Rf #{Dir.pwd}/vendor/colosa/taskscheduler/taskscheduler #{targetDir}/taskscheduler"
system "cp #{Dir.pwd}/vendor/colosa/taskscheduler/public/index.html #{targetDir}/taskscheduler"
hashVendors = pmuiHash+"-"+mafeHash
## Building minified JS Files
puts "Building file: " + "/js/mafe-#{hashVendors}.js".cyan
@@ -463,5 +469,4 @@ end
def getLog
output = `git log -30 --pretty='[%cr] %h %d %s <%an>' --no-merges`
return output
end
end

View File

@@ -0,0 +1,99 @@
<?php
namespace App\Console\Commands;
use Illuminate\Support\Carbon;
use Illuminate\Console\Scheduling\ScheduleRunCommand as BaseCommand;
use Maveriks\WebApplication;
use ProcessMaker\Model\TaskScheduler;
class ScheduleRunCommand extends BaseCommand
{
use AddParametersTrait;
/**
* Create a new command instance.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
public function __construct(\Illuminate\Console\Scheduling\Schedule $schedule)
{
$this->startedAt = Carbon::now();
$this->signature = "schedule:run";
$this->signature .= "
{--workspace=workflow : Workspace to use.}
{--user=apache : Operating system's user who executes the crons.}
{--processmakerPath=./ : ProcessMaker path.}
";
$this->description .= ' (ProcessMaker has extended this command)';
parent::__construct($schedule);
}
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
$that = $this;
$workspace = $this->option('workspace');
$user = $this->option('user');
if (!empty($workspace)) {
$webApplication = new WebApplication();
$webApplication->setRootDir($this->option('processmakerPath'));
$webApplication->loadEnvironment($workspace, false);
}
TaskScheduler::all()->each(function ($p) use ($that, $user) {
if ($p->enable == 1) {
$starting = isset($p->startingTime) ? $p->startingTime : "0:00";
$ending = isset($p->startingTime) ? $p->endingTime : "23:59";
$timezone = isset($p->timezone) && $p->timezone != "" ? $p->timezone : date_default_timezone_get();
$body = str_replace(" -c"," " . $user . " -c", $p->body);
$that->schedule->exec($body)->cron($p->expression)->between($starting, $ending)->timezone($timezone)->when(function () use ($p) {
$now = Carbon::now();
$result = false;
$datework = Carbon::createFromFormat('Y-m-d H:i:s', $p->last_update);
if (isset($p->everyOn)) {
switch ($p->interval) {
case "day":
$interval = $now->diffInDays($datework);
$result = ($interval !== 0 && ($interval % intval($p->everyOn)) == 0);
break;
case "week":
$diff = $now->diffInDays($datework);
if ($diff % (intval($p->everyOn) * 7) < 7 && $diff % (intval($p->everyOn) * 7) >= 0) {
$result = true;
} else {
$result = false;
}
break;
case "month":
$interval = $now->diffInMonths($datework);
if ($interval % intval($p->everyOn) == 0) {
$result = true;
} else {
$result = false;
}
break;
case "year":
$interval = $now->diffInYears($datework);
if ($interval % intval($p->everyOn) == 0) {
$result = true;
} else {
$result = false;
}
break;
}
return $result;
}
return true;
});
}
});
parent::handle();
}
}

View File

@@ -22,6 +22,10 @@
{
"type": "git",
"url": "git@bitbucket.org:colosa/pmui.git"
},
{
"type": "git",
"url": "git@bitbucket.org:colosa/taskscheduler.git"
}
],
"minimum-stability": "dev",
@@ -31,9 +35,10 @@
"laravel/framework": "5.7.*",
"luracast/restler": "^3.0",
"bshaffer/oauth2-server-php": "v1.0",
"colosa/pmui": "release/3.4.8-dev",
"colosa/michelangelofe": "release/3.4.8-dev",
"colosa/pmdynaform": "release/3.4.8-dev",
"colosa/pmui": "release/3.5.0-dev",
"colosa/michelangelofe": "release/3.5.0-dev",
"colosa/pmdynaform": "release/3.5.0-dev",
"colosa/taskscheduler": "release/1.0.0-dev",
"google/apiclient": "1.1.6",
"dapphp/securimage": "^3.6",
"psr/log": "1.0.0",
@@ -54,7 +59,8 @@
"league/oauth2-client": "^2.4",
"league/oauth2-google": "^3.0",
"tecnickcom/tcpdf": "6.3.*",
"fzaninotto/faker": "^1.7"
"fzaninotto/faker": "^1.7",
"predis/predis": "1.1.1"
},
"require-dev": {
"guzzlehttp/guzzle": "^6.3",

722
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,7 @@ return [
Laravel\Tinker\TinkerServiceProvider::class,
Illuminate\Notifications\NotificationServiceProvider::class,
Illuminate\Bus\BusServiceProvider::class,
Illuminate\Redis\RedisServiceProvider::class,
],
'aliases' => [

View File

@@ -76,6 +76,12 @@ return [
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'cache' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_CACHE_DB', 1),
],
],
],

View File

@@ -0,0 +1,27 @@
<?php
/**
* Model factory for a task scheduler
*/
use Faker\Generator as Faker;
$factory->define(\ProcessMaker\Model\TaskScheduler::class, function (Faker $faker) {
return [
'id' => G::generateUniqueID(),
'title' => $faker->title,
'startingTime' => $faker->dateTime(),
'endingTime' => $faker->dateTime(),
'everyOn' => "",
'interval' => "",
'description' => "",
'expression' => "",
'body' => "",
'type' => "",
'category' => "emails_notifications", //emails_notifications, case_actions, plugins, processmaker_sync
'system' => "",
'timezone' => "",
'enable' => "",
'creation_date' => $faker->dateTime(),
'last_update' => $faker->dateTime()
];
});

View File

@@ -615,6 +615,11 @@ class RBAC
'PER_UID' => '00000000000000000000000000000068',
'PER_CODE' => 'PM_FOLDERS_OWNER',
'PER_NAME' => 'View Your Folders'
],
[
'PER_UID' => '00000000000000000000000000000069',
'PER_CODE' => 'PM_TASK_SCHEDULER_ADMIN',
'PER_NAME' => 'View Task Scheduler'
]
];

4
rbac/engine/data/mysql/insert.sql Normal file → Executable file
View File

@@ -68,6 +68,9 @@ INSERT INTO `RBAC_PERMISSIONS` VALUES
('00000000000000000000000000000067','PM_SETUP_LOG_FILES','2018-02-06 00:00:00','2018-02-06 00:00:00',1,'00000000000000000000000000000002'),
('00000000000000000000000000000068','PM_FOLDERS_OWNER','2020-01-29 00:00:00','2020-01-29 00:00:00',1,'00000000000000000000000000000002');
INSERT INTO `RBAC_PERMISSIONS` VALUES
('00000000000000000000000000000069','PM_TASK_SCHEDULER_ADMIN','2020-01-29 00:00:00','2020-01-29 00:00:00',1,'00000000000000000000000000000002');
INSERT INTO `RBAC_ROLES` VALUES
('00000000000000000000000000000001','','00000000000000000000000000000001','RBAC_ADMIN','2007-07-31 19:10:22','2007-08-03 12:24:36',1),
('00000000000000000000000000000002','','00000000000000000000000000000002','PROCESSMAKER_ADMIN','2007-07-31 19:10:22','2007-08-03 12:24:36',1),
@@ -144,6 +147,7 @@ INSERT INTO `RBAC_ROLES_PERMISSIONS` VALUES
('00000000000000000000000000000002','00000000000000000000000000000065'),
('00000000000000000000000000000002','00000000000000000000000000000067'),
('00000000000000000000000000000002','00000000000000000000000000000068'),
('00000000000000000000000000000002','00000000000000000000000000000069'),
('00000000000000000000000000000003','00000000000000000000000000000001'),
('00000000000000000000000000000003','00000000000000000000000000000005'),
('00000000000000000000000000000003','00000000000000000000000000000040'),

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
{
"type": "dropdown",
"variable": "",
"var_uid": "",
"dataType": "",
"protectedValue": false,
"id": "stateDropdown",
"name": "stateDropdown",
"label": "State use form",
"tabIndex": "",
"defaultValue": "BO",
"placeholder": "BO",
"hint": "",
"ariaLabel": "",
"required": false,
"requiredFieldErrorMessage": "",
"mode": "parent",
"datasource": "database",
"dbConnection": "workflow",
"dbConnectionLabel": "PM Database",
"sql": "SELECT IS_UID, IS_NAME FROM ISO_SUBDIVISION \nWHERE IC_UID = @?countryDropdown ORDER BY IS_NAME",
"memoryCache": false,
"dataVariable": "",
"options": [
{
"value": "val1",
"label": "val1"
}
],
"columnWidth": "25",
"width": 100,
"title": "State use form",
"var_name": "gridVar003"
}

View File

@@ -13,15 +13,13 @@ use Tests\TestCase;
*/
class PmDynaformTest extends TestCase
{
use DatabaseTransactions;
/**
* Constructor of the class.
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
public function __construct($name = null, array $data = [], $dataName = '')
protected function setUp()
{
parent::__construct($name, $data, $dataName);
parent::setUp();
$_SERVER["REQUEST_URI"] = "";
if (!defined("DB_ADAPTER")) {
define("DB_ADAPTER", "mysql");
@@ -38,15 +36,7 @@ class PmDynaformTest extends TestCase
if (!defined("DB_PASS")) {
define("DB_PASS", env('DB_PASSWORD'));
}
}
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
parent::setUp();
Dynaform::truncate();
}
/**
@@ -1042,6 +1032,156 @@ class PmDynaformTest extends TestCase
$reflectionMethod->invokeArgs($dynaform, [&$a]);
$this->assertInstanceOf('ReflectionMethod', $reflectionMethod);
}
/**
* This verify method getValuesDependentFields.
* @test
* @covers PmDynaform::jsonr()
* @covers PmDynaform::getValuesDependentFields()
*/
public function it_should_test_get_values_dependent_fields()
{
$pathData = PATH_TRUNK . "/tests/resources/dynaform2.json";
$data = file_get_contents($pathData);
$json = json_decode($data);
$pathData2 = PATH_TRUNK . "/tests/resources/fieldDynaform.json";
$data2 = file_get_contents($pathData2);
$json2 = json_decode($data2);
$dynaform = new PmDynaform();
$dynaform->record = [
'DYN_CONTENT' => $data
];
$dynaform->fields = [
'APP_DATA' => [
'stateDropdown' => 'stateDropdown'
]
];
$reflection = new ReflectionClass($dynaform);
$reflectionMethod = $reflection->getMethod('getValuesDependentFields');
$reflectionMethod->setAccessible(true);
$result = $reflectionMethod->invokeArgs($dynaform, [&$json2]);
$this->assertArrayHasKey('countryDropdown', $result);
}
/**
* This verify method searchField.
* @test
* @covers PmDynaform::jsonr()
* @covers PmDynaform::searchField()
*/
public function it_should_test_search_field()
{
$pathData = PATH_TRUNK . "/tests/resources/dynaform2.json";
$data = file_get_contents($pathData);
$json = json_decode($data);
$pathData2 = PATH_TRUNK . "/tests/resources/fieldDynaform.json";
$data2 = file_get_contents($pathData2);
$json2 = json_decode($data2);
$dynaform = factory(Dynaform::class)->create([
'DYN_CONTENT' => $data
]);
factory(Dynaform::class)->create([
'DYN_CONTENT' => $data,
'PRO_UID' => $dynaform->PRO_UID
]);
$dynUid = $dynaform->DYN_UID;
$fieldId = 'stateDropdown';
$proUid = '';
$and = [];
$dynaform = new PmDynaform();
$result = $dynaform->searchField($dynUid, $fieldId, $proUid, $and);
$this->assertObjectHasAttribute('id', $result);
$this->assertEquals($result->id, 'stateDropdown');
}
/**
* This verify method replaceDataField.
* @test
* @covers PmDynaform::jsonr()
* @covers PmDynaform::replaceDataField()
*/
public function it_should_test_replace_data_field()
{
$sql = "SELECT IS_UID, IS_NAME FROM ISO_SUBDIVISION WHERE IC_UID = '@?countryDropdown' ORDER BY IS_NAME";
$data = [
'countryDropdown' => 'BO'
];
$dynaform = new PmDynaform();
$reflection = new ReflectionClass($dynaform);
$reflectionMethod = $reflection->getMethod('replaceDataField');
$reflectionMethod->setAccessible(true);
$result = $reflectionMethod->invokeArgs($dynaform, [&$sql, $data]);
$expected = "SELECT IS_UID, IS_NAME FROM ISO_SUBDIVISION WHERE IC_UID = 'BO' ORDER BY IS_NAME";
$this->assertEquals($expected, $result);
}
/**
* This verify method completeAdditionalHelpInformationOnControls.
* @test
* @covers PmDynaform::jsonr()
* @covers PmDynaform::completeAdditionalHelpInformationOnControls()
*/
public function it_should_test_complete_additional_help_information_on_controls()
{
$pathData = PATH_TRUNK . "/tests/resources/dynaform2.json";
$data = file_get_contents($pathData);
$json = json_decode($data);
$dynaform = new PmDynaform();
$reflection = new ReflectionClass($dynaform);
$reflectionMethod = $reflection->getMethod('completeAdditionalHelpInformationOnControls');
$reflectionMethod->setAccessible(true);
$reflectionMethod->invokeArgs($dynaform, [&$json]);
$this->assertInstanceOf('ReflectionMethod', $reflectionMethod);
}
/**
* This verify method jsonsf.
* @test
* @covers PmDynaform::jsonr()
* @covers PmDynaform::jsonsf()
*/
public function it_should_test_jsonsf()
{
$pathData = PATH_TRUNK . "/tests/resources/dynaform2.json";
$data = file_get_contents($pathData);
$json = json_decode($data);
$pathData2 = PATH_TRUNK . "/tests/resources/fieldDynaform.json";
$data2 = file_get_contents($pathData2);
$json2 = json_decode($data2);
$dynaform = factory(Dynaform::class)->create([
'DYN_CONTENT' => $data
]);
factory(Dynaform::class)->create([
'DYN_CONTENT' => $data,
'PRO_UID' => $dynaform->PRO_UID
]);
$id = 'stateDropdown';
$for = 'id';
$and = ['gridName' => 'gridVar003'];
$dynaform = new PmDynaform();
$reflection = new ReflectionClass($dynaform);
$reflectionMethod = $reflection->getMethod('jsonsf');
$reflectionMethod->setAccessible(true);
$result = $reflectionMethod->invokeArgs($dynaform, [&$json, $id, $for, $and]);
$this->assertObjectHasAttribute('id', $result);
$this->assertEquals($result->id, 'stateDropdown');
}
}
// Dummy function used for the coverture

View File

@@ -0,0 +1,30 @@
<?php
namespace ProcessMaker\BusinessModel;
use ProcessMaker\BusinessModel\Lists;
use ProcessMaker\Model\User;
use Tests\TestCase;
/**
* Lists Tests
*/
class ListsTest extends TestCase
{
/**
* It tests the construct of the Lists class
*
* @covers \ProcessMaker\BusinessModel\Lists
* @test
*/
public function it_should_test_the_lists_construct()
{
$user = factory(User::class)->create();
$list = new Lists();
$res = $list->getList('inbox', ['userId' => $user->USR_UID]);
$this->assertEmpty($res['data']);
$this->assertEquals(0, $res['totalCount']);
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace ProcessMaker\BusinessModel;
use ProcessMaker\BusinessModel\TaskSchedulerBM;
use ProcessMaker\Model\TaskScheduler;
use Tests\TestCase;
class TaskSchedulerBMTest extends TestCase
{
/**
* Test getSchedule method
*
* @covers \ProcessMaker\BusinessModel\TaskSchedulerBM::getSchedule
* @test
*/
public function it_should_test_get_schedule_method()
{
TaskScheduler::truncate();
$obj = new TaskSchedulerBM();
$res = $obj->getSchedule('emails_notifications');
$this->assertNotEmpty($res);
factory(TaskScheduler::class)->create();
$res = $obj->getSchedule('emails_notifications');
$this->assertNotEmpty(1, $res);
$res = $obj->getSchedule('case_actions');
$this->assertEmpty(0, $res);
$res = $obj->getSchedule('plugins');
$this->assertEmpty(0, $res);
$res = $obj->getSchedule('processmaker_sync');
$this->assertEmpty(0, $res);
$res = $obj->getSchedule(null);
$this->assertNotEmpty(1, $res);
}
/**
* Test saveSchedule method
*
* @covers \ProcessMaker\BusinessModel\TaskSchedulerBM::saveSchedule
* @test
*/
public function it_should_test_save_schedule_method()
{
$obj = new TaskSchedulerBM();
$scheduler = factory(TaskScheduler::class)->create();
$request_data = [
"id" => $scheduler->id,
"title" => "ProcessMaker Events",
"enable" => "1",
"service" => "events",
"category" => "case_actions",
"file" => "workflow/engine/bin/cron.php",
"startingTime" => "0:00",
"endingTime" => "23:59",
"expression" => "* * * * *",
"description" => "Unpauses any case whose pause time has expired",
"timezone" => "",
"everyOn" => "",
'interval' => "",
'body' => "",
'type' => "",
'system' => "",
'creation_date' => date(''),
'last_update' => date('')
];
$res = $obj->saveSchedule($request_data);
$this->assertEquals($scheduler->id , $res->id);
}
/**
* Test generateInitialData method
*
* @covers \ProcessMaker\BusinessModel\TaskSchedulerBM::generateInitialData
* @test
*/
public function it_should_test_generate_initial_data_method()
{
TaskScheduler::truncate();
$r = TaskScheduler::all()->toArray();
$this->assertEmpty($r);
$obj = new TaskSchedulerBM();
$obj->generateInitialData();
$r = TaskScheduler::all()->toArray();
$this->assertNotEmpty($r);
}
}

View File

@@ -1,8 +1,12 @@
<?php
namespace ProcessMaker\BusinessModel;
use Exception;
use G;
use ProcessMaker\BusinessModel\Variable;
use ProcessMaker\Model\Application;
use ProcessMaker\Model\Dynaform;
use ProcessMaker\Model\Process;
use ProcessMaker\Model\ProcessVariables;
use Tests\TestCase;
@@ -12,6 +16,7 @@ use Tests\TestCase;
*/
class VariableTest extends TestCase
{
/**
* Test it create variables related to the process
*
@@ -23,10 +28,9 @@ class VariableTest extends TestCase
$process = factory(Process::class)->create();
factory(ProcessVariables::class)->create([
'PRJ_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
]
);
'PRJ_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
]);
$properties = [
'VAR_UID' => G::generateUniqueID(),
'VAR_NAME' => 'var_test',
@@ -69,10 +73,9 @@ class VariableTest extends TestCase
{
$process = factory(Process::class)->create();
factory(ProcessVariables::class)->create([
'PRJ_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
]
);
'PRJ_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
]);
$properties = [
'VAR_UID' => G::generateUniqueID(),
'VAR_NAME' => '',
@@ -101,10 +104,9 @@ class VariableTest extends TestCase
{
$process = factory(Process::class)->create();
factory(ProcessVariables::class)->create([
'PRJ_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
]
);
'PRJ_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
]);
$properties = [
'VAR_UID' => G::generateUniqueID(),
'VAR_NAME' => 'var_test',
@@ -133,10 +135,9 @@ class VariableTest extends TestCase
{
$process = factory(Process::class)->create();
factory(ProcessVariables::class)->create([
'PRJ_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
]
);
'PRJ_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
]);
$properties = [
'VAR_UID' => G::generateUniqueID(),
'VAR_NAME' => 'var_test',
@@ -166,10 +167,9 @@ class VariableTest extends TestCase
$process = factory(Process::class)->create();
factory(ProcessVariables::class)->create([
'PRJ_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
]
);
'PRJ_UID' => $process->PRO_UID,
'PRO_ID' => $process->PRO_ID,
]);
$variable = new Variable();
$res = $variable->getVariables($process->PRO_UID);
$this->assertNotEmpty($res);
@@ -227,4 +227,49 @@ class VariableTest extends TestCase
$res = $variable->getVariablesByType($process->PRO_UID, 2, null, null, 'other');
$this->assertEmpty($res);
}
/**
* This verify method executeSqlControl.
* @test
* @covers \ProcessMaker\BusinessModel\Variable::executeSqlControl()
*/
public function it_should_test_execute_sql_control()
{
$pathData = PATH_TRUNK . "/tests/resources/dynaform2.json";
$data = file_get_contents($pathData);
$json = json_decode($data);
$dynaform = factory(Dynaform::class)->create([
'DYN_CONTENT' => $data
]);
$application = factory(Application::class)->create();
$proUid = '';
$params = [
'app_uid' => $application->APP_UID,
'countryDropdown1' => 'BO',
'dyn_uid' => $dynaform->DYN_UID,
'field_id' => 'stateDropdown',
'grid_name' => 'gridVar004',
];
$_SERVER["REQUEST_URI"] = '';
$variable = new Variable();
$result = $variable->executeSqlControl($proUid, $params);
$this->assertNotEmpty($result);
}
/**
* This verify method executeSqlControl try exception.
* @test
* @covers \ProcessMaker\BusinessModel\Variable::executeSqlControl()
*/
public function it_should_test_execute_sql_control_with_exception()
{
//assert
$this->expectException(Exception::class);
$variable = new Variable();
$result = $variable->executeSqlControl(null, []);
}
}

View File

@@ -396,15 +396,19 @@ class CasesTraitTest extends TestCase
];
$cases = new Cases();
$cases->routeCaseActionByEmail($appUid, $delIndex, $aber, $dynUid, $forms, $remoteAddr, $files);
$result = $cases->routeCaseActionByEmail($appUid, $delIndex, $aber, $dynUid, $forms, $remoteAddr, $files);
//asserts
$this->assertEquals($aber, $result['ABE_REQ_UID']);
$this->assertArrayHasKey('ABE_RES_STATUS', $result);
}
/**
* This test verifies if the ABE form has been completed.
* This test verifies if the ABE form has not been completed and hope for an exception.
* @test
* @covers Cases::routeCaseActionByEmail
*/
public function it_should_verify_if_abe_has_completed()
public function it_should_verify_if_abe_has_not_completed()
{
$delegation1 = factory(Delegation::class)->state('closed')->create();
$abeRequest = factory(AbeRequest::class)->create();
@@ -420,6 +424,7 @@ class CasesTraitTest extends TestCase
$remoteAddr = '127.0.0.1';
$files = [];
//assert exception
$this->expectException(\Exception::class);
$cases = new Cases();
$cases->routeCaseActionByEmail($appUid, $delIndex, $aber, $dynUid, $forms, $remoteAddr, $files);
@@ -446,6 +451,7 @@ class CasesTraitTest extends TestCase
$remoteAddr = '127.0.0.1';
$files = [];
//assert exception
$this->expectException(\Exception::class);
$cases = new Cases();
$cases->routeCaseActionByEmail($appUid, $delIndex, $aber, $dynUid, $forms, $remoteAddr, $files);

View File

@@ -0,0 +1,47 @@
<?php
namespace Tests\unit\workflow\engine\src\ProcessMaker\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use ProcessMaker\Model\Application;
use ProcessMaker\Model\AppNotes;
use Tests\TestCase;
/**
* Class AppNotesTest
*
* @coversDefaultClass \ProcessMaker\Model\AppNotes
*/
class AppNotesTest extends TestCase
{
use DatabaseTransactions;
/**
* Review get cases notes related to the case
*
* @test
*/
public function it_test_get_case_notes()
{
$appNotes = factory(AppNotes::class)->states('foreign_keys')->create();
$notes = new AppNotes();
$res = $notes->getNotes($appNotes->APP_UID);
$this->assertNotEmpty($res);
}
/**
* Review get total cases notes by cases
*
* @test
*/
public function it_test_get_total_case_notes()
{
$application = factory(Application::class)->create();
$appNotes = factory(AppNotes::class, 10)->states('foreign_keys')->create([
'APP_UID' => $application->APP_UID
]);
$notes = new AppNotes();
$total = $notes->getTotal($application->APP_UID);
$this->assertEquals(10, $total);
}
}

View File

@@ -882,7 +882,7 @@ class ActionsByEmailCoreClass extends PMPlugin
}
}
$obj = new PmDynaform($dynUid);
$obj = new PmDynaform(["CURRENT_DYNAFORM" => $dynUid]);
$this->addItemAbeProperties(['CURRENT_DYNAFORM' => $dynUid]);
$file = $obj->printPmDynaformAbe($this->getTaskAbeProperties());
$html = $file;

View File

@@ -22,6 +22,7 @@ class PmDynaform
private $lastQueryError = null;
private $propertiesToExclude = [];
private $sysSys = null;
private $fieldsAppData;
public $credentials = null;
public $displayMode = null;
public $fields = null;
@@ -91,6 +92,7 @@ class PmDynaform
if (is_array($this->fields) && !isset($this->fields["APP_UID"])) {
$this->fields["APP_UID"] = null;
}
$this->fieldsAppData = isset($this->fields["APP_DATA"]) ? $this->fields["APP_DATA"] : [];
//todo: compatibility checkbox
if ($this->record !== null && isset($this->record["DYN_CONTENT"]) && $this->record["DYN_CONTENT"] !== "") {
@@ -338,7 +340,7 @@ class PmDynaform
}
}
}
$sql = G::replaceDataField($json->sql, $dtFields, 'mysql', false);
$sql = $this->replaceDataField($json->sql, $dtFields);
if ($value === "suggest") {
$sql = $this->prepareSuggestSql($sql, $json);
}
@@ -686,6 +688,8 @@ class PmDynaform
$json->dataGridEnvironment = "onDataGridEnvironment";
if (isset($this->fields["APP_DATA"])) {
$dataGridEnvironment = $this->fields["APP_DATA"];
//Grids only access the global variables of 'ProcessMaker', other variables are removed.
$this->fields["APP_DATA"] = Cases::getGlobalVariables($this->fields["APP_DATA"]);
//restore AppData with dataVariable definition, only for columns control
foreach ($columnsDataVariable as $dge) {
if (isset($dataGridEnvironment[$dge])) {
@@ -833,7 +837,12 @@ class PmDynaform
}
}
private function getValuesDependentFields($json)
/**
* Get the values of the dependent references.
* @param object $json
* @return array
*/
private function getValuesDependentFields($json): array
{
if (!isset($this->record["DYN_CONTENT"])) {
return array();
@@ -848,7 +857,7 @@ class PmDynaform
}
if (isset($json->dbConnection) && isset($json->sql)) {
$result = array();
preg_match_all('/\@(?:([\@\%\#\=\!Qq])([a-zA-Z\_]\w*)|([a-zA-Z\_][\w\-\>\:]*)\(((?:[^\\\\\)]*?)*)\))/', $json->sql, $result, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE);
preg_match_all('/\@(?:([\@\%\#\=\?\!Qq])([a-zA-Z\_]\w*)|([a-zA-Z\_][\w\-\>\:]*)\(((?:[^\\\\\)]*?)*)\))/', $json->sql, $result, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE);
$variables = isset($result[2]) ? $result[2] : array();
foreach ($variables as $key => $value) {
//Prevents an infinite cycle. If the name of the variable is used within its own dependent.
@@ -863,7 +872,7 @@ class PmDynaform
}
}
if ($json->dbConnection !== "" && $json->dbConnection !== "none" && $json->sql !== "") {
$sql = G::replaceDataField($json->sql, $data, 'mysql', false);
$sql = $this->replaceDataField($json->sql, $data);
$dt = $this->getCacheQueryData($json->dbConnection, $sql, $json->type);
$row = isset($dt[0]) ? $dt[0] : [];
$index = $json->variable === "" ? $json->id : $json->variable;
@@ -1780,12 +1789,11 @@ class PmDynaform
* @param string $dynUid
* @param string $fieldId
* @param string $proUid
*
* @param array $and
* @return object
*
* @see \ProcessMaker\BusinessModel\Variable::executeSqlControl()
*/
public function searchField($dynUid, $fieldId, $proUid = null)
*/
public function searchField($dynUid, $fieldId, $proUid = null, array $and = [])
{
//get pro_uid if empty
if (empty($proUid)) {
@@ -1828,8 +1836,8 @@ class PmDynaform
}
}
}
return $this->jsonsf($json, $fieldId);
$this->completeAdditionalHelpInformationOnControls($json);
return $this->jsonsf($json, $fieldId, "id", $and);
}
public function searchFieldByName($dyn_uid, $name)
@@ -1846,19 +1854,92 @@ class PmDynaform
return $this->jsonsf($json, $name, "name");
}
private function jsonsf(&$json, $id, $for = "id")
/**
* Replace data field with custom variables.
* @param string $sql
* @param array $data
* @return string
*/
private function replaceDataField(string $sql, array $data): string
{
$textParse = '';
$dbEngine = 'mysql';
$start = 0;
$prefix = '\?';
$pattern = '/\@(?:([' . $prefix . 'Qq\!])([a-zA-Z\_]\w*)|([a-zA-Z\_][\w\-\>\:]*)\(((?:[^\\\\\)]*(?:[\\\\][\w\W])?)*)\))((?:\s*\[[\'"]?\w+[\'"]?\])+|\-\>([a-zA-Z\_]\w*))?/';
$result = preg_match_all($pattern, $sql, $match, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE);
for ($r = 0; $result !== false && $r < $result; $r++) {
$dataGlobal = array_merge($this->fieldsAppData, $data);
if (!isset($dataGlobal[$match[2][$r][0]])) {
$dataGlobal[$match[2][$r][0]] = '';
}
if (!is_array($dataGlobal[$match[2][$r][0]])) {
$textParse = $textParse . substr($sql, $start, $match[0][$r][1] - $start);
$start = $match[0][$r][1] + strlen($match[0][$r][0]);
if (($match[1][$r][0] == '?') && (isset($dataGlobal[$match[2][$r][0]]))) {
$textParse = $textParse . $dataGlobal[$match[2][$r][0]];
continue;
}
}
}
$textParse = $textParse . substr($sql, $start);
$sqlResult = G::replaceDataField($textParse, $data, $dbEngine, false);
return $sqlResult;
}
/**
* complete additional help information on controls.
* @param object $json
*/
private function completeAdditionalHelpInformationOnControls(&$json)
{
foreach ($json as $key => $value) {
$sw1 = is_array($value);
$sw2 = is_object($value);
if ($sw1 || $sw2) {
$val = $this->jsonsf($value, $id, $for);
$this->completeAdditionalHelpInformationOnControls($value);
}
if (!$sw1 && !$sw2) {
if ($key === "type" && ($value === "grid")) {
foreach ($json->columns as $column) {
$column->gridName = $json->id;
}
}
}
}
}
/**
* Gets an element within an object that represents the dynaform. Search is
* done by 'id', 'property' and additional filters.
* @param object $json
* @param string $id
* @param string $for
* @param array $and
* @return mixed
*/
private function jsonsf(&$json, string $id, string $for = "id", array $and = [])
{
foreach ($json as $key => $value) {
$sw1 = is_array($value);
$sw2 = is_object($value);
if ($sw1 || $sw2) {
$val = $this->jsonsf($value, $id, $for, $and);
if ($val !== null) {
return $val;
}
}
if (!$sw1 && !$sw2) {
if ($key === $for && $id === $value) {
$filter = empty($and);
foreach ($and as $keyAnd => $valueAnd) {
$filter = isset($json->{$keyAnd}) && $json->{$keyAnd} === $valueAnd;
if ($filter === false) {
break;
}
}
if ($key === $for && $id === $value && $filter) {
return $json;
}
}

View File

@@ -468,12 +468,13 @@ function evaluateFunction($aGrid, $sExpresion)
* stantard deviation, variance, percentile, count, count distinct
*
* @name PMFTotalCalculation
* @label PMFTotalCalculation Function
* @label PMF TotalCalculation
* @link http://wiki.processmaker.com/index.php/ProcessMaker_Functions#PMFTotalCalculation.28.29
* @param array | $grid | Grid | The input grid.
* @param array | $grid | Grid | The input grid
* @param string (32) | $field | Name of field | The name of the field.
* @param string (32) | $function | Operation.
* @return int|float|array | $result | Result | Result according of the function
* @param string (32) | $function | Operation | More information about the type of calculations can be found in https://wiki.processmaker.com/3.2/ProcessMaker_Functions
*
* @return mixed | $result | Result | Result according of the operation
*
*/
function PMFTotalCalculation($grid, $field, $function)
@@ -3019,13 +3020,13 @@ function PMFUnpauseCase ($caseUid, $delIndex, $userUid)
* @param string(32) | $taskUid | ID of the task | The unique ID of the task.
* @param string(32) | $userUid | ID user | The unique ID of the user who will add note case.
* @param string | $note | Note of the case | Note of the case.
* @param int | $sendMail = 1 | Send mail | Optional parameter. If set to 1, will send an email to all participants in the case.
* @param int | $sendMail = 0 | Send mail | Optional parameter. If set to 1, will send an email to all participants in the case.
* @param array | $files | Array of files | An array of files (full paths) to be attached to the case notes.
*
* @return int | $result | Result of the add a case note | Returns 1 if the note has been added to the case.; otherwise, returns 0 if an error occurred.
*
*/
function PMFAddCaseNote($caseUid, $processUid, $taskUid, $userUid, $note, $sendMail = 1, $files = [])
function PMFAddCaseNote($caseUid, $processUid, $taskUid, $userUid, $note, $sendMail = 0, $files = [])
{
$ws = new WsBase();
$result = $ws->addCaseNote($caseUid, $processUid, $taskUid, $userUid, $note, $sendMail, $files);

View File

@@ -0,0 +1,19 @@
<?php
require_once 'classes/model/om/BaseScheduler.php';
/**
* Skeleton subclass for representing a row from the 'SCHEDULER' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package classes.model
*/
class Scheduler extends BaseScheduler {
} // Scheduler

View File

@@ -0,0 +1,23 @@
<?php
// include base peer class
require_once 'classes/model/om/BaseSchedulerPeer.php';
// include object class
include_once 'classes/model/Scheduler.php';
/**
* Skeleton subclass for performing query and update operations on the 'SCHEDULER' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package classes.model
*/
class SchedulerPeer extends BaseSchedulerPeer {
} // SchedulerPeer

View File

@@ -0,0 +1,102 @@
<?php
require_once 'propel/map/MapBuilder.php';
include_once 'creole/CreoleTypes.php';
/**
* This class adds structure of 'SCHEDULER' table to 'workflow' DatabaseMap object.
*
*
*
* These statically-built map classes are used by Propel to do runtime db structure discovery.
* For example, the createSelectSql() method checks the type of a given column used in an
* ORDER BY clause to know whether it needs to apply SQL to make the ORDER BY case-insensitive
* (i.e. if it's a text column type).
*
* @package workflow.classes.model.map
*/
class SchedulerMapBuilder
{
/**
* The (dot-path) name of this class
*/
const CLASS_NAME = 'classes.model.map.SchedulerMapBuilder';
/**
* The database map.
*/
private $dbMap;
/**
* Tells us if this DatabaseMapBuilder is built so that we
* don't have to re-build it every time.
*
* @return boolean true if this DatabaseMapBuilder is built, false otherwise.
*/
public function isBuilt()
{
return ($this->dbMap !== null);
}
/**
* Gets the databasemap this map builder built.
*
* @return the databasemap
*/
public function getDatabaseMap()
{
return $this->dbMap;
}
/**
* The doBuild() method builds the DatabaseMap
*
* @return void
* @throws PropelException
*/
public function doBuild()
{
$this->dbMap = Propel::getDatabaseMap('workflow');
$tMap = $this->dbMap->addTable('SCHEDULER');
$tMap->setPhpName('Scheduler');
$tMap->setUseIdGenerator(true);
$tMap->addPrimaryKey('ID', 'Id', 'string', CreoleTypes::BIGINT, true, 20);
$tMap->addColumn('TITLE', 'Title', 'string', CreoleTypes::VARCHAR, false, 255);
$tMap->addColumn('STARTINGTIME', 'Startingtime', 'string', CreoleTypes::VARCHAR, false, 100);
$tMap->addColumn('ENDINGTIME', 'Endingtime', 'string', CreoleTypes::VARCHAR, false, 100);
$tMap->addColumn('EVERYON', 'Everyon', 'string', CreoleTypes::VARCHAR, false, 255);
$tMap->addColumn('INTERVAL', 'Interval', 'string', CreoleTypes::VARCHAR, false, 10);
$tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::VARCHAR, false, 255);
$tMap->addColumn('EXPRESSION', 'Expression', 'string', CreoleTypes::VARCHAR, false, 255);
$tMap->addColumn('BODY', 'Body', 'string', CreoleTypes::VARCHAR, false, 255);
$tMap->addColumn('TYPE', 'Type', 'string', CreoleTypes::VARCHAR, false, 255);
$tMap->addColumn('CATEGORY', 'Category', 'string', CreoleTypes::VARCHAR, false, 255);
$tMap->addColumn('SYSTEM', 'System', 'int', CreoleTypes::TINYINT, false, 3);
$tMap->addColumn('TIMEZONE', 'Timezone', 'string', CreoleTypes::VARCHAR, false, 255);
$tMap->addColumn('ENABLE', 'Enable', 'int', CreoleTypes::TINYINT, false, 3);
$tMap->addColumn('CREATION_DATE', 'CreationDate', 'int', CreoleTypes::TIMESTAMP, false, null);
$tMap->addColumn('LAST_UPDATE', 'LastUpdate', 'int', CreoleTypes::TIMESTAMP, false, null);
} // doBuild()
} // SchedulerMapBuilder

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

22
workflow/engine/config/schema.xml Normal file → Executable file
View File

@@ -6030,4 +6030,26 @@
<column name="exception" type="LONGVARCHAR" required="true"/>
<column name="failed_at" type="TIMESTAMP" required="true"/>
</table>
<table name="SCHEDULER" idMethod="native">
<vendor type="mysql">
<parameter name="Engine" value="InnoDB"/>
<parameter name="Collation" value="utf8"/>
</vendor>
<column name="id" type="BIGINT" size="20" required="true" autoIncrement="true" primaryKey="true"/>
<column name="title" type="VARCHAR" size="255" required="false"/>
<column name="startingTime" type="VARCHAR" size="100" required="false"/>
<column name="endingTime" type="VARCHAR" size="100" required="false"/>
<column name="everyOn" type="VARCHAR" size="255" required="false"/>
<column name="interval" type="VARCHAR" size="10" required="false"/>
<column name="description" type="VARCHAR" size="255" required="false"/>
<column name="expression" type="VARCHAR" size="255" required="false"/>
<column name="body" type="VARCHAR" size="255" required="false"/>
<column name="type" type="VARCHAR" size="255" required="false"/>
<column name="category" type="VARCHAR" size="255" required="false"/>
<column name="system" type="TINYINT" size="3" required="false"/>
<column name="timezone" type="VARCHAR" size="255" required="false"/>
<column name="enable" type="TINYINT" size="3" required="false"/>
<column name="creation_date" type="TIMESTAMP" required="false"/>
<column name="last_update" type="TIMESTAMP" required="false"/>
</table>
</database>

4
workflow/engine/content/languages/translation.en Normal file → Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More