Conflicts

This commit is contained in:
Paula Quispe
2020-06-12 19:04:53 -04:00
33 changed files with 2799 additions and 620 deletions

View File

@@ -0,0 +1,14 @@
<?php
namespace App\Jobs;
class GenerateReportTable extends QueuedClosure
{
/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 1;
}

View File

@@ -6,9 +6,37 @@ use ProcessMaker\Model\ProcessVariables;
$factory->define(ProcessVariables::class, function (Faker $faker) { $factory->define(ProcessVariables::class, function (Faker $faker) {
return [ return [
'VAR_UID' => G::generateUniqueID(), 'VAR_UID' => G::generateUniqueID(),
'PRO_ID' => G::generateUniqueID(),
'PRJ_UID' => G::generateUniqueID(), 'PRJ_UID' => G::generateUniqueID(),
'VAR_NAME' => $faker->word, 'VAR_NAME' => $faker->word,
'VAR_FIELD_TYPE' => G::generateUniqueID(), 'VAR_FIELD_TYPE' => G::generateUniqueID(),
'VAR_FIELD_TYPE_ID' => G::generateUniqueID(),
'VAR_FIELD_SIZE' => 10,
'VAR_LABEL' => 'string',
'VAR_DBCONNECTION' => 'workflow',
'VAR_SQL' => '',
'VAR_NULL' => 0,
'VAR_DEFAULT' => '',
'VAR_ACCEPTED_VALUES' => '[]',
'INP_DOC_UID' => ''
];
});
// Create a processVariables with the foreign keys
$factory->state(ProcessVariables::class, 'foreign_keys', function (Faker $faker) {
$types = ['string', 'integer', 'float', 'boolean', 'datetime', 'grid', 'array', 'file', 'multiplefile', 'object'];
$varType = $faker->randomElement($types);
$varTypeId = array_search($varType, $types) + 1;
// Create values in the foreign key relations
$process = factory(\ProcessMaker\Model\Process::class)->create();
return [
'VAR_UID' => G::generateUniqueID(),
'PRO_ID' => $process->PRO_ID,
'PRJ_UID' => $process->PRO_UID,
'VAR_NAME' => $faker->word,
'VAR_FIELD_TYPE' => $varType,
'VAR_FIELD_TYPE_ID' => $varTypeId,
'VAR_FIELD_SIZE' => 10, 'VAR_FIELD_SIZE' => 10,
'VAR_LABEL' => 'string', 'VAR_LABEL' => 'string',
'VAR_DBCONNECTION' => 'workflow', 'VAR_DBCONNECTION' => 'workflow',

View File

@@ -90,6 +90,10 @@
var evaluateFunctionFunction = [evaluateFunction+"($gridName,$Expression)"]; var evaluateFunctionFunction = [evaluateFunction+"($gridName,$Expression)"];
arrayFunctions[evaluateFunction] = evaluateFunctionFunction; arrayFunctions[evaluateFunction] = evaluateFunctionFunction;
var PMFTotalCalculation = "PMFTotalCalculation";
var PMFTotalCalculationFunction = [PMFTotalCalculation + "($gridName, $field, 'function')"];
arrayFunctions[PMFTotalCalculation] = PMFTotalCalculationFunction;
var PMFTaskCase = "PMFTaskCase"; var PMFTaskCase = "PMFTaskCase";
var PMFTaskCaseFunction = [PMFTaskCase+"($caseId)"]; var PMFTaskCaseFunction = [PMFTaskCase+"($caseId)"];
arrayFunctions[PMFTaskCase] = PMFTaskCaseFunction; arrayFunctions[PMFTaskCase] = PMFTaskCaseFunction;
@@ -219,7 +223,7 @@
arrayFunctions[PMFGetCaseNotes] = PMFGetCaseNotesFunction; arrayFunctions[PMFGetCaseNotes] = PMFGetCaseNotesFunction;
var phpPMFunctions = [formatDate,getCurrentDate,getCurrentTime,literalDate,capitalize,lowerCase,upperCase,userInfo,executeQuery,orderGrid, var phpPMFunctions = [formatDate,getCurrentDate,getCurrentTime,literalDate,capitalize,lowerCase,upperCase,userInfo,executeQuery,orderGrid,
evaluateFunction,PMFTaskCase,PMFTaskList,PMFUserList,PMFGroupList,PMFRoleList,PMFCaseList,PMFProcessList,PMFSendVariables,PMFDerivateCase, evaluateFunction, PMFTotalCalculation, PMFTaskCase,PMFTaskList,PMFUserList,PMFGroupList,PMFRoleList,PMFCaseList,PMFProcessList,PMFSendVariables,PMFDerivateCase,
PMFNewCaseImpersonate,PMFNewCase,PMFPauseCase,PMFUnpauseCase,PMFAssignUserToGroup,PMFCreateUser,PMFUpdateUser,PMFInformationUser, PMFNewCaseImpersonate,PMFNewCase,PMFPauseCase,PMFUnpauseCase,PMFAssignUserToGroup,PMFCreateUser,PMFUpdateUser,PMFInformationUser,
generateCode,setCaseTrackerCode,jumping,PMFRedirectToStep,pauseCase,PMFSendMessage,PMFgetLabelOption,PMFGenerateOutputDocument, generateCode,setCaseTrackerCode,jumping,PMFRedirectToStep,pauseCase,PMFSendMessage,PMFgetLabelOption,PMFGenerateOutputDocument,
PMFGetUserEmailAddress,PMFGetNextAssignedUser,PMFDeleteCase,PMFCancelCase,PMFAddInputDocument,PMFAddCaseNote,PMFGetCaseNotes]; PMFGetUserEmailAddress,PMFGetNextAssignedUser,PMFDeleteCase,PMFCancelCase,PMFAddInputDocument,PMFAddCaseNote,PMFGetCaseNotes];

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
{
"data": {
"var_Text1": "5298067855ed6e6893e1424067710552",
"var_Textarea1": "4835809915ed6e6893e14a6079656976",
"var_Dropdown1": "5287566085ed6e6893e14e0083475368",
"var_Suggest1": "4813021735ed6e6893e1520081779769",
"var_DateTime1": "1975-04-04 16:34:22",
"var_String1": "7984290665ed6e6893e15b2092042769",
"var_Integer1": "44"
},
"mapping": [{
"sFieldName": "var_Text1",
"sType": "char"
}, {
"sFieldName": "var_Textarea1",
"sType": "text"
}, {
"sFieldName": "var_Dropdown1",
"sType": "char"
}, {
"sFieldName": "var_Suggest1",
"sType": "char"
}, {
"sFieldName": "var_DateTime1",
"sType": "date"
}, {
"sFieldName": "var_String1",
"sType": "char"
}, {
"sFieldName": "var_Integer1",
"sType": "number"
}]
}

View File

@@ -984,6 +984,64 @@ class PmDynaformTest extends TestCase
// Compare the values // Compare the values
$this->assertEquals($dynaformTitle, $dynaform->DYN_TITLE); $this->assertEquals($dynaformTitle, $dynaform->DYN_TITLE);
} }
/**
* This test should verify the setDependentOptionsForDatetime() method, to
* add the dependentOptions property to the datetime control.
* @test
* @covers PmDynaform::jsonr()
* @covers PmDynaform::setDependentOptionsForDatetime()
*/
public function it_should_test_dependent_options_for_datetime_control()
{
$pathData = PATH_TRUNK . "/tests/resources/dynaform1.json";
$data = file_get_contents($pathData);
$json = json_decode($data);
//assert for not contain property: dependentOptions
$result = json_decode(json_encode($json), JSON_OBJECT_AS_ARRAY);
$fn = function($item) use(&$fn) {
if (is_array($item)) {
if (isset($item['type']) && $item['type'] === 'datetime') {
$this->assertArrayNotHasKey('dependentOptions', $item);
}
array_map($fn, $item);
}
};
array_map($fn, $result);
//assert new property: dependentOptions
$dynaform = new PmDynaform();
$dynaform->jsonr($json);
$result = json_decode(json_encode($json), JSON_OBJECT_AS_ARRAY);
$fn = function($item) use(&$fn) {
if (is_array($item)) {
if (isset($item['type']) && $item['type'] === 'datetime') {
$this->assertArrayHasKey('dependentOptions', $item);
$this->assertArrayHasKey('minDate', $item['dependentOptions']);
$this->assertArrayHasKey('maxDate', $item['dependentOptions']);
$this->assertArrayHasKey('defaultDate', $item['dependentOptions']);
}
array_map($fn, $item);
}
};
array_map($fn, $result);
$dynaform = new PmDynaform();
$reflection = new ReflectionClass($dynaform);
$reflectionMethod = $reflection->getMethod('setDependentOptionsForDatetime');
$reflectionMethod->setAccessible(true);
$a = new stdClass();
$reflectionMethod->invokeArgs($dynaform, [&$a]);
$this->assertInstanceOf('ReflectionMethod', $reflectionMethod);
$a = new stdClass();
$a->type = 'suggest';
$reflectionMethod->invokeArgs($dynaform, [&$a]);
$this->assertInstanceOf('ReflectionMethod', $reflectionMethod);
}
} }
// Dummy function used for the coverture // Dummy function used for the coverture

View File

@@ -0,0 +1,260 @@
<?php
namespace Tests\unit\workflow\engine\classes\PmFunctions;
use Faker\Factory;
use Tests\TestCase;
/**
* Test the PMFTotalCalculation() function
*
* @link https://wiki.processmaker.com/3.1/ProcessMaker_Functions#executeQuery.28.29
*/
class PMFTotalCalculationTest extends TestCase
{
/**
* This tests if the "PMFTotalCalculation" execute correctly the sum
* @test
*/
public function it_must_return_the_sum_of_the_method()
{
$grid = [
'1' => [
"field1" => "Value 1",
"field2" => 2
],
'2' => [
"field1" => "Value 2",
"field2" => 5
],
'3' => [
"field1" => "Value 3",
"field2" => 3
]
];
$field = "field2";
$this->assertEquals(10, PMFTotalCalculation($grid, $field, 'sum'));
}
/**
* This tests if the "PMFTotalCalculation" execute correctly the average
* @test
*/
public function it_must_return_the_average_of_the_method()
{
$grid = [
'1' => [
"field1" => "Value 1",
"field2" => 2
],
'2' => [
"field1" => "Value 2",
"field2" => 5
],
'3' => [
"field1" => "Value 3",
"field2" => 3
]
];
$this->assertEquals(3.3333333333, PMFTotalCalculation($grid, 'field2', 'average'));
}
/**
* This tests if the "PMFTotalCalculation" execute correctly the median
* @test
*/
public function it_must_return_the_median_of_the_method()
{
$grid1 = [
'1' => [
"field1" => "Value 1",
"field2" => 2
],
'2' => [
"field1" => "Value 2",
"field2" => 5
],
'3' => [
"field1" => "Value 3",
"field2" => 3
]
];
$grid2 = [
'1' => [
"field1" => "Value 1",
"field2" => 2
],
'2' => [
"field1" => "Value 2",
"field2" => 5
],
'3' => [
"field1" => "Value 3",
"field2" => 3
],
'4' => [
"field1" => "Value 3",
"field2" => 8
]
];
$this->assertEquals(3, PMFTotalCalculation($grid1, 'field2', 'median'));
$this->assertEquals(4, PMFTotalCalculation($grid2, 'field2', 'median'));
}
/**
* This tests if the "PMFTotalCalculation" execute correctly the minimum
* @test
*/
public function it_must_return_the_minimum_of_the_method()
{
$grid = [
'1' => [
"field1" => "Value 1",
"field2" => 5
],
'2' => [
"field1" => "Value 2",
"field2" => 2
],
'3' => [
"field1" => "Value 3",
"field2" => 3
]
];
$this->assertEquals(2, PMFTotalCalculation($grid, 'field2', 'minimum'));
}
/**
* This tests if the "PMFTotalCalculation" execute correctly the maximum
* @test
*/
public function it_must_return_the_maximum_of_the_method()
{
$grid = [
'1' => [
"field1" => "Value 1",
"field2" => 2
],
'2' => [
"field1" => "Value 2",
"field2" => 5
],
'3' => [
"field1" => "Value 3",
"field2" => 3
]
];
$this->assertEquals(5, PMFTotalCalculation($grid, 'field2', 'maximum'));
}
/**
* This tests if the "PMFTotalCalculation" execute correctly the standardDeviation
* @test
*/
public function it_must_return_the_standardDeviation_of_the_method()
{
$grid = [
'1' => [
"field1" => "Value 1",
"field2" => 25
],
'2' => [
"field1" => "Value 2",
"field2" => 40
],
'3' => [
"field1" => "Value 3",
"field2" => 10
]
];
$this->assertEquals(12.2474487139, PMFTotalCalculation($grid, 'field2', 'standardDeviation'));
}
/**
* This tests if the "PMFTotalCalculation" execute correctly the variance
* @test
*/
public function it_must_return_the_variance_of_the_method()
{
$grid = [
'1' => [
"field1" => "Value 1",
"field2" => 25
],
'2' => [
"field1" => "Value 2",
"field2" => 40
],
'3' => [
"field1" => "Value 3",
"field2" => 10
]
];
$this->assertEquals(150, PMFTotalCalculation($grid, 'field2', 'variance'));
}
/**
* This tests if the "PMFTotalCalculation" execute correctly the percentile
* @test
*/
public function it_must_return_the_percentile_of_the_method()
{
$grid = [
'1' => [
"field1" => "Value 1",
"field2" => 10
],
'2' => [
"field1" => "Value 2",
"field2" => 35
],
'3' => [
"field1" => "Value 3",
"field2" => 5
]
];
$expectedArray = [
"1" => 20,
"2" => 70,
"3" => 10,
];
$this->assertEquals($expectedArray, PMFTotalCalculation($grid, 'field2', 'percentile'));
}
/**
* This tests if the "PMFTotalCalculation" execute correctly the count
* @test
*/
public function it_must_return_the_count_of_the_method()
{
$grid = [
'1' => [
"field1" => "Value 1",
"field2" => 25
],
'2' => [
"field1" => "Value 2",
"field2" => 40
],
'3' => [
"field1" => "Value 3",
"field2" => 10
]
];
$this->assertEquals(3, PMFTotalCalculation($grid, 'field2', 'count'));
}
/**
* This tests if the "PMFTotalCalculation" execute correctly the count distinct
* @test
*/
public function it_must_return_the_count_distinct_of_the_method()
{
$grid = [
'1' => [
"field1" => "Value 1",
"field2" => 20
],
'2' => [
"field1" => "Value 2",
"field2" => 20
],
'3' => [
"field1" => "Value 3",
"field2" => 10
]
];
$this->assertEquals(2, PMFTotalCalculation($grid, 'field2', 'countDistinct'));
}
}

View File

@@ -12,6 +12,7 @@ use Tests\TestCase;
class ReportTablesTest extends TestCase class ReportTablesTest extends TestCase
{ {
use CreateTestSite; use CreateTestSite;
use DatabaseTransactions; use DatabaseTransactions;
@@ -21,14 +22,12 @@ class ReportTablesTest extends TestCase
public function setUp() public function setUp()
{ {
parent::setUp(); parent::setUp();
$this->markTestIncomplete(""
. "This test has started using the ./processmaker command, this "
. "command requires the file 'paths_installed.php', that is, a "
. "valid installation of processmaker.");
$_SERVER["REQUEST_URI"] = ""; $_SERVER["REQUEST_URI"] = "";
config(['queue.default' => 'sync']);
config(["system.workspace" => "test"]); config(["system.workspace" => "test"]);
$workspace = config("system.workspace"); $workspace = config("system.workspace");
$this->createDBFile($workspace); $this->createDBFile($workspace);
$this->createConstantsOfConnection();
} }
/** /**
@@ -39,6 +38,33 @@ class ReportTablesTest extends TestCase
parent::tearDown(); parent::tearDown();
} }
/**
* Create constants of connection to databases.
*/
private function createConstantsOfConnection()
{
$constants = [
'DB_ADAPTER' => env('mysql'),
'DB_HOST' => env('DB_HOST'),
'DB_NAME' => env('DB_DATABASE'),
'DB_USER' => env('DB_USERNAME'),
'DB_PASS' => env('DB_PASSWORD'),
'DB_RBAC_HOST' => env('DB_HOST'),
'DB_RBAC_NAME' => env('DB_DATABASE'),
'DB_RBAC_USER' => env('DB_USERNAME'),
'DB_RBAC_PASS' => env('DB_PASSWORD'),
'DB_REPORT_HOST' => env('DB_HOST'),
'DB_REPORT_NAME' => env('DB_DATABASE'),
'DB_REPORT_USER' => env('DB_USERNAME'),
'DB_REPORT_PASS' => env('DB_PASSWORD'),
];
foreach ($constants as $key => $value) {
if (!defined($key)) {
define($key, $value);
}
}
}
/** /**
* Check if the "populateTable" function returns an array value if entered all parameters. * Check if the "populateTable" function returns an array value if entered all parameters.
* @test * @test
@@ -565,97 +591,6 @@ class ReportTablesTest extends TestCase
$this->assertEquals($expected, $actual); $this->assertEquals($expected, $actual);
} }
/**
* Get mapping fields supported by report table.
* @return array
*/
private function getMapFields()
{
return [
[
'sFieldName' => 'var_Text1',
'sType' => 'char'
],
[
'sFieldName' => 'var_Textarea1',
'sType' => 'text'
],
[
'sFieldName' => 'var_Dropdown1',
'sType' => 'char'
],
[
'sFieldName' => 'var_Suggest1',
'sType' => 'char'
],
[
'sFieldName' => 'var_DateTime1',
'sType' => 'date'
],
[
'sFieldName' => 'var_String1',
'sType' => 'char'
],
[
'sFieldName' => 'var_Integer1',
'sType' => 'number'
],
[
'sFieldName' => 'var_Boolean1',
'sType' => 'boolean'
],
[
'sFieldName' => 'var_Array1',
'sType' => 'array'
]
];
}
/**
* Create fields data by type supported.
* @param array $types
* @return array
*/
private function createFieldsByType($types = [])
{
$fields = [];
$mapping = [];
$faker = Faker\Factory::create();
$date = $faker->dateTime();
$mapFields = $this->getMapFields();
foreach ($mapFields as $key => $value) {
if (!in_array($value['sType'], $types)) {
continue;
}
switch ($value['sType']) {
case 'number':
$mapping[] = $value;
$fields[$value['sFieldName']] = (string) random_int(0, 100);
break;
case 'char':
$mapping[] = $value;
$fields[$value['sFieldName']] = G::generateUniqueID();
break;
case 'text':
$mapping[] = $value;
$fields[$value['sFieldName']] = G::generateUniqueID();
break;
case 'date':
$mapping[] = $value;
$fields[$value['sFieldName']] = $date->format('Y-m-d H:i:s');
break;
case 'boolean':
$mapping[] = $value;
$fields[$value['sFieldName']] = ['0' => 0];
break;
}
}
return [
'data' => $fields,
'mapping' => $mapping
];
}
/** /**
* Prepare data initial for test, the grid parameter is optional if you want * Prepare data initial for test, the grid parameter is optional if you want
* to create a grid type field. * to create a grid type field.
@@ -665,7 +600,7 @@ class ReportTablesTest extends TestCase
* @param boolean $grid * @param boolean $grid
* @return object * @return object
*/ */
private function prepareData($tableName, $grid = null) private function prepareData($tableName, $grid = null, $structure = [])
{ {
$applicationNumber = Application::max('APP_NUMBER'); $applicationNumber = Application::max('APP_NUMBER');
if (is_null($applicationNumber)) { if (is_null($applicationNumber)) {
@@ -681,7 +616,10 @@ class ReportTablesTest extends TestCase
$taskUid = G::generateUniqueID(); $taskUid = G::generateUniqueID();
$applicationUid = G::generateUniqueID(); $applicationUid = G::generateUniqueID();
$structure = $this->createFieldsByType(['number', 'char', 'text', 'date']); if (empty($structure)) {
$structure = $this->getDataFromFile('structureReportTable.json');
}
$fields = $structure['mapping']; $fields = $structure['mapping'];
$dataFields = $structure['data']; $dataFields = $structure['data'];
$appData = [ $appData = [
@@ -753,4 +691,157 @@ class ReportTablesTest extends TestCase
$result->application = $application; $result->application = $application;
return $result; return $result;
} }
/**
* Check if the "populateTable" method is it filling with missing values into app_data.
* @test
* @covers ReportTables::populateTable
*/
public function it_should_populating_data_with_fields_missing_in_to_app_data()
{
$tableName = 'TestReportTable';
$result = $this->prepareData($tableName);
$connectionShortName = 'wf';
$type = 'NORMAL';
$fields = $result->fields;
$proUid = $result->processUid;
$grid = '';
$app = Application::where('APP_UID', '=', $result->applicationUid)->get()->first();
$appData = unserialize($app->APP_DATA);
unset($appData['var_Textarea1']);
$appData = serialize($appData);
Application::where('APP_UID', '=', $result->applicationUid)->update(['APP_DATA' => $appData]);
$reportTables = new ReportTables();
$reportTables->populateTable($tableName, $connectionShortName, $type, $fields, $proUid, $grid);
$expected = $result->dataFields;
$expected['APP_UID'] = $result->applicationUid;
$expected['APP_NUMBER'] = $result->applicationNumber;
$expected['var_Textarea1'] = '';
$actual = (array) DB::table($tableName)
->select()
->first();
$this->assertEquals($expected, $actual);
}
/**
* Check if the "populateTable" method is it filling with arrays values.
* @test
* @covers ReportTables::populateTable
*/
public function it_should_populating_data_with_arrays_values()
{
$tableName = 'TestReportTable';
$result = $this->prepareData($tableName);
$connectionShortName = 'wf';
$type = 'NORMAL';
$fields = $result->fields;
$proUid = $result->processUid;
$grid = '';
$app = Application::where('APP_UID', '=', $result->applicationUid)->get()->first();
$appData = unserialize($app->APP_DATA);
$appData['var_Textarea1'] = [];
$appData = serialize($appData);
Application::where('APP_UID', '=', $result->applicationUid)->update(['APP_DATA' => $appData]);
$reportTables = new ReportTables();
$reportTables->populateTable($tableName, $connectionShortName, $type, $fields, $proUid, $grid);
$expected = $result->dataFields;
$expected['APP_UID'] = $result->applicationUid;
$expected['APP_NUMBER'] = $result->applicationNumber;
$expected['var_Textarea1'] = '';
$actual = (array) DB::table($tableName)
->select()
->first();
$this->assertEquals($expected, $actual);
}
/**
* Check if the "populateTable" method is it filling with missing values into app_data for grids control.
* parameters and type and grid are correct values.
* @test
* @covers ReportTables::populateTable
*/
public function it_should_populating_data_with_all_parameters_with_type_is_grid_fields_missing_in_to_app_data()
{
$tableName = 'TestReportTable';
$result = $this->prepareData($tableName, true);
$connectionShortName = 'wf';
$type = 'GRID';
$fields = $result->fields;
$proUid = $result->processUid;
$grid = 'var_Grid1';
$app = Application::where('APP_UID', '=', $result->applicationUid)->get()->first();
$appData = unserialize($app->APP_DATA);
unset($appData['var_Grid1'][1]['var_Textarea1']);
$appData = serialize($appData);
Application::where('APP_UID', '=', $result->applicationUid)->update(['APP_DATA' => $appData]);
$reportTables = new ReportTables();
$reportTables->populateTable($tableName, $connectionShortName, $type, $fields, $proUid, $grid);
$indexRow = 1;
$expected = $result->appData[$grid];
foreach ($expected as &$row) {
$row['APP_UID'] = $result->applicationUid;
$row['APP_NUMBER'] = $result->applicationNumber;
$row['ROW'] = (string) ($indexRow++);
}
$expected = array_values($expected);
$expected[0]['var_Textarea1'] = '';
$actual = DB::table($tableName)
->select()
->get();
$actual->transform(function ($item, $key) {
return (array) $item;
});
$actual = $actual->toArray();
$this->assertEquals($expected, $actual);
}
/**
* Check an exception if the input parameters are wrong.
* @test
* @covers ReportTables::populateTable
*/
public function it_should_catch_an_exception()
{
$tableName = 'TestReportTable';
$result = $this->prepareData($tableName, true);
$connectionShortName = 'wf';
$type = 'GRID';
$fields = $result->fields;
$proUid = $result->processUid;
$grid = 'var_Grid1';
//assert exception
$this->expectException(Exception::class);
$reportTables = new ReportTables();
$reportTables->populateTable($tableName, $connectionShortName, $type, null, $proUid, $grid);
}
/**
* This gets data from a json file.
* @param string $pathData
* @return array
*/
private function getDataFromFile(string $pathData): array
{
$pathData = PATH_TRUNK . "tests/resources/{$pathData}";
$data = file_get_contents($pathData);
$result = json_decode($data, JSON_OBJECT_AS_ARRAY);
return $result;
}
} }

View File

@@ -3,17 +3,32 @@
namespace Tests\unit\workflow\engine\classes\model; namespace Tests\unit\workflow\engine\classes\model;
use AdditionalTables; use AdditionalTables;
use App\Jobs\GenerateReportTable;
use Exception; use Exception;
use G; use G;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
use ProcessMaker\BusinessModel\ReportTable; use ProcessMaker\BusinessModel\ReportTable;
use ProcessMaker\Model\AdditionalTables as AdditionalTablesModel; use ProcessMaker\Model\AdditionalTables as AdditionalTablesModel;
use ProcessMaker\Model\Application;
use ProcessMaker\Model\DbSource;
use ProcessMaker\Model\Delegation;
use ProcessMaker\Model\Process;
use ProcessMaker\Model\Task;
use Tests\TestCase; use Tests\TestCase;
class AdditionalTablesTest extends TestCase class AdditionalTablesTest extends TestCase
{ {
/**
* Set up method.
*/
public function setUp()
{
parent::setUp();
}
/** /**
* This tests the creation of a PMTable. * This tests the creation of a PMTable.
* @test * @test
@@ -198,6 +213,74 @@ class AdditionalTablesTest extends TestCase
$this->assertContains($actual[0], $expected, false); $this->assertContains($actual[0], $expected, false);
} }
/**
* Check if populate report table is added to job queue.
* @test
* @covers \AdditionalTables::populateReportTable
*/
public function it_should_test_populate_report_table()
{
$proUid = factory(Process::class)->create()->PRO_UID;
$task = factory(Task::class)->create([
'PRO_UID' => $proUid
]);
//local connections
$dbSource = factory(DbSource::class)->create([
'PRO_UID' => $proUid,
'DBS_SERVER' => env('DB_HOST'),
'DBS_DATABASE_NAME' => env('DB_DATABASE'),
'DBS_USERNAME' => env('DB_USERNAME'),
'DBS_PASSWORD' => G::encrypt(env('DB_PASSWORD'), env('DB_DATABASE')) . "_2NnV3ujj3w",
'DBS_PORT' => '3306',
'DBS_CONNECTION_TYPE' => 'NORMAL'
]);
$additionalTable = factory(AdditionalTablesModel::class)->create([
'PRO_UID' => $proUid,
'DBS_UID' => $dbSource->DBS_UID,
]);
$tableName = $additionalTable->ADD_TAB_NAME;
$name = $additionalTable->ADD_TAB_CLASS_NAME;
$this->createSchema($dbSource->DBS_DATABASE_NAME, $tableName, $name, $dbSource->DBS_UID);
//external connection
$dbSource = factory(DbSource::class)->create([
'PRO_UID' => $proUid,
'DBS_SERVER' => config('database.connections.testexternal.host'),
'DBS_DATABASE_NAME' => config('database.connections.testexternal.database'),
'DBS_USERNAME' => config('database.connections.testexternal.username'),
'DBS_PASSWORD' => G::encrypt(config('database.connections.testexternal.password'), config('database.connections.testexternal.database')) . "_2NnV3ujj3w",
'DBS_PORT' => '3306',
'DBS_CONNECTION_TYPE' => 'NORMAL'
]);
$additionalTable = factory(AdditionalTablesModel::class)->create([
'PRO_UID' => $proUid,
'DBS_UID' => $dbSource->DBS_UID,
]);
$tableNameExternal = $additionalTable->ADD_TAB_NAME;
$nameExternal = $additionalTable->ADD_TAB_CLASS_NAME;
$this->createSchema($dbSource->DBS_DATABASE_NAME, $tableNameExternal, $nameExternal, $dbSource->DBS_UID);
$application = factory(Application::class)->create([
'PRO_UID' => $proUid
]);
factory(Delegation::class)->create([
'DEL_THREAD_STATUS' => 'CLOSED',
'APP_NUMBER' => $application->APP_NUMBER,
'TAS_UID' => $task->TAS_UID,
]);
//assertions
Queue::fake();
Queue::assertNothingPushed();
$additionalTables = new AdditionalTables();
$additionalTables->populateReportTable($tableName, 'workflow', 'NORMAL', $proUid, '', $additionalTable->ADD_TAB_UID);
Queue::assertPushed(GenerateReportTable::class);
}
/** /**
* This gets the content from template file. * This gets the content from template file.
* @param string $pathData * @param string $pathData

View File

@@ -188,4 +188,43 @@ class VariableTest extends TestCase
$this->assertArrayHasKey('var_accepted_values', $res, "The result does not contains 'var_accepted_values' as key"); $this->assertArrayHasKey('var_accepted_values', $res, "The result does not contains 'var_accepted_values' as key");
$this->assertArrayHasKey('inp_doc_uid', $res, "The result does not contains 'inp_doc_uid' as key"); $this->assertArrayHasKey('inp_doc_uid', $res, "The result does not contains 'inp_doc_uid' as key");
} }
/**
* Test it return the variables by type related to the PRO_UID
*
* @covers \ProcessMaker\BusinessModel\Variable::getVariablesByType()
* @test
*/
public function it_list_variables_by_type_related_a_process()
{
$process = factory(Process::class)->create();
$varType = 'integer';
$varTypeId = 2;
for ($x = 1; $x <= 5; $x++) {
$processVar = factory(ProcessVariables::class)->states('foreign_keys')->create([
'PRO_ID' => $process->PRO_ID,
'PRJ_UID' => $process->PRO_UID,
'VAR_FIELD_TYPE' => $varType,
'VAR_FIELD_TYPE_ID' => $varTypeId,
'VAR_NAME' => 'varTestName' . $x,
]);
}
$variable = new Variable();
// Get all results
$res = $variable->getVariablesByType($process->PRO_UID, 2);
$this->assertEquals(5, count($res));
$res = head($res);
$this->assertArrayHasKey('value', $res, "The result does not contains 'value' as key");
// Get a specific start and limit
$res = $variable->getVariablesByType($process->PRO_UID, 2, 0, 2);
$this->assertNotEmpty($res);
$this->assertEquals(2, count($res));
// Get a specific search
$res = $variable->getVariablesByType($process->PRO_UID, 2, 0, 4, 'varTest');
$this->assertNotEmpty($res);
$this->assertEquals(4, count($res));
// When the search does not match
$res = $variable->getVariablesByType($process->PRO_UID, 2, null, null, 'other');
$this->assertEmpty($res);
}
} }

View File

@@ -2,6 +2,7 @@
namespace ProcessMaker\Core; namespace ProcessMaker\Core;
use App\Jobs\Email;
use Tests\TestCase; use Tests\TestCase;
class JobsManagerTest extends TestCase class JobsManagerTest extends TestCase

View File

@@ -70,4 +70,41 @@ class ProcessVariablesTest extends TestCase
$result = ProcessVariables::getVariables($process->PRO_ID); $result = ProcessVariables::getVariables($process->PRO_ID);
$this->assertNotEmpty($result); $this->assertNotEmpty($result);
} }
/**
* Test it return the variables by type related to the PRO_ID
*
* @covers \ProcessMaker\Model\ProcessVariables::getVariablesByType()
* @test
*/
public function it_list_variables_type_by_process()
{
$process = factory(Process::class)->create();
$varType = 'integer';
$varTypeId = 2;
for ($x = 1; $x <= 5; $x++) {
$processVar = factory(ProcessVariables::class)->states('foreign_keys')->create([
'PRO_ID' => $process->PRO_ID,
'PRJ_UID' => $process->PRO_UID,
'VAR_FIELD_TYPE' => $varType,
'VAR_FIELD_TYPE_ID' => $varTypeId,
'VAR_NAME' => 'varTestName' . $x,
]);
}
$res = ProcessVariables::getVariablesByType($processVar->PRO_ID, 2, null, null, null);
$this->assertNotEmpty($res);
$this->assertEquals(5, count($res));
// Get a specific start and limit
$res = ProcessVariables::getVariablesByType($process->PRO_ID, 2, 0, 2);
$this->assertNotEmpty($res);
$this->assertEquals(2, count($res));
// Get a specific search
$res = ProcessVariables::getVariablesByType($process->PRO_ID, 2, 0, 4, 'varTest');
$this->assertNotEmpty($res);
$this->assertEquals(4, count($res));
// When the search does not match
$res = ProcessVariables::getVariablesByType($process->PRO_ID, 2, null, null, 'other');
$this->assertEmpty($res);
}
} }

View File

@@ -1,74 +0,0 @@
<?php
use Illuminate\Support\Facades\DB;
use ProcessMaker\Core\System;
CLI::taskName("generate-data-report");
CLI::taskRun("generateDataReport");
CLI::taskDescription("\nGenerate data report by process in a respective workspace, you must pass through arguments the project identifier and the processing interval.");
CLI::taskArg("workspace", false);
CLI::taskOpt("uid", "Identifier that represents the process, must be 32 characters.", "", "process=");
CLI::taskOpt("start", "The start option skips so many rows before returning results.", "", "start=");
CLI::taskOpt("limit", "The limit option restricts the number of rows returned.", "", "limit=");
/**
* Generate data report by process in a respective workspace, you must pass through
* arguments the project identifier and the processing interval.
* @param array $options
* @return void
*/
function generateDataReport(array $options): void
{
//get workspace
if (empty($options[0])) {
CLI::logging("Workspace undefined!\n");
return;
}
$workspace = $options[0];
//get options
$parameters = [
"tableName=" => "",
"type=" => "",
"process=" => "",
"gridKey=" => "",
"additionalTable=" => "",
"className=" => "",
"pathWorkspace=" => "",
"start=" => "",
"limit=" => ""
];
foreach ($parameters as $key => $value) {
for ($i = 1; $i < count($options); $i++) {
if (strpos($options[$i], $key) !== false) {
$parameters[$key] = str_replace($key, "", $options[$i]);
break;
}
}
}
//validations
$needed = [
"process="
];
foreach ($needed as $value) {
if (empty($parameters[$value])) {
CLI::logging("Missing options {$value}.\n");
return;
}
}
//run method
$workspaceTools = new WorkspaceTools($workspace);
$workspaceTools->generateDataReport(
$parameters["tableName="],
$parameters["type="],
$parameters["process="],
$parameters["gridKey="],
$parameters["additionalTable="],
$parameters["className="],
$parameters["pathWorkspace="],
(int) $parameters["start="],
(int) $parameters["limit="]
);
}

View File

@@ -1,21 +0,0 @@
<?php
CLI::taskName("populate-table");
CLI::taskRun("populateTable");
CLI::taskDescription("\nThis function populates the report table with the APP_DATA data");
CLI::taskArg("workspace", false);
/**
* This function populates the report table with the APP_DATA data.
* @return void
*/
function populateTable($options): void
{
//get options
$workspaceName = $options[0];
$query = base64_decode($options[1]);
$isRbac = (bool) $options[2];
$workspace = new WorkspaceTools($workspaceName);
$workspace->populateTableReport($query, $isRbac);
}

View File

@@ -29,6 +29,7 @@ class PmDynaform
public $lang = SYS_LANG; public $lang = SYS_LANG;
public $translations = null; public $translations = null;
public $onPropertyRead = "onPropertyReadFormInstance"; public $onPropertyRead = "onPropertyReadFormInstance";
public $onAfterPropertyRead = "onAfterPropertyReadFormInstance";
public $pathRTLCss = ''; public $pathRTLCss = '';
public $record = null; public $record = null;
public $records = null; public $records = null;
@@ -545,6 +546,7 @@ class PmDynaform
if (isset($this->fields["APP_DATA"][$json->name . "_label"])) { if (isset($this->fields["APP_DATA"][$json->name . "_label"])) {
$json->data->label = $this->fields["APP_DATA"][$json->name . "_label"]; $json->data->label = $this->fields["APP_DATA"][$json->name . "_label"];
} }
$this->setDependentOptionsForDatetime($json, $this->fields);
} }
if ($key === "type" && ($value === "file") && isset($this->fields["APP_DATA"]["APPLICATION"])) { if ($key === "type" && ($value === "file") && isset($this->fields["APP_DATA"]["APPLICATION"])) {
$oCriteriaAppDocument = new Criteria("workflow"); $oCriteriaAppDocument = new Criteria("workflow");
@@ -771,6 +773,11 @@ class PmDynaform
} }
} }
} }
//read event after
$fn = $this->onAfterPropertyRead;
if (is_callable($fn) || function_exists($fn)) {
$fn($json, $key, $value);
}
} }
} }
} }
@@ -2489,4 +2496,38 @@ class PmDynaform
$json->dataSchema[$key] = $columnsData; $json->dataSchema[$key] = $columnsData;
} }
} }
/**
* Sets the dependentOptions property for datetime control, if it contains dependent fields.
* @param stdClass $json
* @param array $fields
* @return void
*/
private function setDependentOptionsForDatetime(stdClass &$json, array $fields = []): void
{
if (!isset($json->type)) {
return;
}
if ($json->type !== 'datetime') {
return;
}
$json->dependentOptions = '';
$backup = $this->onAfterPropertyRead;
$properties = [
'defaultDate' => $json->defaultDate,
'minDate' => $json->minDate,
'maxDate' => $json->maxDate
];
$this->onAfterPropertyRead = function(stdClass &$json, $key, $value) use($backup, $properties) {
if (isset($json->type) && $json->type === 'datetime' && $key === "dependentOptions") {
$json->dependentOptions = new stdClass();
foreach ($properties as $property => $value) {
if (is_string($value) && in_array(substr($value, 0, 2), self::$prefixs)) {
$json->dependentOptions->{$property} = $value;
}
}
$this->onAfterPropertyRead = $backup;
}
};
}
} }

View File

@@ -1,8 +1,8 @@
<?php <?php
use App\Jobs\GenerateReportTable;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use ProcessMaker\Core\MultiProcOpen; use ProcessMaker\Core\JobsManager;
use ProcessMaker\Commands\PopulateTableReport;
use ProcessMaker\Model\Application; use ProcessMaker\Model\Application;
/** /**
@@ -205,6 +205,9 @@ class ReportTables
*/ */
public function populateTable($tableName, $connectionShortName = 'report', $type = 'NORMAL', $fields = [], $proUid = '', $grid = '') public function populateTable($tableName, $connectionShortName = 'report', $type = 'NORMAL', $fields = [], $proUid = '', $grid = '')
{ {
$config = System::getSystemConfiguration();
$reportTableBatchRegeneration = $config['report_table_batch_regeneration'];
$tableName = $this->sPrefix . $tableName; $tableName = $this->sPrefix . $tableName;
//we have to do the propel connection //we have to do the propel connection
$database = $this->chooseDB($connectionShortName); $database = $this->chooseDB($connectionShortName);
@@ -222,7 +225,7 @@ class ReportTables
$applications = Application::getByProUid($proUid); $applications = Application::getByProUid($proUid);
$i = 1; $i = 1;
$queryValues = ""; $queryValues = "";
$numberRecords = 1000; $numberRecords = $reportTableBatchRegeneration;
$n = count($applications); $n = count($applications);
foreach ($applications as $application) { foreach ($applications as $application) {
$appData = $case->unserializeData($application->APP_DATA); $appData = $case->unserializeData($application->APP_DATA);
@@ -262,11 +265,12 @@ class ReportTables
$queryValues = rtrim($queryValues, ","); $queryValues = rtrim($queryValues, ",");
$query = $headQuery . $queryValues; $query = $headQuery . $queryValues;
$queryValues = ""; $queryValues = "";
$workspace = config("system.workspace");
$processesManager = new MultiProcOpen(); //add to queue
$processesManager->chunk(1, 1, function($size, $start, $limit) use ($query, $workspace) { $closure = function() use($query) {
return new PopulateTableReport($workspace, $query); DB::insert($query);
}); };
JobsManager::getSingleton()->dispatch(GenerateReportTable::class, $closure);
} }
} else { } else {
if (isset($appData[$grid])) { if (isset($appData[$grid])) {
@@ -304,11 +308,12 @@ class ReportTables
$queryValues = rtrim($queryValues, ","); $queryValues = rtrim($queryValues, ",");
$query = $headQuery . $queryValues; $query = $headQuery . $queryValues;
$queryValues = ""; $queryValues = "";
$workspace = config("system.workspace");
$processesManager = new MultiProcOpen(); //add to queue
$processesManager->chunk(1, 1, function($size, $start, $limit) use ($query, $workspace) { $closure = function() use($query) {
return new PopulateTableReport($workspace, $query); DB::insert($query);
}); };
JobsManager::getSingleton()->dispatch(GenerateReportTable::class, $closure);
} }
} }
} }

View File

@@ -249,15 +249,16 @@ function executeQuery ($SqlStatement, $DBConnectionUID = 'workflow', $aParameter
if (is_null(config('database.connections.' . $DBConnectionUID . '.driver'))) { if (is_null(config('database.connections.' . $DBConnectionUID . '.driver'))) {
// Force to load the external connections // Force to load the external connections
DbConnections::loadAdditionalConnections(); DbConnections::loadAdditionalConnections();
if (config('database.connections.' . $DBConnectionUID . '.driver') !== 'oracle') { }
// If the connections drivers are "mysql", "pgsql" or "sqlsrv" we're using Laravel
$con = DB::connection($DBConnectionUID); if (config('database.connections.' . $DBConnectionUID . '.driver') !== 'oracle') {
$con->beginTransaction(); // If the connections drivers are "mysql", "pgsql" or "sqlsrv" we're using Laravel
} else { $con = DB::connection($DBConnectionUID);
// If the connection driver is "oracle" we're using the native oci8 functions $con->beginTransaction();
$con = Propel::getConnection($DBConnectionUID); } else {
$con->begin(); // If the connection driver is "oracle" we are using the native oci8 functions
} $con = Propel::getConnection($DBConnectionUID);
$con->begin();
} }
$blackList = System::getQueryBlackList(); $blackList = System::getQueryBlackList();
@@ -459,6 +460,123 @@ function evaluateFunction($aGrid, $sExpresion)
return $aGrid; return $aGrid;
} }
/**
*
* @method
*
* Executes operations in the grid fields, such as sum, average, median, minimum, maximun,
* stantard deviation, variance, percentile, count, count distinct
*
* @name PMFTotalCalculation
* @label PMFTotalCalculation Function
* @link http://wiki.processmaker.com/index.php/ProcessMaker_Functions#PMFTotalCalculation.28.29
* @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
*
*/
function PMFTotalCalculation($grid, $field, $function)
{
$systemConfiguration = Bootstrap::getSystemConfiguration();
$floatPointNumber = $systemConfiguration['pmftotalcalculation_floating_point_number'];
$function = strtolower($function);
$totalRows = count($grid);
$result = 0;
$sum = 0;
switch ($function) {
case "sum":
for ($i = 1; $i <= $totalRows; $i += 1) {
$result += $grid[$i][$field];
}
break;
case "average":
for ($i = 1; $i <= $totalRows; $i += 1) {
$result += $grid[$i][$field];
}
$result = $result / $totalRows;
break;
case "median":
$arrayAux = [];
for ($i = 1; $i <= $totalRows; $i += 1) {
$arrayAux[] = $grid[$i][$field];
}
sort($arrayAux);
$term = ($totalRows + 1) / 2;
if ($totalRows % 2 === 0) {
$term = floor($term);
$result = ($arrayAux[$term - 1] + $arrayAux[$term]) / 2;
} else {
$result = $arrayAux[$term - 1];
}
break;
case "minimum":
$result = $grid[1][$field];
for ($i = 2; $i <= $totalRows; $i += 1) {
if ($grid[$i][$field] < $result) {
$result = $grid[$i][$field];
}
}
break;
case "maximum":
$result = $grid[1][$field];
for ($i = 2; $i <= $totalRows; $i += 1) {
if ($grid[$i][$field] > $result) {
$result = $grid[$i][$field];
}
}
break;
case "standarddeviation":
$mean = 0;
for ($i = 1; $i <= $totalRows; $i += 1) {
$mean += $grid[$i][$field];
}
$mean = $mean / $totalRows;
for ($i = 1; $i <= $totalRows; $i += 1) {
$result += pow($grid[$i][$field] - $mean, 2);
}
$result = sqrt($result / $totalRows);
break;
case "variance":
$mean = 0;
for ($i = 1; $i <= $totalRows; $i += 1) {
$mean += $grid[$i][$field];
}
$mean = $mean / $totalRows;
for ($i = 1; $i <= $totalRows; $i += 1) {
$result += pow($grid[$i][$field] - $mean, 2);
}
$result = $result / $totalRows;
break;
case "percentile":
$result = [];
$arrayAux = [];
for ($i = 1; $i <= $totalRows; $i += 1) {
$sum += $grid[$i][$field];
$arrayAux[$i] = $grid[$i][$field];
}
for ($i = 1; $i <= count($arrayAux); $i += 1) {
$result[$i] = round(($arrayAux[$i] * 100) / $sum, $floatPointNumber);
}
break;
case "count":
$result = $totalRows;
break;
case "countdistinct":
$arrayAux = [];
for ($i = 1; $i <= $totalRows; $i += 1) {
$arrayAux[] = $grid[$i][$field];
}
$result = count(array_count_values($arrayAux));
break;
}
if ($function !== "percentile") {
return round($result, $floatPointNumber);
}
return $result;
}
/** /**
* Web Services Functions * * Web Services Functions *
*/ */

View File

@@ -1,8 +1,9 @@
<?php <?php
use App\Jobs\GenerateReportTable;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use ProcessMaker\Commands\GenerateDataReport; use ProcessMaker\Core\JobsManager;
use ProcessMaker\Core\MultiProcOpen; use ProcessMaker\Core\System;
use ProcessMaker\Model\Application; use ProcessMaker\Model\Application;
use ProcessMaker\Model\Fields; use ProcessMaker\Model\Fields;
@@ -735,28 +736,23 @@ class AdditionalTables extends BaseAdditionalTables
$workspace = config("system.workspace"); $workspace = config("system.workspace");
$pathWorkspace = PATH_WORKSPACE; $pathWorkspace = PATH_WORKSPACE;
$n = Application::count(); $n = Application::count();
$processesManager = new MultiProcOpen();
$processesManager->chunk($n, 1000, function($size, $start, $limit) use( //batch process
$workspace, $config = System::getSystemConfiguration();
$tableName, $reportTableBatchRegeneration = $config['report_table_batch_regeneration'];
$type,
$processUid, $size = $n;
$gridKey, $start = 0;
$addTabUid, $limit = $reportTableBatchRegeneration;
$className,
$pathWorkspace) { for ($i = 1; $start < $size; $i++) {
return new GenerateDataReport( $closure = function() use($workspace, $tableName, $type, $processUid, $gridKey, $addTabUid, $className, $pathWorkspace, $start, $limit) {
$workspace, $workspaceTools = new WorkspaceTools($workspace);
$tableName, $workspaceTools->generateDataReport($tableName, $type, $processUid, $gridKey, $addTabUid, $className, $pathWorkspace, $start, $limit);
$type, };
$processUid, JobsManager::getSingleton()->dispatch(GenerateReportTable::class, $closure);
$gridKey, $start = $i * $limit;
$addTabUid, }
$className,
$pathWorkspace,
$start,
$limit);
});
} }
/** /**

View File

@@ -77,7 +77,7 @@ class AppMessageMapBuilder
$tMap->addColumn('APP_MSG_TYPE_ID', 'AppMsgTypeId', 'int', CreoleTypes::TINYINT, false, null); $tMap->addColumn('APP_MSG_TYPE_ID', 'AppMsgTypeId', 'int', CreoleTypes::TINYINT, false, null);
$tMap->addColumn('APP_MSG_SUBJECT', 'AppMsgSubject', 'string', CreoleTypes::VARCHAR, true, 150); $tMap->addColumn('APP_MSG_SUBJECT', 'AppMsgSubject', 'string', CreoleTypes::VARCHAR, true, 998);
$tMap->addColumn('APP_MSG_FROM', 'AppMsgFrom', 'string', CreoleTypes::VARCHAR, true, 100); $tMap->addColumn('APP_MSG_FROM', 'AppMsgFrom', 'string', CreoleTypes::VARCHAR, true, 100);

View File

@@ -579,9 +579,6 @@ abstract class BaseEmailServerPeer
} }
} else { } else {
if ($obj->isNew() || $obj->isColumnModified(EmailServerPeer::MESS_ENGINE))
$columns[EmailServerPeer::MESS_ENGINE] = $obj->getMessEngine();
} }
return BasePeer::doValidate(EmailServerPeer::DATABASE_NAME, EmailServerPeer::TABLE_NAME, $columns); return BasePeer::doValidate(EmailServerPeer::DATABASE_NAME, EmailServerPeer::TABLE_NAME, $columns);

View File

@@ -1,27 +1,4 @@
<?php <?php
/**
* databases.php
*
* ProcessMaker Open Source Edition
* Copyright (C) 2004 - 2008 Colosa Inc.23
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* For more information, contact Colosa Inc, 2566 Le Jeune Rd.,
* Coral Gables, FL, 33134, USA, or email info@colosa.com.
*
*/
if (defined('PATH_DB') && !empty(config("system.workspace"))) { if (defined('PATH_DB') && !empty(config("system.workspace"))) {
@@ -29,7 +6,32 @@ if (defined('PATH_DB') && !empty(config("system.workspace"))) {
throw new Exception("Could not find db.php in current workspace " . config("system.workspace")); throw new Exception("Could not find db.php in current workspace " . config("system.workspace"));
} }
require_once(PATH_DB . config("system.workspace") . '/db.php'); //These constants must not exist, they will be created by "db.php".
$constants = [
'DB_ADAPTER',
'DB_HOST',
'DB_NAME',
'DB_USER',
'DB_PASS',
'DB_RBAC_HOST',
'DB_RBAC_NAME',
'DB_RBAC_USER',
'DB_RBAC_PASS' ,
'DB_REPORT_HOST',
'DB_REPORT_NAME',
'DB_REPORT_USER',
'DB_REPORT_PASS',
];
$load = true;
foreach ($constants as $value) {
if (defined($value)) {
$load = false;
break;
}
}
if ($load === true) {
require_once(PATH_DB . config("system.workspace") . '/db.php');
}
//to do: enable for other databases //to do: enable for other databases
$dbType = DB_ADAPTER; $dbType = DB_ADAPTER;
$dsn = DB_ADAPTER . '://' . DB_USER . ':' . urlencode(DB_PASS) . '@' . DB_HOST . '/' . DB_NAME; $dsn = DB_ADAPTER . '://' . DB_USER . ':' . urlencode(DB_PASS) . '@' . DB_HOST . '/' . DB_NAME;
@@ -42,15 +44,12 @@ if (defined('PATH_DB') && !empty(config("system.workspace"))) {
switch (DB_ADAPTER) { switch (DB_ADAPTER) {
case 'mysql': case 'mysql':
$dsn .= '?encoding=utf8'; $dsn .= '?encoding=utf8';
$dsnRbac .= '?encoding=utf8'; $dsnRbac .= '?encoding=utf8';
$dsnReport .= '?encoding=utf8'; $dsnReport .= '?encoding=utf8';
break; break;
case 'mssql': case 'mssql':
case 'sqlsrv': case 'sqlsrv':
//$dsn .= '?sendStringAsUnicode=false';
//$dsnRbac .= '?sendStringAsUnicode=false';
//$dsnReport .= '?sendStringAsUnicode=false';
break; break;
default: default:
break; break;
@@ -64,7 +63,7 @@ if (defined('PATH_DB') && !empty(config("system.workspace"))) {
$pro ['datasources']['rp']['connection'] = $dsnReport; $pro ['datasources']['rp']['connection'] = $dsnReport;
$pro ['datasources']['rp']['adapter'] = DB_ADAPTER; $pro ['datasources']['rp']['adapter'] = DB_ADAPTER;
$dbHost = explode(':', DB_HOST); $dbHost = explode(':', DB_HOST);
config(['database.connections.workflow.host' => $dbHost[0]]); config(['database.connections.workflow.host' => $dbHost[0]]);
config(['database.connections.workflow.database' => DB_NAME]); config(['database.connections.workflow.database' => DB_NAME]);
@@ -76,6 +75,6 @@ if (defined('PATH_DB') && !empty(config("system.workspace"))) {
} }
$pro ['datasources']['dbarray']['connection'] = 'dbarray://user:pass@localhost/pm_os'; $pro ['datasources']['dbarray']['connection'] = 'dbarray://user:pass@localhost/pm_os';
$pro ['datasources']['dbarray']['adapter'] = 'dbarray'; $pro ['datasources']['dbarray']['adapter'] = 'dbarray';
return $pro; return $pro;

View File

@@ -25325,6 +25325,12 @@ msgstr "The PHP files execution was disabled please contact the system administr
msgid "Please complete the reassign reason." msgid "Please complete the reassign reason."
msgstr "Please complete the reassign reason." msgstr "Please complete the reassign reason."
# TRANSLATION
# LABEL/ID_THE_REPORT_TABLE_IS_REGENERATING_PLEASE_COME_BACK_IN_A_FEW_MINUTES
#: LABEL/ID_THE_REPORT_TABLE_IS_REGENERATING_PLEASE_COME_BACK_IN_A_FEW_MINUTES
msgid "The report table is regenerating please come back in a few minutes."
msgstr "The report table is regenerating please come back in a few minutes."
# TRANSLATION # TRANSLATION
# LABEL/ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED # LABEL/ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED
#: LABEL/ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED #: LABEL/ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED

View File

@@ -1215,7 +1215,7 @@ class pmTablesProxy extends HttpProxyController
if (!empty($table) && $table['PRO_UID'] != '') { if (!empty($table) && $table['PRO_UID'] != '') {
try { try {
$additionalTables->populateReportTable($table['ADD_TAB_NAME'], PmTable::resolveDbSource($table['DBS_UID']), $table['ADD_TAB_TYPE'], $table['PRO_UID'], $table['ADD_TAB_GRID'], $table['ADD_TAB_UID']); $additionalTables->populateReportTable($table['ADD_TAB_NAME'], PmTable::resolveDbSource($table['DBS_UID']), $table['ADD_TAB_TYPE'], $table['PRO_UID'], $table['ADD_TAB_GRID'], $table['ADD_TAB_UID']);
$result->message = 'Generated for table ' . $table['ADD_TAB_NAME']; $result->message = G::LoadTranslation("ID_THE_REPORT_TABLE_IS_REGENERATING_PLEASE_COME_BACK_IN_A_FEW_MINUTES");
} catch (Exception $e) { } catch (Exception $e) {
$context = Bootstrap::getDefaultContextLog(); $context = Bootstrap::getDefaultContextLog();
$context['proUid'] = $table['PRO_UID']; $context['proUid'] = $table['PRO_UID'];

View File

@@ -61112,6 +61112,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE
( 'LABEL','ID_THE_NAME_CHANGE_MAY_CAUSE_DATA_LOSS','en','The change might cause data loss in the PM table. Do you want to continue?','2017-03-30') , ( 'LABEL','ID_THE_NAME_CHANGE_MAY_CAUSE_DATA_LOSS','en','The change might cause data loss in the PM table. Do you want to continue?','2017-03-30') ,
( 'LABEL','ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED','en','The PHP files execution was disabled please contact the system administrator.','2018-04-20') , ( 'LABEL','ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED','en','The PHP files execution was disabled please contact the system administrator.','2018-04-20') ,
( 'LABEL','ID_THE_REASON_REASSIGN_USER_EMPTY','en','Please complete the reassign reason.','2016-10-20') , ( 'LABEL','ID_THE_REASON_REASSIGN_USER_EMPTY','en','Please complete the reassign reason.','2016-10-20') ,
( 'LABEL','ID_THE_REPORT_TABLE_IS_REGENERATING_PLEASE_COME_BACK_IN_A_FEW_MINUTES','en','The report table is regenerating please come back in a few minutes.','2020-06-01') ,
( 'LABEL','ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED','en','The upload of PHP files was disabled please contact the system administrator.','2018-04-20') , ( 'LABEL','ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED','en','The upload of PHP files was disabled please contact the system administrator.','2018-04-20') ,
( 'LABEL','ID_THE_USERNAME_EMAIL_IS_INCORRECT','en','The username or email is incorrect','2018-01-18') , ( 'LABEL','ID_THE_USERNAME_EMAIL_IS_INCORRECT','en','The username or email is incorrect','2018-01-18') ,
( 'LABEL','ID_THIS_MONTH','en','This Month','2014-01-15') , ( 'LABEL','ID_THIS_MONTH','en','This Month','2014-01-15') ,

View File

@@ -1178,7 +1178,9 @@ class DynaForm
} }
foreach ($oldColumns as $oldColumn) { foreach ($oldColumns as $oldColumn) {
if (strtolower(AdditionalTables::getPHPName($column->id)) === strtolower(AdditionalTables::getPHPName($oldColumn->id))) { if (strtolower(AdditionalTables::getPHPName($column->id)) === strtolower(AdditionalTables::getPHPName($oldColumn->id))) {
$identicals[] = "'" . $column->id . "' - '" . $oldColumn->id . "'"; if (strtolower(AdditionalTables::getPHPName($column->var_name)) === strtolower(AdditionalTables::getPHPName($oldColumn->var_name))) {
$identicals[] = "'" . $column->id . "' - '" . $oldColumn->id . "'";
}
} }
} }
} }

View File

@@ -26,6 +26,16 @@ class Variable
'object' => 10 'object' => 10
]; ];
/**
* Get the variables types accepted
*
* @return array
*/
public function getVariableTypes()
{
return $this->variableTypes;
}
/** /**
* Create Variable for a Process * Create Variable for a Process
* *
@@ -355,6 +365,33 @@ class Variable
return $arrayVariables; return $arrayVariables;
} }
/**
* Get data of Variables related to the specific type
*
* @param string $processUid Unique id of Process
* @param int $typeVarId
* @param int $start
* @param int $limit
* @param string $search
* @param string $prefix
*
* @return array, return an array with varaibles filter by type
*/
public function getVariablesByType($processUid, $typeVarId = 0, $start = null, $limit = null, $search = null, $prefix = null)
{
//Verify data
$proId = Validator::proUid($processUid, '$prj_uid');
$variables = ProcessVariables::getVariablesByType($proId, $typeVarId, $start, $limit, $search);
$arrayVariables = [];
foreach ($variables as $var) {
$arrayVariables[] = [
'value' => is_null($prefix) ? $var['VAR_NAME'] : $prefix . $var['VAR_NAME'],
];
}
return $arrayVariables;
}
/** /**
* Verify field definition * Verify field definition
* *

View File

@@ -1,80 +0,0 @@
<?php
namespace ProcessMaker\Commands;
use ProcessMaker\Core\ProcOpen;
class GenerateDataReport extends ProcOpen
{
private $workspace;
private $tableName;
private $type;
private $processUid;
private $gridKey;
private $addTabUid;
private $className;
private $pathWorkspace;
private $start;
private $limit;
/**
* Initializes the command parameters.
* @param string $workspace
* @param string $tableName
* @param string $type
* @param string $processUid
* @param string $gridKey
* @param string $addTabUid
* @param string $className
* @param string $pathWorkspace
* @param integer $start
* @param integer $limit
*/
public function __construct(
$workspace,
$tableName,
$type = 'NORMAL',
$processUid = '',
$gridKey = '',
$addTabUid = '',
$className = '',
$pathWorkspace,
$start = 0,
$limit = 10)
{
$this->workspace = $workspace;
$this->tableName = $tableName;
$this->type = $type;
$this->processUid = $processUid;
$this->gridKey = $gridKey;
$this->addTabUid = $addTabUid;
$this->className = $className;
$this->pathWorkspace = $pathWorkspace;
$this->start = $start;
$this->limit = $limit;
$this->setCwd(PATH_TRUNK);
parent::__construct($this->buildCommand());
}
/**
* Returns the command to execute.
* @return string
*/
private function buildCommand(): string
{
$command = PHP_BINDIR . "/php "
. "./processmaker "
. "'generate-data-report' "
. "'{$this->workspace}' "
. "'tableName={$this->tableName}' "
. "'type={$this->type}' "
. "'process={$this->processUid}' "
. "'gridKey={$this->gridKey}' "
. "'additionalTable={$this->addTabUid}' "
. "'className={$this->className}' "
. "'pathWorkspace={$this->pathWorkspace}' "
. "'start={$this->start}' "
. "'limit={$this->limit}' ";
return $command;
}
}

View File

@@ -1,42 +0,0 @@
<?php
namespace ProcessMaker\Commands;
use ProcessMaker\Core\ProcOpen;
class PopulateTableReport extends ProcOpen
{
private $workspace;
private $sql;
private $isRbac;
/**
* Initializes the command parameters.
* @param string $workspace
* @param string $sql
* @param boolean $isRbac
*/
public function __construct($workspace, $sql, $isRbac = false)
{
$this->workspace = $workspace;
$this->sql = $sql;
$this->isRbac = $isRbac;
$this->setCwd(PATH_TRUNK);
parent::__construct($this->buildCommand());
}
/**
* Returns the command to execute.
* @return string
*/
public function buildCommand()
{
$command = PHP_BINDIR . "/php "
. "./processmaker "
. "'populate-table' "
. "'{$this->workspace}' "
. base64_encode($this->sql) . " "
. ($this->isRbac ? "'1'" : "'0'");
return $command;
}
}

View File

@@ -1,92 +0,0 @@
<?php
namespace ProcessMaker\Core;
class MultiProcOpen
{
/**
* Represents the waiting time before starting the process monitoring.
* @var integer
*/
private $sleepTime = 1;
/**
* This method obtains a paging by returning the start and limit indexes
* compatible with the mysql pagination in its call function.
* The return function must return an instance of the object "ProcessMaker\Core\ProcOpen".
* Returns an array containing the status, content, and errors generated by
* the open process.
* @param int $size
* @param int $chunk
* @param callable $callback
* @return array
*/
public function chunk(int $size, int $chunk, callable $callback): array
{
$start = 0;
$limit = $chunk;
$queries = [];
for ($i = 1; $start < $size; $i++) {
$queries[] = $callback($size, $start, $limit);
$start = $i * $limit;
}
return $this->run($queries);
}
/**
* Open a set of background processes.
* The array must contain one or more instances of the object inherited from
* the class "ProcessMaker\Core\ProcOpen"
* Returns an array containing the status, content, and errors generated by
* the open process.
* @param array $processes
* @return array
*/
public function run(array $processes): array
{
foreach ($processes as $procOpen) {
$procOpen->open();
}
return $this->processMonitoring($processes);
}
/**
* It monitors the open processes, verifying if they have ended or thrown an
* error and later closing the resources related to the process.
* Returns an array containing the status, content, and errors generated by
* the open process.
* @param array $processes
* @return array
*/
private function processMonitoring(array $processes): array
{
sleep($this->sleepTime); //this sleep is very important
$i = 0;
$n = count($processes);
if ($n === 0) {
return [];
}
$outputs = [];
do {
$index = $i % $n;
if (isset($processes[$index])) {
$procOpen = $processes[$index];
$status = $procOpen->getStatus();
$contents = $procOpen->getContents();
$errors = $procOpen->getErrors();
if ($status->running === false || !empty($errors)) {
$outputs[] = [
"status" => $status,
"contents" => $contents,
"errors" => $errors,
];
$procOpen->terminate();
$procOpen->close();
unset($processes[$index]);
}
}
$i = $i + 1;
} while (!empty($processes));
return $outputs;
}
}

View File

@@ -1,126 +0,0 @@
<?php
namespace ProcessMaker\Core;
class ProcOpen
{
private $command;
private $resource;
private $descriptorspec;
private $pipes;
private $cwd;
/**
* This initializes the descriptors and the command for the open process.
* @param string $command
*/
public function __construct(string $command)
{
$this->descriptorspec = [
['pipe', 'r'],
['pipe', 'w'],
['pipe', 'w']
];
$this->command = $command;
}
/**
* Gets the resource that represents the process.
* @return resource
*/
public function getResource()
{
return $this->resource;
}
/**
* Sets the process execution directory.
* @param string $cwd
*/
public function setCwd(string $cwd)
{
$this->cwd = $cwd;
}
/**
* Open a background process.
*/
public function open()
{
if (empty($this->cwd)) {
$this->resource = proc_open($this->command, $this->descriptorspec, $this->pipes);
} else {
$this->resource = proc_open($this->command, $this->descriptorspec, $this->pipes, $this->cwd);
}
}
/**
* Get the content of the process when it is finished.
* @return string
*/
public function getContents()
{
if (is_resource($this->pipes[1])) {
return stream_get_contents($this->pipes[1]);
}
return "";
}
/**
* Get the process errors when it is finished.
* @return string
*/
public function getErrors()
{
if (is_resource($this->pipes[2])) {
return stream_get_contents($this->pipes[2]);
}
return "";
}
/**
* Close the resources related to the open process.
* return void
*/
public function close()
{
if (is_resource($this->resource)) {
foreach ($this->pipes as $value) {
fclose($value);
}
proc_close($this->resource);
}
}
/**
* End the process before it ends.
*/
public function terminate()
{
if (is_resource($this->resource)) {
proc_terminate($this->resource);
}
}
/**
* Gets the status of the process.
* @return object
*/
public function getStatus()
{
$status = [
"command" => $this->command,
"pid" => null,
"running" => false,
"signaled" => false,
"stopped" => false,
"exitcode" => -1,
"termsig" => 0,
"stopsig" => 0
];
if (is_resource($this->resource)) {
$status = proc_get_status($this->resource);
}
return (object) $status;
}
}

View File

@@ -77,7 +77,9 @@ class System
'highlight_home_folder_enable' => 0, 'highlight_home_folder_enable' => 0,
'highlight_home_folder_refresh_time' => 10, 'highlight_home_folder_refresh_time' => 10,
'highlight_home_folder_scope' => 'unassigned', // For now only this list is supported 'highlight_home_folder_scope' => 'unassigned', // For now only this list is supported
'disable_advanced_search_case_title_fulltext' => 0 'disable_advanced_search_case_title_fulltext' => 0,
'pmftotalcalculation_floating_point_number' => 10,
'report_table_batch_regeneration' => 1000
]; ];
/** /**

View File

@@ -72,8 +72,21 @@ class ProcessVariables extends Model
*/ */
public function scopeProcessId($query, int $proId) public function scopeProcessId($query, int $proId)
{ {
return $query->where('PRO_ID', $proId); return $query->where('PROCESS_VARIABLES.PRO_ID', $proId);
} }
/**
* Scope a query to filter a specific type for variable
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param int $typeId
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeTypeId($query, int $typeId)
{
return $query->where('VAR_FIELD_TYPE_ID', $typeId);
}
/** /**
* Return the variables list * Return the variables list
* *
@@ -96,4 +109,46 @@ class ProcessVariables extends Model
return $variablesList; return $variablesList;
} }
/**
* Return the variables list
*
* @param int $proId
* @param int $typeId
* @param int $start
* @param int $limit
* @param string $search
*
* @return array
*/
public static function getVariablesByType(int $proId, int $typeId = 0, $start = null, $limit = null, $search = null)
{
$query = ProcessVariables::query()->select();
$query->leftJoin('DB_SOURCE', function ($join) {
$join->on('DB_SOURCE.PRO_ID', '=', 'PROCESS_VARIABLES.PRO_ID');
});
$query->processId($proId);
// Check if we need to filter the type of variables
if ($typeId > 0) {
$query->typeId($typeId);
}
// search a specific variable name
if (!empty($search)) {
$query->where('VAR_NAME', 'LIKE', "${search}%");
}
// order by varNane
$query->orderBy('VAR_NAME', 'ASC');
// Check if we need to add a pagination
if(!is_null($start) && !is_null($limit)) {
$query->offset($start)->limit($limit);
}
// Get records
$results = $query->get();
$variablesList = [];
$results->each(function ($item, $key) use (&$variablesList) {
$variablesList[] = $item->toArray();
});
return $variablesList;
}
} }

View File

@@ -1,8 +1,12 @@
<?php <?php
namespace ProcessMaker\Services\Api\Project; namespace ProcessMaker\Services\Api\Project;
use \ProcessMaker\Services\Api; use Exception;
use \Luracast\Restler\RestException; use G;
use Luracast\Restler\RestException;
use ProcessMaker\BusinessModel\Variable as BmVariable;
use ProcessMaker\Services\Api;
/** /**
* Project\Variable Api Controller * Project\Variable Api Controller
* *
@@ -28,6 +32,43 @@ class Variable extends Api
} }
} }
/**
* Get variables by type
*
* @url GET /:prj_uid/process-variables/:typeVariable/paged
*
* @param string $prj_uid {@min 32}{@max 32}
* @param string $typeVariable {@from path}
* @param int $start {@from path}
* @param int $limit {@from path}
* @param string $search {@from path}
*/
public function doGetVariablesByType($prj_uid, $typeVariable, $start = null, $limit = null, $search = null)
{
try {
$variable = new BmVariable();
$typesAccepted = $variable::$varTypesValues;
if (!empty($typesAccepted[$typeVariable])) {
$typeVatId = $typesAccepted[$typeVariable];
} else {
throw new Exception(G::LoadTranslation("ID_INVALID_VALUE_ONLY_ACCEPTS_VALUES", ['$typeVariable', implode(',', $variable->getVariableTypes())]));
}
// Review if the word has the prefix
$count = preg_match_all('/\@(?:([\@\%\#\?\$\=\&Qq\!])|([a-zA-Z\_][\w\-\>\:]*)\(((?:[^\\\\\)]*(?:[\\\\][\w\W])?)*)\))((?:\s*\[[\'"]?\w+[\'"]?\])+|\-\>([a-zA-Z\_]\w*))?/', $search, $match, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE);
// Check if the search has some prefix
$prefix = '';
if ($count) {
$prefix = substr($search,0,2);
$search = substr($search,2);
}
$response = $variable->getVariablesByType($prj_uid, $typeVatId, $start, $limit, $search, $prefix);
return $response;
} catch (Exception $e) {
throw (new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage()));
}
}
/** /**
* @url GET /:prj_uid/process-variable/:var_uid * @url GET /:prj_uid/process-variable/:var_uid
* *